首页 > 代码库 > 即时通讯之XMPP好友列表、添加好友、获取会话内容、简单聊天

即时通讯之XMPP好友列表、添加好友、获取会话内容、简单聊天

1、好友列表

初始化好友花名册

 1 #pragma mark - 管理好友 2         // 获取管理好友的单例对象 3         XMPPRosterCoreDataStorage *rosterStorage = [XMPPRosterCoreDataStorage sharedInstance]; 4         // 用管理好友的单例对象初始化Roster花名册 5         // 好友操作是耗时操作 6         self.xmppRoster = [[XMPPRoster alloc] initWithRosterStorage:rosterStorage dispatchQueue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)]; 7         // 在通道中激活xmppRoster 8         [self.xmppRoster activate:self.xmppStream]; 9         // 设置代理10         [self.xmppRoster addDelegate:self delegateQueue:dispatch_get_main_queue()];

 XMPPRoster代理方法

  好友列表

技术分享

  添加好友

技术分享

  删除好友

技术分享

  XMPPManager.h 新增代码

 

1 #pragma mark - 添加好友2 - (void)addFriend;3 4 #pragma mark - 删除好友5 - (void)removeFriendWithName:(NSString *)userName;6 7 #pragma mark - 手动断开连接(注销)8 - (void)disconnectionToServer;

 

 

 

  XMPPManager.m 新增代码

 

  1 /// 接收要添加好友的名字  2 @property (nonatomic, strong) UITextField *addText;  3   4 #pragma mark - 重写初始化方法  5 - (instancetype)init {  6     if (self = [super init]) {  7 #pragma mark - 创建通道  8         // 初始化通道对象  9         self.xmppStream = [[XMPPStream alloc] init]; 10         // 设置Openfire服务器主机名 11         self.xmppStream.hostName = kHostName; 12         // 设置服务器端口号 13         self.xmppStream.hostPort = kHostPort; 14         // 设置代理 15         [self.xmppStream addDelegate:self delegateQueue:dispatch_get_main_queue()]; 16          17 #warning -----------------以下是该方法中新增加的代码----------------------- 18 #pragma mark - 管理好友 19         // 获取管理好友的单例对象 20         XMPPRosterCoreDataStorage *rosterStorage = [XMPPRosterCoreDataStorage sharedInstance]; 21         // 用管理好友的单例对象初始化Roster花名册 22         // 好友操作是耗时操作 23         self.xmppRoster = [[XMPPRoster alloc] initWithRosterStorage:rosterStorage dispatchQueue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)]; 24         // 在通道中激活xmppRoster 25         [self.xmppRoster activate:self.xmppStream]; 26         // 设置代理 27         [self.xmppRoster addDelegate:self delegateQueue:dispatch_get_main_queue()]; 28          29 #warning -----------------以上是该方法中新增加的代码----------------------- 30  31     } 32     return self; 33 } 34  35 #pragma mark -----------------以下是管理好友列表---------------- 36 #pragma mark - 添加好友 37 - (void)addFriend { 38     NSLog(@"manager - 添加好友 %d", __LINE__); 39     UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"添加好友" message:@"请输入要添加好友的名字" preferredStyle:UIAlertControllerStyleAlert]; 40     __weak typeof(self)weakSelf = self; 41     [alertController addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) { 42         // 接收输入的好友名字 43         weakSelf.addText = textField; 44     }]; 45     UIAlertAction *cancleAction = [UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:nil]; 46     UIAlertAction *sureAction = [UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) { 47         NSLog(@"======%@", weakSelf.addText.text); 48         // 使用JID记录 49         XMPPJID *addJID = [XMPPJID jidWithUser:weakSelf.addText.text domain:kDomin resource:kResource]; 50         // 监听好友的动作 51         [weakSelf.xmppRoster subscribePresenceToUser:addJID]; 52         // 添加好友 53         [weakSelf.xmppRoster addUser:addJID withNickname:weakSelf.addText.text]; 54     }]; 55     [alertController addAction:sureAction]; 56     [alertController addAction:cancleAction]; 57     [[self getCurrentVC ]presentViewController:alertController animated:YES completion:nil]; 58 } 59  60 #pragma mark - 删除好友 61 - (void)removeFriendWithName:(NSString *)userName { 62     NSLog(@"manager删除好友 %d", __LINE__); 63     // 使用JID记录要删除的用户名 64     XMPPJID *removeJID = [XMPPJID jidWithUser:userName domain:kDomin resource:kResource]; 65     // 停止监听好友 66     [self.xmppRoster unsubscribePresenceFromUser:removeJID]; 67     // 删除好友 68     [self.xmppRoster removeUser:removeJID]; 69 } 70 #pragma mark - 获取当前屏幕显示的viewcontroller 71 - (UIViewController *)getCurrentVC 72 { 73     UIViewController *result = nil; 74      75     UIWindow * window = [[UIApplication sharedApplication] keyWindow]; 76     if (window.windowLevel != UIWindowLevelNormal) 77     { 78         NSArray *windows = [[UIApplication sharedApplication] windows]; 79         for(UIWindow * tmpWin in windows) 80         { 81             if (tmpWin.windowLevel == UIWindowLevelNormal) 82             { 83                 window = tmpWin; 84                 break; 85             } 86         } 87     } 88      89     UIView *frontView = [[window subviews] objectAtIndex:0]; 90     id nextResponder = [frontView nextResponder]; 91      92     if ([nextResponder isKindOfClass:[UIViewController class]]) 93         result = nextResponder; 94     else 95         result = window.rootViewController; 96      97     return result; 98 }

  RosterListTableViewController.m 好友列表显示页面

  1 #import "RosterListTableViewController.h"  2 #import "XMPPManager.h"  3 #import "ChatTableViewController.h"  4   5 @interface RosterListTableViewController ()<XMPPRosterDelegate, XMPPStreamDelegate>  6   7 /// 好友列表  8 @property (nonatomic, strong) NSMutableArray *allRosterArray;  9 /// 用来存储发送好友请求者的JID 10 @property (nonatomic, strong) XMPPJID *fromJID; 11  12 @end 13  14 @implementation RosterListTableViewController 15  16 - (void)viewDidLoad { 17     [super viewDidLoad]; 18     // 初始化数组 19     self.allRosterArray = [NSMutableArray array]; 20      21     [[XMPPManager sharedXMPPManager].xmppStream addDelegate:self delegateQueue:dispatch_get_main_queue()]; 22     [[XMPPManager sharedXMPPManager].xmppRoster addDelegate:self delegateQueue:dispatch_get_main_queue()]; 23     self.title = @"好友列表"; 24      25     // 添加按钮 26     self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:@selector(addFriendAction)]; 27     // 返回按钮 28     self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"注销" style:UIBarButtonItemStylePlain target:self action:@selector(cancleAction)]; 29      30     [self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:@"RosterCell"]; 31  32 } 33  34  35 #pragma mark - 添加好友按钮点击事件 36 - (void)addFriendAction { 37      38     [[XMPPManager sharedXMPPManager] addFriend]; 39 } 40  41 #pragma mark - 注销按钮点击事件 42 - (void)cancleAction { 43     // 注销 44     [[XMPPManager sharedXMPPManager] disconnectionToServer]; 45     [self.navigationController popViewControllerAnimated:YES]; 46 } 47  48 #pragma mark - Table view data source 49  50 - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { 51     return 1; 52 } 53  54 - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { 55     return self.allRosterArray.count; 56 } 57  58  59 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 60     UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"RosterCell" forIndexPath:indexPath]; 61      62     // 根据项目情况分析,合理添加判断 63     if (self.allRosterArray.count > 0) { 64         // 获取用户 65         XMPPJID *jid = [self.allRosterArray objectAtIndex:indexPath.row]; 66         cell.textLabel.text = jid.user; 67         NSLog(@"bare %@", jid.bare); 68     } 69      70     return cell; 71 } 72  73  74 - (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath { 75     return YES; 76 } 77  78 - (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath { 79     if (editingStyle == UITableViewCellEditingStyleDelete) { 80         // 删除一个好友 81         XMPPJID *jid = self.allRosterArray[indexPath.row]; 82         // 根据名字删除好友 83         [[XMPPManager sharedXMPPManager] removeFriendWithName:jid.user]; 84         // 从数组中移除 85         [self.allRosterArray removeObjectAtIndex:indexPath.row]; 86         [tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade]; 87     } else if (editingStyle == UITableViewCellEditingStyleInsert) { 88      89     }    90 } 91  92 #pragma mark - 点击cell进入聊天界面 93 - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { 94     ChatTableViewController *chatTVC = [[ChatTableViewController alloc] initWithStyle:UITableViewStylePlain]; 95     // 将当前好友的JID传到聊天界面 96     chatTVC.chatWithJID = self.allRosterArray[indexPath.row]; 97     [self.navigationController pushViewController:chatTVC animated:YES]; 98 } 99 100 #pragma mark - ----------------XMPPRosterDelegate代理方法----------------101 #pragma mark - 开始获取好友102 - (void)xmppRosterDidBeginPopulating:(XMPPRoster *)sender {103     NSLog(@"listTVC 开始获取好友 %d", __LINE__);104 }105 106 #pragma mark - 结束获取好友107 - (void)xmppRosterDidEndPopulating:(XMPPRoster *)sender {108     NSLog(@"listTVC 获取好友结束 %d", __LINE__);109     // 当前页面是用于显示好友列表的,所以在结束获取好友的代理方法中要进行页面刷新页面,然后将数据显示。110     // 刷新UI111     [self.tableView reloadData];112 }113 114 #pragma mark - 接收好友信息115 116 // 获取好友列表时会执行多次,每次获取一个好友信息并将该好友信息添加到数组中117 // 发送完添加好友请求会执行118 // 同意别人的好友请求会执行119 // 删除好友时会执行120 - (void)xmppRoster:(XMPPRoster *)sender didReceiveRosterItem:(DDXMLElement *)item {121     NSLog(@"listTVC 接收好友信息 %d", __LINE__);122     /**123      *  好友信息状态有5种124         both - 互为好友125         none - 互不为好友126         to - 请求添加对方为好友,对方还没有同意127         from - 对方添加我为好友,自己还没有同意128         remove - 曾经删除的好友129      */130     131     // 自己和对方之间的关系132     NSString *description = [[item attributeForName:@"subscription"] stringValue];133     NSLog(@"关系%@", description);134 135     // 显示我的好友136     if ([description isEqualToString:@"both"]) {137         // 添加好友138         // 获取好友的JID139         NSString *friendJID = [[item attributeForName:@"jid"] stringValue];140         XMPPJID *jid = [XMPPJID jidWithString:friendJID];141         // 如果数组中含有这个用户,那么不添加进数组142         if ([self.allRosterArray containsObject:jid]) {143             NSLog(@"已经有该好友");144             return;145         }146         // 添加好友到数组中147         [self.allRosterArray addObject:jid];148 149         // 在TableView的最后一个cell下面添加这条数据150         NSIndexPath *indexPath = [NSIndexPath indexPathForItem:self.allRosterArray.count - 1 inSection:0];151         [self.tableView insertRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationLeft];152     }153 }154 155 #pragma mark - 接收到添加好友的请求,选择接受or拒绝156 - (void)xmppRoster:(XMPPRoster *)sender didReceivePresenceSubscriptionRequest:(XMPPPresence *)presence {157     NSLog(@"listTVC 接收添加好友的请求 %d", __LINE__);158     self.fromJID = presence.from;159     // 需要相关的提醒框去确定是否接受好友请求160     UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"请求添加好友" message:@"是否同意" preferredStyle:UIAlertControllerStyleAlert];161     __weak typeof(self)weakSelf = self;162     UIAlertAction *acceptAction = [UIAlertAction actionWithTitle:@"同意" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {163         // 添加到花名册164         [[XMPPManager sharedXMPPManager].xmppRoster acceptPresenceSubscriptionRequestFrom:weakSelf.fromJID andAddToRoster:YES];165     }];166     UIAlertAction *rejectAction = [UIAlertAction actionWithTitle:@"拒绝" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {167         [[XMPPManager sharedXMPPManager].xmppRoster rejectPresenceSubscriptionRequestFrom:weakSelf.fromJID];168     }];169     [alertController addAction:acceptAction];170     [alertController addAction:rejectAction];171     [self presentViewController:alertController animated:YES completion:nil];172 }173 174 #pragma mark - ----------------XMPPStreamDelegate代理方法----------------175 #pragma mark - 判断好友是否处于上线状态176 - (void)xmppStream:(XMPPStream *)sender didReceivePresence:(XMPPPresence *)presence {177     NSLog(@"listTVC 判断好友是否处于上线状态 %@ %d", presence.status, __LINE__);178     NSString *type = presence.type;179     NSString *presenceUser = presence.to.user;180     // 判断当前用户是否为好友181     if ([presenceUser isEqualToString:[sender myJID].user]) {182         if ([type isEqualToString:@"available"]) {183             NSLog(@"该用户处于上线状态");184         } else if ([type isEqualToString:@"unavailable"]) {185             NSLog(@"该用户处于下线状态");186         }187     }188 }189 190 @end

 

2、聊天

聊天的规则:

1、从服务器获取聊天记录

2、根据消息类XMPPMessageArchiving_Message_CoreDataObject的对象的属性isOutgoing来判断该消息是不是对方发送过来的消息 YES - 对方发送的消息, NO - 自己发送给对方的消息

3、发送消息

4、接收消息

  初始化消息归档

 

 1 #pragma mark - 初始化消息归档 2         // 获取管理消息的存储对象 3         XMPPMessageArchivingCoreDataStorage *storage = [XMPPMessageArchivingCoreDataStorage sharedInstance]; 4         // 进行消息管理器的初始化 5         self.xmppMessageArchiving = [[XMPPMessageArchiving alloc] initWithMessageArchivingStorage:storage dispatchQueue:dispatch_get_main_queue()]; 6         // 在通道中激活xmppMessageArchiving 7         [self.xmppMessageArchiving activate:self.xmppStream]; 8         // 设置代理 9         [self.xmppMessageArchiving addDelegate:self delegateQueue:dispatch_get_main_queue()];10         // 设置管理上下文 (此时不再从AppDelegate获取)11         self.context = storage.mainThreadManagedObjectContext;

 

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

1、创建请求

2、创建实体描述,实体名:   XMPPMessageArchiving_Message_CoreDataObject

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

4、创建排序对象,排序条件:timestamp

5、执行请求

接受、发送消息用到的代理方法

技术分享

消息气泡

 

 技术分享

  XMPPManager.h 新增代码

1 /// 和聊天相关的属性,消息归档2 @property (nonatomic, strong) XMPPMessageArchiving *xmppMessageArchiving;3 /// 管理数据库上下文4 @property (nonatomic, strong) NSManagedObjectContext *context;

  XMPPManager.m 新增代码

#pragma mark - 重写初始化方法- (instancetype)init {    if (self = [super init]) {#pragma mark - 创建通道        // 初始化通道对象        self.xmppStream = [[XMPPStream alloc] init];        // 设置Openfire服务器主机名        self.xmppStream.hostName = kHostName;        // 设置服务器端口号        self.xmppStream.hostPort = kHostPort;        // 设置代理        [self.xmppStream addDelegate:self delegateQueue:dispatch_get_main_queue()];                #pragma mark - 管理好友        // 获取管理好友的单例对象        XMPPRosterCoreDataStorage *rosterStorage = [XMPPRosterCoreDataStorage sharedInstance];        // 用管理好友的单例对象初始化Roster花名册        // 好友操作是耗时操作        self.xmppRoster = [[XMPPRoster alloc] initWithRosterStorage:rosterStorage dispatchQueue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)];        // 在通道中激活xmppRoster        [self.xmppRoster activate:self.xmppStream];        // 设置代理        [self.xmppRoster addDelegate:self delegateQueue:dispatch_get_main_queue()];        #warning -----------------以下是该方法中新增加的代码-----------------------#pragma mark - 初始化管理归档        // 获取管理消息的存储对象        XMPPMessageArchivingCoreDataStorage *storage = [XMPPMessageArchivingCoreDataStorage sharedInstance];        // 进行消息管理器的初始化        self.xmppMessageArchiving = [[XMPPMessageArchiving alloc] initWithMessageArchivingStorage:storage dispatchQueue:dispatch_get_main_queue()];        // 在通道中激活xmppMessageArchiving        [self.xmppMessageArchiving activate:self.xmppStream];        // 设置代理        [self.xmppMessageArchiving addDelegate:self delegateQueue:dispatch_get_main_queue()];        // 设置管理上下文 (此时不再从AppDelegate获取)        self.context = storage.mainThreadManagedObjectContext;#warning -----------------以上是该方法中新增加的代码-----------------------    }    return self;}

  从好友列表页面点击cell进入聊天界面

  RosterListTableViewController.m 好友列表界面新增代码

1 #pragma mark - 点击cell进入聊天界面2 - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {3     ChatTableViewController *chatTVC = [[ChatTableViewController alloc] initWithStyle:UITableViewStylePlain];4     // 将当前好友的JID传到聊天界面5     chatTVC.chatWithJID = self.allRosterArray[indexPath.row];6     [self.navigationController pushViewController:chatTVC animated:YES];7 }

  聊天界面

  ChatTableViewController.h

1 #import <UIKit/UIKit.h>2 #import "XMPPManager.h"3 4 @interface ChatTableViewController : UITableViewController5 /// 当前和谁在聊天6 @property (nonatomic, strong) XMPPJID *chatWithJID;7 @end

 

   ChatTableViewController.m

  1 #import "ChatTableViewController.h"  2 #import "ChatTableViewCell.h"  3   4 @interface ChatTableViewController ()<XMPPStreamDelegate>  5 @property (nonatomic, strong) NSMutableArray *allMessageArray;  6 @end  7   8 @implementation ChatTableViewController  9  10 - (void)viewDidLoad { 11     [super viewDidLoad]; 12     self.allMessageArray = [NSMutableArray array]; 13     // 隐藏分割线 14     self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone; 15     // 注册cell 16     [self.tableView registerClass:[ChatTableViewCell class] forCellReuseIdentifier:@"chatCell"]; 17     // 发送按钮 18     self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"取消" style:UIBarButtonItemStylePlain target:self action:@selector(cancelAction)]; 19     // 取消按钮 20     self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"发送" style:UIBarButtonItemStylePlain target:self action:@selector(sendMessageAction)]; 21     [[XMPPManager sharedXMPPManager].xmppStream addDelegate:self delegateQueue:dispatch_get_main_queue()]; 22  23     // 获取显示消息的方法 24     [self showMessage]; 25      26 } 27  28 #pragma mark - 取消按钮点击事件 29 - (void)cancelAction { 30     // 返回上一界面 31     [self.navigationController popViewControllerAnimated:YES]; 32 } 33 #pragma mark - 发送消息按钮点击事件 34 - (void)sendMessageAction { 35     XMPPMessage *message = [XMPPMessage messageWithType:@"chat" to:self.chatWithJID]; 36     // 设置message的body为固定值 (没有实现发送自定义消息) 37     [message addBody:@"我爱你"]; 38     // 通过通道进行消息发送 39     [[XMPPManager sharedXMPPManager].xmppStream sendElement:message]; 40 } 41  42 #pragma mark - 显示消息 43 - (void)showMessage { 44     // 获取管理对象上下文 45     NSManagedObjectContext *context = [XMPPManager sharedXMPPManager].context; 46     // 初始化请求对象 47     NSFetchRequest *request = [[NSFetchRequest alloc] init]; 48     // 获取实体 49     NSEntityDescription *entity = [NSEntityDescription entityForName:@"XMPPMessageArchiving_Message_CoreDataObject" inManagedObjectContext:context]; 50     // 设置查询请求的实体 51     [request setEntity:entity]; 52     // 设置谓词查询 (当前用户的jid,对方用户的jid)  (根据项目需求而定) 53     request.predicate = [NSPredicate predicateWithFormat:@"streamBareJidStr == %@ AND bareJidStr == %@",[XMPPManager sharedXMPPManager].xmppStream.myJID.bare,self.chatWithJID.bare]; 54     // 按照时间顺序排列 55     NSSortDescriptor *sort = [[NSSortDescriptor alloc] initWithKey:@"timestamp" ascending:YES]; 56     [request setSortDescriptors:@[sort]]; 57     // 获取到存储在数据库中的聊天记录 58     NSArray *resultArray = [context executeFetchRequest:request error:nil]; 59     // 先清空消息数组 (根据项目需求而定) 60     [self.allMessageArray removeAllObjects]; 61     // 将结果数组赋值给消息数组 62     self.allMessageArray = [resultArray mutableCopy]; 63     // 刷新UI 64     [self.tableView reloadData]; 65     // 当前聊天记录跳到最后一行 66     if (self.allMessageArray.count > 0) { 67         NSIndexPath * indexPath = [NSIndexPath indexPathForRow:self.allMessageArray.count - 1 inSection:0]; 68         // 跳到最后一行 69         [self.tableView selectRowAtIndexPath:indexPath animated:YES scrollPosition:UITableViewScrollPositionBottom]; 70     } 71     [context save:nil]; 72 } 73  74 #pragma mark - Table view data source 75 - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { 76     return 1; 77 } 78  79 - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { 80     return self.allMessageArray.count; 81 } 82  83  84 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 85     ChatTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"chatCell" forIndexPath:indexPath]; 86     // 数组里存储的是XMPPMessageArchiving_Message_CoreDataObject对象 87     XMPPMessageArchiving_Message_CoreDataObject *message = [self.allMessageArray objectAtIndex:indexPath.row]; 88     // 设置cell中的相关数据 89     // 根据isOutgoing判断是不是对方发送过来的消息 YES - 对方发送的消息, NO - 自己发送给对方的消息 90     cell.isOut = message.isOutgoing; 91     cell.message = message.body; 92      93     return cell; 94 } 95  96 - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { 97     // cell的高度并没有自适应 98     return 70; 99 }100 101 #pragma mark - ------------XMPPStreamDelegate相关代理------------102 #pragma mark - 已经发送消息103 - (void)xmppStream:(XMPPStream *)sender didSendMessage:(XMPPMessage *)message {104     // 重新对消息进行操作105     [self showMessage];106 }107 #pragma mark - 已经接收消息108 - (void)xmppStream:(XMPPStream *)sender didReceiveMessage:(XMPPMessage *)message {109     // 重新对消息进行操作110     [self showMessage];111 }112 113 #pragma mark - 消息发送失败114 - (void)xmppStream:(XMPPStream *)sender didFailToSendMessage:(XMPPMessage *)message error:(NSError *)error {115     NSLog(@"消息发送失败");116 }117 118 @end

  自定义cell

  ChatTableViewCell.h

#import <UIKit/UIKit.h>@interface ChatTableViewCell : UITableViewCell/// 判断是不是对方发送过来的消息 YES - 对方发送的消息, NO - 自己发送给对方的消息@property (nonatomic, assign) BOOL isOut;/// 消息内容@property (nonatomic, copy) NSString *message;@end

  ChatTableViewCell.m

 

 1 #import "ChatTableViewCell.h" 2  3 @interface ChatTableViewCell () 4 /// 头像 5 @property(nonatomic,strong)UIImageView * headerImageView; 6 /// 消息框背景 7 @property(nonatomic,strong)UIImageView * backgroundImageView; 8 /// 显示每一条聊天内容 9 @property(nonatomic,strong)UILabel * contentLabel;10 @end11 12 @implementation ChatTableViewCell13 14 //使用懒加载创建并初始化所有UI控件15 - (UILabel *)contentLabel{16     if (_contentLabel == nil) {17         _contentLabel = [[UILabel alloc] init];18     }19     return _contentLabel;20 }21 - (UIImageView *)backgroundImageView22 {23     if (_backgroundImageView == nil) {24         _backgroundImageView = [[UIImageView alloc] init];25     }26     return _backgroundImageView;27 }28 - (UIImageView *)headerImageView29 {30     if (_headerImageView == nil) {31         _headerImageView = [[UIImageView alloc] init];32     }33     return _headerImageView;34 }35 36 37 - (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier{38     self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];39     if (self) {40         //设置cell不能选中41         self.selectionStyle = UITableViewCellSelectionStyleNone;42         43         [self.contentView addSubview:self.backgroundImageView];44         [self.contentView addSubview:self.headerImageView];45         [self.backgroundImageView addSubview:self.contentLabel];46         47     }48     return self;49 }50 51 - (void)awakeFromNib {52     // Initialization code53     54     55 }56 57 //重写isOut的setter方法,来设定cell上的不同布局58 - (void)setIsOut:(BOOL)isOut59 {60     _isOut = isOut;61     CGRect rect = self.frame;62     if (_isOut) {63         self.headerImageView.frame = CGRectMake(rect.size.width-50, 10, 50, 50);64         self.headerImageView.image = [UIImage imageNamed:@"nike"];65     }else{66         self.headerImageView.frame = CGRectMake(0, 10, 50, 50);67         self.headerImageView.image = [UIImage imageNamed:@"keji"];68     }69 }70 //重写message方法,在cell上显示聊天记录71 - (void)setMessage:(NSString *)message72 {73     if (_message != message) {74         _message = message;75         self.contentLabel.text = _message;76         //        self.contentLabel.numberOfLines = 0;77         [self.contentLabel sizeToFit];78         79         CGRect rect = self.frame;80         if (self.isOut) {//发出去的81             // 消息气泡82             self.backgroundImageView.image = [[UIImage imageNamed:@"chat_to"] stretchableImageWithLeftCapWidth:45 topCapHeight:40];83             self.backgroundImageView.frame = CGRectMake(rect.size.width - self.contentLabel.frame.size.width - 50-20, 10, self.contentLabel.frame.size.width+20, rect.size.height-20);84         }else{//接收的85             self.backgroundImageView.image = [[UIImage imageNamed:@"chat_from"] stretchableImageWithLeftCapWidth:45 topCapHeight:40];86             self.backgroundImageView.frame = CGRectMake(50, 10,self.contentLabel.frame.size.width+40, rect.size.height-20);87         }88         //因为contentLabel已经自适应文字大小,故不用设置宽高,但需要设置位置89         self.contentLabel.center = CGPointMake(self.backgroundImageView.frame.size.width/2.0, self.backgroundImageView.frame.size.height/2.0);90         91     }92 }93 94 95 @end

 

 技术分享

 

以上,一个超级简单的即时通讯工具就已经完成,有些逻辑思维是不固定的,可以根据自己的项目需求去更改代码

还有没有实现到的 图片/语音传输,在这里就只说一下原理

1、将图片/语音上传到服务器

2、根据和服务器的约定,拼好文件在服务器的地址(即图片/语音的URL)

3、调用XMPP发送消息方法,将地址发送出去

4、在接收端接收到的为一条文本信息,里面仅仅是一个指向资源文件的URL地址

5、在拿到URL后进行需要的操作(即请求图片/语音显示到页面上)

即时通讯之XMPP好友列表、添加好友、获取会话内容、简单聊天