你的位置:首页 > 操作系统

[操作系统]iOS学习43即时通信之XMPP


本篇是 即时通信之XMPP(2) 接上次 即时通信之XMPP(1)

1. 好友列表

 1> 初始化好友花名册

  // 获取管理好友的单例对象  XMPPRosterCoreDataStorage *rosterStorage = [XMPPRosterCoreDataStorage sharedInstance];  // 给roster属性进行初始化  self.xmppRoster = [[XMPPRoster alloc] initWithRosterStorage:rosterStorage dispatchQueue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0)];  // 将好友列表在通道中激活  [self.xmppRoster activate:self.xmppStream];  // 设置花名册代理  [self.xmppRoster addDelegate:self delegateQueue:dispatch_get_main_queue()];

 2> XMPPRoster代理方法

  代码:

#pragma mark - XMPPRosterDelegate代理方法/// 开始获取好友- (void)xmppRosterDidBeginPopulating:(XMPPRoster *)sender{  NSLog(@"开始获取好友");}/// 结束获取好友- (void)xmppRosterDidEndPopulating:(XMPPRoster *)sender{  // 当前页面适用于显示好友列表的,所以在结束好友获取的代理方法中要进行刷新页面,然后将数据显示  // 刷新页面  [self.tableView reloadData];}// 接收好友的信息// 这个代理方法会被执行多次,每添加完好友,相对应的好友信息都要有反馈- (void)xmppRoster:(XMPPRoster *)sender didReceiveRosterItem:(DD)item{  /*   both 互为好友   none 互不为好友   to 我已经添加对方为好友,但是对方还没有接受   from 对方已经添加我为好友,但是我还没有接受   remove 曾经删除的好友   */    // 描述自己和对方之间的关系  NSString *description = [[item attributeForName:@"subscription"] stringValue];    NSLog(@"description = %@", description);    if ([description isEqualToString:@"to"] || [description isEqualToString:@"none"] || [description isEqualToString:@"both"] || [description isEqualToString:@"from"]) {        // 添加好友    // 获取添加好友的JID    NSString *friendJID = [[item attributeForName:@"jid"] stringValue];        XMPPJID *jid = [XMPPJID jidWithString:friendJID];        // 如果数组中有这个用户,就不用再进行操作    if ([self.allRosterArray containsObject:jid]) {      return;    }        // 添加好友到数组    [self.allRosterArray addObject:jid];        // 在tableView中添加这条数据    NSIndexPath *indexPath = [NSIndexPath indexPathForItem:self.allRosterArray.count - 1 inSection:0];        [self.tableView insertRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationRight];  }}// 收到好友的监听请求(加好友请求),是否同意- (void)xmppRoster:(XMPPRoster *)sender didReceivePresenceSubscriptionRequest:(XMPPPresence *)presence{  self.fromJID = presence.from;  // 需要相关的提醒框去确定是否接受  UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"好友请求" message:@"是否接受好友请求" preferredStyle:UIAlertControllerStyleAlert];    __weak typeof(self)weakSelf = self;    UIAlertAction *acceptAction = [UIAlertAction actionWithTitle:@"接受" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {        // 在花名册中去接受相关的好友    [[XMPPManager shareXMPPManager].xmppRoster acceptPresenceSubscriptionRequestFrom:weakSelf.fromJID andAddToRoster:YES];  }];    UIAlertAction *rejectAction = [UIAlertAction actionWithTitle:@"拒绝" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {        [[XMPPManager shareXMPPManager].xmppRoster rejectPresenceSubscriptionRequestFrom:weakSelf.fromJID];  }];    [alertController addAction:acceptAction];  [alertController addAction:rejectAction];    [self presentViewController:alertController animated:YES completion:nil];}

 3> 添加好友所需方法

  代码:

 

- (void)addFriend{  UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"添加好友" message:@"请输入添加好友的名字" preferredStyle:UIAlertControllerStyleAlert];   __weak typeof(self)mySlef = self;    [alertController addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) {    mySlef.textField = textField;  }];    UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {    NSLog(@"取消删除好友!");  }];    UIAlertAction *ensureAction = [UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {        // 使用JID记录    XMPPJID *friendJID = [XMPPJID jidWithString:[NSString stringWithFormat:@"%@@%@", mySlef.textField.text, kDomin]];    // 监听好友的动作    [mySlef.xmppRoster subscribePresenceToUser:friendJID];    // 添加好友    [mySlef.xmppRoster addUser:friendJID withNickname:mySlef.textField.text];      }];    [alertController addAction:ensureAction];  [alertController addAction:cancelAction];    [[self getCurrentVC] presentViewController:alertController animated:YES completion:nil];}

4> 删除好友

   代码:

#pragma mark - 删除好友- (void)removeFriendWithName:(NSString *)name{  // 使用JID记录  XMPPJID *friendJID = [XMPPJID jidWithUser:name domain:kDomin resource:kResource];    // 停止监听好友  [self.xmppRoster unsubscribePresenceFromUser:friendJID];    // 删除好友  [self.xmppRoster removeUser:friendJID];}

2. 聊天

 1> 聊天的规则:

  • 从服务器获取聊天记录,根据数据属性判断消息类型

  • 发送消息

  • 接收消息

 2> 初始化消息归档

  // 获取管理消息的存储对象  XMPPMessageArchivingCoreDataStorage *storage = [XMPPMessageArchivingCoreDataStorage sharedInstance];  // 消息管理器的初始化  self.messageArchiving = [[XMPPMessageArchiving alloc] initWithMessageArchivingStorage:storage dispatchQueue:dispatch_get_main_queue()];  // 激活通道  [self.messageArchiving activate:self.xmppStream];  // 设置代理  [self.messageArchiving addDelegate:self delegateQueue:dispatch_get_main_queue()];  // 设置消息管理上下文  self.context = [storage mainThreadManagedObjectContext];

 3> 获取聊天记录

  获取聊天记录使用CoreData的方式

  • 创建请求

  • 创建实体描述,实体名:   XMPPMessageArchiving_Message_CoreDataObject

  • 创建谓词查询条件,条件:streamBareJidStr == 本人Jid AND bareJidStr == 好友Jid

  • 创建排序对象,排序条件:timestamp

  • 执行请求

  代码:

#pragma mark - 显示消息- (void)showMessage{  // 获取管理上下文  NSManagedObjectContext *contxt = [XMPPManager shareXMPPManager].context;    // 初始化请求对象  NSFetchRequest *request = [NSFetchRequest new];    // 获取实体  NSEntityDescription *entity = [NSEntityDescription entityForName:@"XMPPMessageArchiving_Message_CoreDataObject" inManagedObjectContext:contxt];    // 设置查询请求的实体  [request setEntity:entity];    // 设置谓词查询  NSPredicate *predicate = [NSPredicate predicateWithFormat:@"streamBareJidStr == %@ AND bareJidStr == %@", [XMPPManager shareXMPPManager].xmppStream.myJID.bare, self.chatToJID.bare];  [request setPredicate:predicate];    // 按照时间顺序排序  NSSortDescriptor *sort = [[NSSortDescriptor alloc] initWithKey:@"timestamp" ascending:YES];  [request setSortDescriptors:@[sort]];    // 执行相关的操作  NSArray *resultArray = [contxt executeFetchRequest:request error:nil];    // 先清空消息数组  [self.allMessageArray removeAllObjects];    // 添加context执行结果数组  [self.allMessageArray addObjectsFromArray:resultArray];    // 刷新UI  [self.tableView reloadData];    // 当前聊天记录跳到最后一行  if (self.allMessageArray.count > 0) {    NSIndexPath * indexPath = [NSIndexPath indexPathForRow:self.allMessageArray.count-1 inSection:0];    // 跳到最后一行    [self.tableView selectRowAtIndexPath:indexPath animated:YES scrollPosition:UITableViewScrollPositionBottom];  }}

 4> 发送消息

#pragma mark - 发送点击方法- (void)sendMessageAction{  // 设置message的body  XMPPMessage *message = [XMPPMessage messageWithType:@"chat" to:self.chatToJID];    // 发送的内容,一般是从输入框获取,这里我们就写成固定的值  [message addBody:@"可以"];    // 通过通道进行消息发送  [[XMPPManager shareXMPPManager].xmppStream sendElement:message];}

 5> 接收/发送消息的回调


 6> 消息气泡


 

以上代码均为练习代码的部分代码!完整练习代码github下载地址: https://github.com/AlonerOwl/UISenior11_-_1

由于只是练习代码,对于界面和部分功能没有优化,看起来比较low,如果有需求,请自己进行优化。

代码效果图: