xmpp实现的即时通讯聊天(二)
参考网址:http://www.jianshu.com/p/8894a5a71b70
借图描述原理:
三、注册、登陆、聊天功能的实现
故事板如下:
四个类如下:
不喜多言,直接上Demo:
LoginViewController.h
#import "ViewController.h" #import "XMPPManager.h" #import "RosterViewController.h" @interface LoginViewController : ViewController<XMPPStreamDelegate> @end
LoginViewController.m
#import "LoginViewController.h" @interface LoginViewController () @property (weak, nonatomic) IBOutlet UITextField *usernameTextField; @property (weak, nonatomic) IBOutlet UITextField *passwordTextField; @end @implementation LoginViewController - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view. [[XMPPManager defaultManager].xmppStream addDelegate:self delegateQueue:dispatch_get_main_queue()]; } - (IBAction)login:(UIButton *)sender { NSLog(@"Click login button"); if (self.usernameTextField.text.length>0&&self.passwordTextField.text.length>0) { [[XMPPManager defaultManager] loginwithName:self.usernameTextField.text andPassword:self.passwordTextField.text]; } } -(void)xmppStreamDidAuthenticate:(XMPPStream *)sender{ NSLog(@"登陆成功"); RosterViewController *roster=[RosterViewController new]; [self.navigationController pushViewController:roster animated:YES]; } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated. }
RegisterViewController.h
#import "ViewController.h" #import "XMPPManager.h" @interface RegisterViewController : ViewController<XMPPStreamDelegate> @end
RegisterViewController.m
#import "RegisterViewController.h" @interface RegisterViewController () @property (weak, nonatomic) IBOutlet UITextField *usernameTextfield; @property (weak, nonatomic) IBOutlet UITextField *passwordTextfield; @end @implementation RegisterViewController - (IBAction)register:(UIButton *)sender { [[XMPPManager defaultManager] registerWithName:self.usernameTextfield.text andPassword:self.passwordTextfield.text]; } - (IBAction)cancel:(UIButton *)sender { [self.navigationController popViewControllerAnimated:YES]; } -(void)xmppStreamDidAuthenticate:(XMPPStream *)sender{ NSLog(@"注册成功!!"); } - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view. [[XMPPManager defaultManager].xmppStream addDelegate:self delegateQueue:dispatch_get_main_queue()]; } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated. }
RosterViewController.h
#import <UIKit/UIKit.h> #import <Foundation/Foundation.h> #import "ViewController.h" #import "XMPPManager.h" #import "ChatViewController.h" @interface RosterViewController : ViewController<UITableViewDataSource,UITableViewDelegate,XMPPRosterDelegate> //存放所有好友的数组 @property(nonatomic,strong) NSMutableArray *rosterJids; @property(nonatomic,strong) UITableView *friendsView; @end
RosterViewController.m
#import "RosterViewController.h" @interface RosterViewController () @end @implementation RosterViewController -(UITableView*)friendsView{ if (_friendsView==nil) { _friendsView=[[UITableView alloc]initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height) style:UITableViewStylePlain]; _friendsView.dataSource=self; _friendsView.delegate=self; } return _friendsView; } #pragma mark friendView 代理方法 - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{ return 1; } - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{ if (self.rosterJids.count>0) { return self.rosterJids.count; } return 0; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{ static NSString *ide=@"cell"; UITableViewCell *cell=[tableView dequeueReusableCellWithIdentifier:ide]; if (cell==nil) { cell=[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:ide]; } XMPPJID *jid = self.rosterJids[indexPath.row]; cell.textLabel.text=jid.user; return cell; } #pragma mark 删除好友执行的方法 -(void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath{ if (editingStyle==UITableViewCellEditingStyleDelete) { //找到要删除的人 XMPPJID *jid = self.rosterJids[indexPath.row]; //从数组中删除 [self.rosterJids removeObjectAtIndex:indexPath.row]; //从Ui单元格删除 [tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic ]; //从服务器删除 [[XMPPManager defaultManager].xmppRoster removeUser:jid]; } } -(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{ ChatViewController *chatVC=[ChatViewController new]; chatVC.chatToJid=self.rosterJids[indexPath.row]; [self.navigationController pushViewController:chatVC animated:YES]; } - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view from its nib. self.rosterJids = [[NSMutableArray alloc]init]; [[XMPPManager defaultManager].xmppRoster addDelegate:self delegateQueue:dispatch_get_main_queue()]; // UIBarButtonItem *right=[[UIBarButtonItem alloc]initWithTitle:@"添加" style:UIBarButtonItemStylePlain target:self action:@selector(doAdd:)]; self.navigationItem.rightBarButtonItem = right; [self.view addSubview:self.friendsView]; } //点击添加好友 -(void)doAdd:(UIButton*)sender{ XMPPJID *jid= [XMPPJID jidWithUser:@"admin" domain:@"" resource:nil]; //添加好友 [[XMPPManager defaultManager].xmppRoster subscribePresenceToUser:jid]; } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated. } //#pragma mark XMPPRoster 的代理方法 #pragma mark 开始检索好友列表的方法 -(void)xmppRosterDidBeginPopulating:(XMPPRoster *)sender{ NSLog(@"开始检索好友列表"); } #pragma mark 正在检索好友列表的方法 -(void)xmppRoster:(XMPPRoster *)sender didRecieveRosterItem:(DDXMLElement *)item{ NSLog(@"每一个好友都会走一次这个方法"); //获得item的属性里的jid字符串,再通过它获得jid对象 NSString *jidStr = [[item attributeForName:@"jid"] stringValue]; XMPPJID *jid = [XMPPJID jidWithString:jidStr]; //是否已经添加 if ([self.rosterJids containsObject:jid]) { return; } //将好友添加到数组中去 [self.rosterJids addObject:jid]; //添加完数据要更新UI(表视图更新) NSIndexPath *indexPath = [NSIndexPath indexPathForRow:self.rosterJids.count-1 inSection:0]; [self.friendsView insertRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic]; } @end
ChatViewController.h
#import "ViewController.h" #import "XMPPManager.h" @interface ChatViewController : ViewController<XMPPStreamDelegate,UITableViewDataSource,UITableViewDelegate,UIImagePickerControllerDelegate,UINavigationControllerDelegate> @property(nonatomic,strong) XMPPJID *chatToJid; @property(nonatomic,retain) NSMutableArray *messages; @property(nonatomic,strong) UITableView *tableView; @end
ChatViewController.m
#import "ChatViewController.h" @interface ChatViewController () @end @implementation ChatViewController - (void)viewDidLoad { [super viewDidLoad]; self.title=self.chatToJid.user; self.view.backgroundColor=[UIColor grayColor]; //初始化聊天数组 self.messages=[[NSMutableArray alloc]init]; //设置代理 [[XMPPManager defaultManager].xmppStream addDelegate:self delegateQueue:dispatch_get_main_queue()]; // [self reloadMessage]; // UIBarButtonItem *sendMessage=[[UIBarButtonItem alloc]initWithTitle:@"发送" style:UIBarButtonItemStylePlain target:self action:@selector(doSend)]; self.navigationItem.rightBarButtonItem=sendMessage; [self.view addSubview:self.tableView]; } -(void)doSend{ /* //创建一个消息对象,并且指明接收者 XMPPMessage *message = [XMPPMessage messageWithType:@"chat" to:self.chatToJid]; //设置消息内容 [message addBody:@"呵呵呵呵呵呵呵呵呵呵啊啊啊啊啊啊"]; //发送消息 [[XMPPManager defaultManager].xmppStream sendElement:message]; //发送成功或者失败,有两种对应的代理方法 */ UIImagePickerController *pick=[[UIImagePickerController alloc]init]; pick.delegate=self; [self presentViewController:pick animated:YES completion:^{ }]; } -(void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary<NSString *,id> *)info{ //获取相册里的图片 //UIImage *image=info[UIImagePickerControllerOriginalImage]; UIImage *image=[UIImage imageNamed:@"1.png"]; //转化成NSData NSData *data=UIImagePNGRepresentation(image); //发送 [self sendImageWithData:data andName:@"图片"]; // [self dismissViewControllerAnimated:YES completion:nil]; } -(void)sendImageWithData:(NSData*)data andName:(NSString*)name{ XMPPMessage *message= [XMPPMessage messageWithType:@"chat" to:self.chatToJid]; [message addBody:name]; // NSString *base64Str=[data base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength]; // XMPPElement *attachment=[XMPPElement elementWithName:@"attachment" stringValue:base64Str]; // [message addChild:attachment]; // [[XMPPManager defaultManager].xmppStream sendElement:message]; } -(UITableView*)tableView{ if (!_tableView) { _tableView=[[UITableView alloc]initWithFrame:CGRectMake(0, 0, 300, self.view.frame.size.height) style:UITableViewStylePlain]; _tableView.dataSource=self; _tableView.delegate=self; } return _tableView; } #pragma tableView delegate -(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{ return 1; } -(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{ return self.messages.count; } -(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{ return 100; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { //NSLog(@"cell"); static NSString *cellIndentifier = @"cell"; UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIndentifier]; if (cell==nil) { cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:cellIndentifier]; } //将聊天信息放到cell上 //拿到一个聊天消息 XMPPMessageArchiving_Message_CoreDataObject *message = self.messages[indexPath.row]; XMPPMessage *msg=message.message; if (message.isOutgoing == YES) { cell.detailTextLabel.text = message.body; cell.textLabel.text=@""; for(XMPPElement *node in msg.children){ NSLog(@"图片呢"); //取出消息 NSString *base64Str=node.stringValue; //NSLog(@"%@",base64Str); //base64转换成NSData NSData *data=[[NSData alloc]initWithBase64EncodedString:base64Str options:1]; UIImage *image=[[UIImage alloc]initWithData:data]; cell.imageView.image=image; cell.imageView.frame=CGRectMake(0, 0, 50, 50); cell.imageView.backgroundColor=[UIColor redColor]; } }else{ cell.textLabel.text = message.body; cell.detailTextLabel.text=@""; } // cell.imageView.backgroundColor=[UIColor redColor]; // cell.imageView.image=[UIImage imageNamed:@"1.png"]; return cell; } #pragma mark 聊天的代理方法 -(void)xmppStream:(XMPPStream *)sender didSendMessage:(XMPPMessage *)message{ NSLog(@"消息发送成功"); [self reloadMessage]; } -(void)xmppStream:(XMPPStream *)sender didFailToSendMessage:(XMPPMessage *)message error:(NSError *)error{ NSLog(@"消息发送失败"); } -(void)xmppStream:(XMPPStream *)sender didReceiveMessage:(XMPPMessage *)message{ NSLog(@"消息接受成功"); [self reloadMessage]; } -(void)xmppStream:(XMPPStream *)sender didReceiveError:(DDXMLElement *)error{ NSLog(@"接收失败"); } #pragma mark 刷新消息的方法 -(void)reloadMessage{ //得到上下文 NSManagedObjectContext *context = [XMPPManager defaultManager].messageArchivingContext; //搜索对象 NSFetchRequest *request = [[NSFetchRequest alloc]init]; //创建一个实体描述 NSEntityDescription *entity = [NSEntityDescription entityForName:@"XMPPMessageArchiving_Message_CoreDataObject" inManagedObjectContext:context]; [request setEntity:entity]; //查询条件 NSPredicate *pre = [NSPredicate predicateWithFormat:@"streamBareJidStr = %@ AND bareJidStr = %@",[XMPPManager defaultManager].xmppStream.myJID.bare,self.chatToJid.bare]; request.predicate = pre; //排序方式 NSSortDescriptor *sort = [[NSSortDescriptor alloc]initWithKey:@"timestamp" ascending:YES]; request.sortDescriptors = @[sort]; //执行查询 NSError *error = nil; NSArray *array = [context executeFetchRequest:request error:&error]; if (self.messages.count != 0) { [self.messages removeAllObjects]; } [self.messages addObjectsFromArray:array]; [self.tableView reloadData]; if (self.messages.count>0) { NSIndexPath *indexpath=[NSIndexPath indexPathForRow:self.messages.count-1 inSection:0]; [self.tableView scrollToRowAtIndexPath:indexpath atScrollPosition:UITableViewScrollPositionTop animated:YES]; } } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated. } @end
运行截图:(基本功能实现,具体细节还需要优化)
初探佳境,多多学习交流
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步