即時通信之XMPP好友列表、添加好友、獲取會話內容、簡單聊天

一、好友列表

初始化好友花名冊數據庫

複製代碼
 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代理方法windows

  好友列表數組

  添加好友服務器

  刪除好友dom

  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 好友列表顯示頁面atom

複製代碼
  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 // 刷新UI 111 [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 // 獲取好友的JID 139 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
複製代碼

 

二、聊天

聊天的規則:spa

一、從服務器獲取聊天記錄代理

二、根據消息類XMPPMessageArchiving_Message_CoreDataObject的對象的屬性isOutgoing來判斷該消息是否是對方發送過來的消息 YES - 對方發送的消息, NO - 本身發送給對方的消息

三、發送消息

四、接收消息

  初始化消息歸檔

 

複製代碼
 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的方式)

一、建立請求

二、建立實體描述,實體名:   XMPPMessageArchiving_Message_CoreDataObject

三、建立謂詞查詢條件,條件:streamBareJidStr == 本人Jid AND bareJidStr == 好友Jid

四、建立排序對象,排序條件:timestamp

五、執行請求

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

消息氣泡

 

 

  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 : UITableViewController 5 /// 當前和誰在聊天 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 @end 11 12 @implementation ChatTableViewCell 13 14 //使用懶加載建立並初始化全部UI控件 15 - (UILabel *)contentLabel{ 16 if (_contentLabel == nil) { 17 _contentLabel = [[UILabel alloc] init]; 18  } 19 return _contentLabel; 20 } 21 - (UIImageView *)backgroundImageView 22 { 23 if (_backgroundImageView == nil) { 24 _backgroundImageView = [[UIImageView alloc] init]; 25  } 26 return _backgroundImageView; 27 } 28 - (UIImageView *)headerImageView 29 { 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 code 53 54 55 } 56 57 //重寫isOut的setter方法,來設定cell上的不一樣佈局 58 - (void)setIsOut:(BOOL)isOut 59 { 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 *)message 72 { 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
複製代碼

 

 

 

以上,一個超級簡單的即時通信工具就已經完成,有些邏輯思惟是不固定的,能夠根據本身的項目需求去更改代碼

還有沒有實現到的 圖片/語音傳輸,在這裏就只說一下原理

一、將圖片/語音上傳到服務器

二、根據和服務器的約定,拼好文件在服務器的地址(即圖片/語音的URL)

三、調用XMPP發送消息方法,將地址發送出去

四、在接收端接收到的爲一條文本信息,裏面僅僅是一個指向資源文件的URL地址

五、在拿到URL後進行須要的操做(即請求圖片/語音顯示到頁面上)

相關文章
相關標籤/搜索