極光IM-JMessager使用總結(jié)

前言

對于即時通訊來說,這是一個大的功能,一直以來也沒怎么實際開發(fā)接觸過,自研IM對一個非社交通訊平臺的公司而言,是不必要的,一般都采用第三方IM框架,正好咋公司最近需要一個在電商環(huán)境下用戶和商家之間需要一個簡單的聊天功能,考慮到APP推送采用的是極光推送,那么IM很自然的使用了JMessager了。今天就和大家分享一下使用JMessager的一些細節(jié)處理或者一些坑,給后續(xù)接入者一點預先了解吧。

需要了解的基礎

1.極光IM使用首先要注冊appkey ,這個在極光開發(fā)者網(wǎng)站上新建一個,就會自動生成一個。
需要注意的是:如果您的app之前使用過極光推送的話,那么直接使用極光推送appkey即可,不必要再為IM注冊一個新的key了,因為其實他們是一家的嘛,極光IM就是極光推送充話費送的~~
2.如果您需要集成到您公司旗下不同的2個APP之間聊天的話,就要使用垮APP發(fā)消息的api, 看它的JMessager API即可,就是使用帶appkey參數(shù),這個appkey就是極光平臺appkey, 注意:是要發(fā)送消息的對象所在的APP的key。
3.JMessager iOS的SDK 中設置方法已讀:setMessageHaveRead 此方法有bug, 安卓設備發(fā)消息給iOS設備上,iOS設備設置此方法將消息已讀無效,安卓設備收不到已讀回執(zhí)。安卓這邊確實設置了需要已讀回執(zhí)為true,但就是收不到回執(zhí)。不知道是不是我代碼問題,誰解決了,可以告訴我一下。
4.消息通知欄的內(nèi)容可以自定義,方法是在發(fā)送消息的時候可以設置一個options,這個option里面可以通知欄的style內(nèi)容,消息回執(zhí)也是在這個options里面開啟。
5.據(jù)安卓同事反應,安卓端自定義類型的消息,是不計入消息未讀個數(shù)里面的。這個有點坑!

集成和使用

1.集成:沒什么好說的,pod JMessager即可,然后appdelegate注冊一下。
2.使用:極光iOS開發(fā)文檔說的還是很清楚了,需要注意一點的就是JMGMessager類下面 haveRead這個屬性只針對接收方而言,而且只存在本地。
3.聊天UI代碼設計:
消息Message具體分很多種,文字、語音、定位、圖片、視頻、自定義消息等等,但有個基本的消息UI:發(fā)送者頭像、昵稱、時間、回執(zhí)消息提示等,這些都是跟具體消息無關(guān)的UI,所以,我是設計了一個BaseMessageCell , 然后具體TextMessageCell\VoiceMessageCell繼承BaseMessageCell,這樣每個具體消息cell專注內(nèi)容的布局顯示即可,其他通用的組件由baseMessageCell處理。

UI布局代碼結(jié)構(gòu)

底部輸入控件單獨抽離出來:InputBar.跟業(yè)務無關(guān)的控件需要解耦出來。

4.聊天消息持有的數(shù)組輕量化:
整個聊天UITableView的數(shù)據(jù)源list 的元素只存msgId, message消息體用一個全局的字典NSDictionary.
為啥用字典+nsarray, 而不直接用一個message的大數(shù)組呢?
因為考慮到本地發(fā)出去的消息成功后要用新的服務器message替換本地message數(shù)據(jù)源,那么這里為了便于快速找到數(shù)組里這條message, 如果用message大數(shù)組需要循環(huán)遍歷,找到msgId一樣的很耗時,而dictionary的有點是通過key訪問的,有點是遍歷快速。對于聊天消息越來越多,就是要考慮性能了,看中了dictionary基于hash快速遍歷的特性,而采用了這種方式。

#pragma mark - 創(chuàng)建會話 -
- (void)createConversation {
    [self showHUD];
    [KWJMessager createConversationUsername:self.userName
                                loginIfNeed:YES completed:^(id resultObject, NSError *error) {
        [self HidenHUD];
        if (!error) {
            //創(chuàng)建會話成功,準備聊天環(huán)境
            self.conversation = resultObject;
            self.navigationView.titleLabel.text = self.conversation.title;
            //監(jiān)聽會話消息
            [JMessage addDelegate:self withConversation:self.conversation];
            //拉取最新消息
            [self fectchLastedMessages];
        }else {
            //創(chuàng)建會話失敗
            NSString *tip = [NSString stringWithFormat:@"創(chuàng)建會話失?。?@",@(error.code)];
            makeToast(tip);
        }
    }];
}
#pragma mark - JMessage監(jiān)聽方法 -
//發(fā)送消息回調(diào)
- (void)onSendMessageResponse:(JMSGMessage *)message error:(NSError *)error {
    if (message) {
        self.offset ++;
        //替換本地message數(shù)據(jù)源
        [self.allMessagesDic setObject:message forKey:message.msgId];
        NSInteger row = [self.allMessagesIds indexOfObject:message.msgId];
        [self.messageTableView reloadRowsAtIndexPaths:@[[NSIndexPath indexPathForRow:row inSection:0]]
                                     withRowAnimation:UITableViewRowAnimationNone];
        [self scrollToEnd:YES];
    }else {
        //發(fā)送失敗
        NSString *tip = [NSString stringWithFormat:@"發(fā)送失?。?@",@(error.code)];
        makeToast(tip);
    }
}
//接收到消息
- (void)onReceiveMessage:(JMSGMessage *)message error:(NSError *)error {
    if (message) {
        //往頁面追加一條消息
        self.offset ++;
        [self appendOneMessage:message];
        [self addImageMessageIfNeed:message localImage:nil reverse:NO];
        if (message.contentType != kJMSGContentTypeVoice) {
            //非語音消息,立馬設置已讀
            [message setMessageHaveRead:^(id resultObject, NSError *error) {}];
            //清除會話角標
            [self.conversation clearUnreadCount];
        }
    }
}

//消息回執(zhí)
- (void)onReceiveMessageReceiptStatusChangeEvent:(JMSGMessageReceiptStatusChangeEvent *)receiptEvent {
    NSMutableArray *paths = [NSMutableArray array];
    for (JMSGMessage *msg in receiptEvent.messages) {
        JMSGMessage *old = [self.allMessagesDic objectForKey:msg.msgId];
        [old updateFlag:@(YES)];//標記已讀
        NSInteger i = -1;
        for (NSString *msgid in self.allMessagesIds) {
            if ([msgid isEqualToString:msg.msgId]) {
                i = [self.allMessagesIds indexOfObject:msgid];
                break;
            }
        }
        if (i >= 0 ) {
            NSIndexPath *indexPaths = [NSIndexPath indexPathForRow:i inSection:0];
            [paths addObject:indexPaths];
        }
    }
    [self.messageTableView reloadRowsAtIndexPaths:paths withRowAnimation:UITableViewRowAnimationNone];
    
}
//滑至底部
- (void)scrollToEnd:(BOOL)animated {

    NSInteger rows = [self.messageTableView numberOfRowsInSection:0];
    rows = MIN(rows, self.allMessagesIds.count);
    if (rows > 0) {
        [self.messageTableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:
                                                       rows-1 inSection:0]
                                     atScrollPosition:UITableViewScrollPositionBottom
                                             animated:animated];
    }
    
}

關(guān)于UITableViewCell委托的代碼:(使用基類,結(jié)構(gòu)清晰,代碼簡潔)

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
   NSString *msgId = [self.allMessagesIds safeObjectAtIndex:indexPath.row];
   JMSGMessage *message = [self.allMessagesDic objectForKey:msgId];
   KWChatBaseCell *cell = nil;
   Weakify(self);
   if ([message.content isKindOfClass:[JMSGTextContent class]]) {
       cell = [tableView dequeueReusableCellWithIdentifier:@"text"];
   }else if ([message.content isKindOfClass:[JMSGImageContent class]]) {
       cell = [tableView dequeueReusableCellWithIdentifier:@"image"];
   }else if ([message.content isKindOfClass:[JMSGLocationContent class]]) {
       cell = [tableView dequeueReusableCellWithIdentifier:@"location"];
   }else if ([message.content isKindOfClass:[JMSGVoiceContent class]]) {
       cell = [tableView dequeueReusableCellWithIdentifier:@"voice"];
   }else if ([message.content isKindOfClass:[JMSGCustomContent class]]) {
       KWChatGoodsLinkCell *linkCell = [tableView dequeueReusableCellWithIdentifier:@"link"];
       linkCell.message = message;
       linkCell.actionBlock = ^{
           #pragma mark - 發(fā)送服務鏈接
           [weakself sendGoodsLinkMessage:NO];
       };
       return linkCell;
   }
   cell.message = message;
   cell.actionBlock = ^(ActionType type){
       if (type == ActionTypeLookDetail) {
           [weakself playContentMessage:message indexPath:indexPath];
       }else {
           //消息重發(fā)
           [weakself resendMessage:message];
       }
   };
   return cell;
}

最后貼一下的使用截圖:


image.png

image.png

image.png

列表
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容