話不多說,先看一下做好的聊天軟件界面:
//初始換錄音 [self initRecord]; //獲取用戶頭像 [self getHeadImg]; //獲取訂單詳情 [self getOrderDetailInfo];3.在viewWillAppear裡: a.注冊了一些鍵盤和聊天消息的通知 b.啟動了一個20秒的NSTimer輪詢獲取聊天消息
#pragma mark - 輪詢消息 - (void)runLoopMessage { SpeakType speaker = [YCChatInfo getSpeakerPassengerBy:self.orderInfo.bigType]; [[YCReceiveMessageCenter defaultMessageCenter] getMessageListBySpeaker:speaker isRemote:NO andPushId:nil]; }第一句代碼是獲取會話類型,這裡定義了一個枚舉值,主要有以下幾個角色:
//會話類型 enum SpeakType { //Business YCDriverType = 11, YCPassenger = 12, YCSystem = 13, //v5.2.2 增加系統角色 YCLoctionAutoReply = 14, //v5.2.2添加本地自動回復 YCDriverAutoReply = 15, //v5.2.2添加司機自動回復 司機角色 YCLoctionUpdateVersionReply = 16, //v5.2.2 未知消息類型回復 【提示不支持的消息類型。請升級】 }; typedef NSInteger SpeakType;然後根據會話類型去請求聊天list接口,然後請求成功後對數據進行處理:
//isRemote 點擊推送欄消息 if (response && [response[@"ret_code"] integerValue] == 200) { NSArray *array = response[@"result"]; id topVC = [[YCAppDelegate sharedDelegate] topViewController]; __block NSString *orderID = nil; __block NSString *dType = nil; [array enumerateObjectsUsingBlock:^(NSDictionary *result, NSUInteger idx, BOOL *stop) { NSString *type = [self controlMessageDispatch:result]; dType = type; //此處省略五百字 } } else { DLog(@"輪詢數據失敗 response = %@, error = %@", response, error); }
typedef NS_ENUM(NSInteger, ClassType) { OrderClass = 1, ChatClass = 2, UserClass = 3, };第一個是訂單類型消息,第二個是聊天類型消息,第三個是賬戶消息。 如果是訂單消息,根據type去判斷是什麼狀態,然後去發不同的Notification。如果是聊天類型把result傳入:
- (void)receiveChatMessage:(id)object方法,然後有一個消息狀態字段kChatRepeatState,如果kChatRepeatState == 20,表示已讀消息,直接返回。如果不是,用content初始化YCChatInfo:
NSDictionary *content = dic[@"content"]; YCChatInfo *item; item = [[YCChatInfo alloc] initWithDictionary:content];然後去判斷ChatType,有以下幾種:
//聊天 類型 enum ChatType { ChatText = 1, ChatImage = 2, ChatAudio = 3, ChatPOI = 4, ChatMix = 5, //混合內容 ChatCard = 6,//v5.2.2卡片消息 ChatUpdateHint = 701 //v5.2.2不支持類型升級提示 }; typedef NSInteger ChatType;
[[NSNotificationCenter defaultCenter] postNotificationName:kChatMessageNotification object:nil userInfo:@{@"chatInfo" : chatInfo}]; [self.chatStore insertChat:chatInfo];這裡上次有個bug,聊天消息去重之後一直收不到語音消息,就是因為我先把新聊天消息先插入數據,然後再去發通知,導致往界面上顯示聊天消息是總是顯示不上去。
//首先判斷是否是推送消息, 且判斷該條點擊的推送id進入的 if (isRemote && [pushId isEqualToString:result[@"id"]]) { if (!orderID && ([type isEqualToString:@"new_chat"] || [type isEqualToString:@"DRIVER_ARRIVE"] || [type isEqualToString:@"RECEPTION_DRIVER"]|| [type isEqualToString:@"SERVICE_DONE"])) { if ([type isEqualToString:@"new_chat"]) { orderID = result[@"content"][@"topic"]; } else if (![topVC isKindOfClass:[YCSelectDriverViewController class]] && ([type isEqualToString:@"DRIVER_ARRIVE"] || [type isEqualToString:@"RECEPTION_DRIVER"] || [type isEqualToString:@"SERVICE_DONE"])) { orderID = result[@"content"][@"order_id"]; } } } }]; if (orderID) { if ([DefaultValueForKey(kShowWelcome) boolValue]) { if (![topVC isKindOfClass:[YCWelcomeVC class]]) { [[NSNotificationCenter defaultCenter] postNotificationName:kRemotePushVC object:nil userInfo:@{@"orderID" : orderID, @"type":dType}]; } } }
- (void)receiveMessage:(NSNotification *)notification { YCChatInfo *chatInfo = notification.userInfo[@"chatInfo"]; //如果此時來的消息不輸入當前會話 頁面不進行操作 NSString *string1 = [[NSString alloc] initWithFormat:@"%@", chatInfo.orderID]; NSString *string2 = [[NSString alloc] initWithFormat:@"%@", self.orderInfo.serverOrderId]; if (![string1 isEqualToString:string2]) { return ; } NSInteger messageID = chatInfo.messageID; YCChatStore *chatStore = [[YCChatStore alloc]init]; BOOL isNotRepeat = [chatStore selectDBwithMessageID:messageID]; if (!isNotRepeat) { return; } [self insertRowToTableViewByIndexPath:chatInfo isSend:NO]; }第一句話是獲取通知裡傳的聊天消息內容,然後拿chatinfo裡的orderID和通過獲取訂單詳情的接口裡獲得的orderID做比較,如果orderID不一致,直接return。如果一直就去YCChatStore裡的selectDBwithMessageID方法裡查詢數據庫是否有相同的messageID存在,如果存在直接return,如果不存在就插入界面
- (NSIndexPath *)insertRowToTableViewByIndexPath:(YCChatInfo *)chatInfo isSend:(BOOL)isSend { NSIndexPath *indexPath; [self.chatArray addObject:chatInfo]; indexPath = [NSIndexPath indexPathForRow:[self.chatArray count] - 1 inSection:0]; void(^ScrollBlock)() = ^{ DLog(@"%d",indexPath.row); [self.tableView scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionBottom animated:YES]; }; [self.tableView insertRowsAtIndexPaths:@[indexPath] withRowAnimation:YCTableViewRowAnimationFromBottom completion:^{ if (isSend) { ScrollBlock(); } }]; if (!isSend) { ScrollBlock(); } return indexPath; }