近期項目中要接入聊天,相對于直播來說這只是一個小需求,但是中間也有一些坑以及掙扎了好久的半屏聊天的實現。
1.首先先說下實現正常的聊天,講真,融云的文檔寫的是真不怎么樣,模棱兩可,首先看下他的
- (void)getUserInfoWithUserId:(NSString *)userId completion:(void(^)(RCUserInfo* userInfo))completion
方法,按照文檔上寫的是兩個用戶,但是寫法是一樣的,給人一種錯覺就是if else 里面只要寫一樣的就行了,我在后面的操作中也把自己的以及我要聊天的人的信息上傳上去了,但是經實踐是不對的,而且這個方法是只用實現一次的,也就是在appdelegate里面登錄成功后實現一次這個方法就行了,不用每次給誰聊天都掉一下這個方法,正確的寫法是if里面給融云上傳自己的信息,在else里面請求一下自己服務器userid的數據,這個userid就是你要聊天對象的id再把請求的頭像、昵稱賦值給
RCUserInfo *user = [[RCUserInfo alloc]init];
user.userId = userInfo.member_id;
user.name = userInfo.basic_info.nickname;
user.portraitUri = imageUrl;
針對這一塊我是寫了一個單例,RongYunUserInfo,因為融云的token是有期限的,所以在登錄成功之后需要校驗rongyun_token是否為空,如果為空,再去服務器請求一下token
2.搞定了頭像昵稱的顯示,列表顯示正常了,但是從會話列表跳轉到聊天列表,聊天記錄不顯示了,必須手動刷一次才能正常顯示,各種檢查代碼,都是沒問題的,最后沒招,只能提工單了,結果答案是在設置所有RCConversationListViewController屬性之前必須先設置
chatRoomScene.targetId = model.targetId;
chatRoomScene.conversationType = model.conversationType;
真蛋疼。設置完成之后,好了,聊天的正常事項我們都完成了,下面就是半屏聊天了。
3.實現半屏可能這個方法不是最好的,有更好的方法請告知,先說下我最初的實現方法,也給大家規避一些不好的實現方法,因為,我們是有兩個聊天
,外面的完成界面的聊天,里面要實現一個高度只有290的mini聊天界面,但是界面是一樣的,
(1)因為最初的聊天、消息是在導航欄上面設置的,正常的VC是不能設置坐標的,后來想到了用特殊的轉場動畫來實現,因為轉場動畫是可以設置toVC.view = 290的坐標實現一個mini的VC,這樣既保留了導航欄的會話列表還能push到聊天界面,想想都很美好,說干就干了,找了一個簡書上一個大神寫的VC轉場動畫,基本都實現了,很開心,但是馬丹,我從聊天界面跳轉回會話列表的時候,會話列表又變成全屏的了,無論怎么去設置從轉場進來的containView的坐標都不行,甚至用了最low的方法,從新拿到做轉場動畫的主VC的superView來設置也不行,至此,這個方法宣布GG,而且這個方法還有一個致命的問題,當然這個問題不是我們的原因,是融云不支持我們去修改工具欄RCChatSessionInputBarControl的坐標,用轉場動畫toVC是正常的,從toVC push的聊天界面的樣式也是符合要求的minivC,但是他的坐標是按照全屏顯示的,雖然導航欄顯示的是push過來的,但是RCChatSessionInputBarControl還是在從導航欄開始為起始點屏幕的高度為終止點的位置,聊天的collectionView坐標是可以修改的,但是RCChatSessionInputBarControl不能修改,修改了雖然可以看到,但是不響應點擊事件。這樣就不能這樣做了。
(2)既然要保證RCChatSessionInputBarControl在最下方不能修改,后來想到了用presentViewController來實現,分別present一個回話列表和一個聊天界面,現在有一個問題就是我們需要去更改present出來的VC的透明度,因為present出來vc是吧下面遮蓋的,就在網上找到了下設置你要present VC的這三個屬性就可以了
chatRoomScene.definesPresentationContext = YES;
chatRoomScene.modalPresentationStyle = UIModalPresentationOverCurrentContext;
chatRoomScene.view.backgroundColor = [UIColor clearColor];
這個地方以及下面的設置都是基于判斷是present的是miniVC才這樣設置,正常的聊天我們還是按照融云的正常聊天就行了
還是按照上面的方法跳轉到聊天界面,因為他是全屏VC我們是可以去修改他的conversationMessageCollectionView的坐標,這樣保證了不用修改工具欄的坐標,再自定義一個導航欄就可以了
中間需要去做的就是去監聽鍵盤的彈出以及表情View彈出我們去修改試圖的坐標以及自己造的導航欄的坐標動態修改一下試圖的坐標就可以了
因為他的列表還是按照全屏顯示的,我們再讓列表自動滾動到最下方
//滾動到最下面
NSUInteger finalRow = MAX(0, [self.conversationMessageCollectionView numberOfItemsInSection:0] - 1);
if (0 == finalRow) {
return;
}
NSIndexPath *finalIndexPath = [NSIndexPath indexPathForItem:finalRow inSection:0];
[self.conversationMessageCollectionView
scrollToItemAtIndexPath:finalIndexPath
atScrollPosition:UICollectionViewScrollPositionBottom
animated:NO];
其中有一個問題就是返回上一級會話列表的時候數據不會和正常的聊天一樣進行數據刷新,這也是唯一的不足,我的做法是在聊天界面disappear的時候發一個通知讓會話列表去刷新
[[[[NSNotificationCenter defaultCenter]
rac_addObserverForName:@"RefreshMessageScene" object:nil]
takeUntil:[self rac_willDeallocSignal]]
subscribeNext:^(NSNotification *notification) {
@strongify(self);
/*!
從數據庫中重新讀取會話列表數據,并刷新會話列表
@warning 從數據庫中重新讀取并刷新,會比較耗時,請謹慎使用。
*/
[self refreshConversationTableViewIfNeeded];
}];
這個融云官方是不提倡的,但是沒別的辦法,還望誰看到了有更好辦法的給我說一下。
總結,啰里啰嗦說這么多,是希望把自己走的彎路也貼出來給大家一個參考。
更新: 解決同安卓聊天無法正常顯示頭像昵稱的問題
聊天都解決了,但是安卓大兄弟過來說咱們兩端聊天的時候,我給你發消息的時候在iOS是正常的,但是你給我發消息的時候在安卓端顯示不到你的頭像和昵稱,其實這個問題很好解決,就是上面提到的我們沒法顯示頭像昵稱的問題,因為安卓大兄弟也實現了
- (void)getUserInfoWithUserId:(NSString *)userId completion:(void(^)(RCUserInfo* userInfo))completion
這個方法,但是呢,他里面就是我們之前說的問題請求被聊天人信息時沒有實現一次網絡請求,所以拿不到我的信息,當時我一直問安卓大兄弟你這個地方請求網絡了嗎,大兄弟很肯定的告訴我,請求了。直覺告訴我就是這個地方出問題了,我問他呢你是怎么實現的,他說是用攜帶消息體的方式,安卓大兄弟說他如果用代理自己這邊會出問題,那就只好iOS這邊改了,這里補充下,融云的消息傳遞是有兩種方式的,一種是實現代理進行網絡請求,另一種是攜帶消息體的方式,就是把用戶消息直接包含在消息里面,實現方式,兩種方式攜帶消息體的優先級高,會優先讀取消息體,這就是咱們說為啥安卓無法顯示iOS信息,因為我用的代理,而安卓用的是攜帶消息體,我沒有攜帶消息體,他也沒有進行網絡請求,所以顯示就不正常了,攜帶消息體的寫法
[RCIM sharedRCIM].currentUserInfo.userId = @"使用者ID";
[RCIM sharedRCIM].currentUserInfo.name = @"名字";
[RCIM sharedRCIM].currentUserInfo.portraitUri =@"圖像";
//設置發送的消息是否攜帶用戶信息
[RCIM sharedRCIM].enableMessageAttachUserInfo = YES;
這里面有個坑,因為兩種實現方式,我以為實現這種方式之后就不需要再去實現代理了,問工單客服,客服也說不用再實現代理
然后我按照他說的做了,結果就會出現這個叼樣子,只會顯示User<>
后來再想了下,所有的操作我都沒有對用戶信息進行保存,這肯定不是正確做法,
然后我又在原來的實現代理的基礎上,在前面加上了攜帶消息體,至此,所有完結,兩端顯示正常,那么這就有問題了,就按照我之前說的,是兩種實現方式,兩者都存在很明顯是不合理的,然后就又去和安卓大兄弟討論一番,把我的想法和處理邏輯給他說了下,發現他那邊在實現的代理的時候是進行網絡請求,但是沒有將用戶信息請求下來之后再去返回給融云,所以導致了他說的他那邊自己顯示會有異常,然后改了下就完美解決了,咱的代碼再撤銷回去。。。。
2018.6.15更新
近期發現,一個用戶在沒有登錄的情況下,收到不同的人給發的聊天消息,或者自己同時給幾個人發聊天消息,這時候登錄回到聊天界面,會出現幾個人使用一個人的聊天頭像和昵稱,根據數據顯示聊天列表的數據源是對的,但是在getuserinfo的代理方法中會出現給的userid和列表數據不一致的情況(比如列表中有9條數據,但是代理方法中只會給6條左右的數據,導致無法比對數據重復的原因,是新包,無緩存情況下)給融云扯皮了兩天,最后一點點排查,找到原因是在- (void)getUserInfoWithUserId:(NSString )userId completion:(void(^)(RCUserInfo userInfo))completion中調取自己服務器的userInfo后,在返回completion(userInfo)返回的時候,同時要調用 [[RCIM sharedRCIM] refreshUserInfoCache:user withUserId:x.member_id];刷新緩存的userInfo。。。