話不多說,先看一下做好的聊天軟件界面:


//初始換錄音
[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;
}