项目是16年的项目,IMSDK和直播SDK过于老旧,TRTC用的IM也是V1版本的,由于近期每天都能从Bugly和Firebase抓到十几个IM的崩溃。也具体拿崩溃去咨询过腾讯的技术,那边每次回复都是SDK过于老旧。建议更新到最新版本。
意思就是:我们也是在迭代版本,修复BUG,你不更新SDK这些问题我们也没办法解决。并且SDK版本太老,已经不维护了,就是苟延残喘。
其实去年其他的同事已经尝试过更新IMSDK,但是更新后,据同事说,直播间的弹幕就出现问题,一个是内存溢出崩溃,再有就是会直播间很卡顿,最后解决不了,放弃了更新启用老代码。
最近需求不是很多,决定把这个顽固的问题解决掉,更新IMSDK到V2,更新移动直播SDK到V2,更新TRTC到最新版本,相当于重构整个项目的所有主要业务,对自己也是个挑战,撸起袖子开干,给自己加个油,开贴记录一下本次遇到的坑。
一、更新顺序问题
首先更新之前就遇到一个难题,因为项目中主要是3大模块,一个是直播间,一个是私信列表,一个是1v1视频通话。
1、如果先重构IMSDK,可能直播DEMO中的代码已经写好的一部分,也需要我在老代码基础上更新。
2、如果先重构V2TXLive,那更新IMSDK又是先决条件。
最后决定,先删除项目中的IMSDK,导入最新的
这里有个坑:老项目中的IMSDK是直接手动导入项目的,现在要删掉,并且使用cocoapods导入
第一天:
导入IMSDK和移动直播SDK:
pod 'TXLiteAVSDK_Professional' #(8.5.10022)
pod 'TXIMSDK_iOS' #(5.1.60)
后面备注一下导入时的版本号,免得每次在群里跟腾讯反馈问题时,问我SDK版本号,还得现跑程序看。
Command+R运行,不出所料,报错。一堆错误。先删掉报错文件中引用的已被删除的类。还有一些API的改变,一些变量名的改变。修复了一些之后,到了这里
本来是想着先用V1的API修复报错,让程序跑起来再慢慢修复bug,看来是没希望了。因为新的SDK中,不存在TIMGroupListener,让我使用V2,但是腾讯IM文档中,明显标注这:V1和V2的API不可混用,会有问题。现在卡在这了。明天再弄
第二天:
想要解决这个问题只有2种方法,1就是用v2代替v1,从此入手,2就是先暂时将次处代码注释掉。后面等报错都解决了之后,开始捋顺业务的时候,再替换此。此处我决定先按2来执行,如果不行,那么将从IM登陆和初始化入手,直接新建个文件开始重写。
因为删掉了IMFriendshipExt.framework,所以很多文件报错缺失
当做到这里时,发现TIMFriendshipManager.h中,在V3.1.0SDK中,只有60行代码,而新V5.1SDK中 是310行代码。所以怀疑新SDK将原来的单独库合并到一起了,并且公开API到TIMFriendshipManager.h中。修改报错时,得到了认证。
同上,TIMGroupManager.h 老SDK70行,新SDK620行,与上面是一样的。
TIMAddFriendRequest是在IMFriendshipExt.framework里的,新SDK中,里面的API改到TIMAddFriendshipDefine.h里。并且改为TIMFriendRequest。
今天改的很顺利。还没到TIMGroupListener,明天继续。
第三天:
继续修改报错,在程序中搜索API,发现有一些API实际并没有用到,这个等后面换V2的时候再统一优化。应该是老SDK的DEMO中腾讯给用户提供的,之前写我们APP的程序员直接拖进来了,后面没用到。
已经改了好多,TLSRefreshTicketListener类也是被删掉了,现在想办法修复。
TIMGroupListener,和TLS票据代码全部删除了,在此记录,有问题的话后面修复,先以修复报错为主。
项目里获取消息是用的:
/**
* 从cache中获取最后几条消息
*
* @param count 需要获取的消息数,最多为20
*
* @return 消息(TIMMessage*)列表,第一条为最新消息
*/
- (NSArray*)getLastMsgs:(uint32_t)count;
但是新的SDK中已经没有这个方法了。现在暂时使用获取本地消息,没有使用获取云端的API
/**
* 2.1 从云端拉取历史消息
*
* 如果用户的网络正常且登录成功,可以通过该接口拉取历史消息,该接口会返回云端存储的历史消息(最多存储7天)。
*
* 1. 单聊和群聊消息会在云端免费存储7天,如果希望存储更长时间,可前往
* ([IM 控制台](https://console.cloud.tencent.com/avc) -> 功能配置 -> 消息 ->消息漫游时长)进行购买,
* 具体资费请参考 [价格说明](https://cloud.tencent.com/document/product/269/11673)。
*
* 2. 对于图片、语音等资源类消息,获取到的消息体只会包含描述信息,需要通过额外的接口下载数据,
* 详情请参考 [消息收发](https://cloud.tencent.com/document/product/269/9150)中的 "消息解析" 部分文档。
*
* @param count 获取数量
* @param last 上次最后一条消息,如果 last 为 nil,从最新的消息开始读取
* @param succ 成功时回调
* @param fail 失败时回调
*
* @return 0:本次操作成功;1:本次操作失败
*/
- (int)getMessage:(int)count last:(TIMMessage*)last succ:(TIMGetMsgSucc)succ fail:(TIMFail)fail;
/**
* 2.2 从本地数据库中获取历史消息
*
* 如果客户网络异常或登录失败,可以通过该接口获取本地存储的历史消息,调用方法和 getMessage() 一致
* AVChatRoom,BChatRoom 消息数量很大,出于程序性能的考虑,默认不存本地,不能通过这个接口拉取到对应群消息
*
* @param count 获取数量
* @param last 上次最后一条消息
* @param succ 成功时回调
* @param fail 失败时回调
*
* @return 0:本次操作成功;1:本次操作失败
*/
- (int)getLocalMessage:(int)count last:(TIMMessage*)last succ:(TIMGetMsgSucc)succ fail:(TIMFail)fail;
后面如果发现问题,再改为获取云端消息。
遇到个棘手的问题,需要使用TIMFriendFutureMeta这个类,但是在新SDK中,只是 @class TIMFriendFutureMeta引用了一下,并没有找到这个类,没有类声明,初始化方法也无法调用。今天先到这,明天继续。
第四天:
IMACustomConversation中的TIMFriendFutureMeta 实在找不到怎么改,暂时先注释掉。
今天有点忙,没改多少明天继续。
第五天:
改的比较顺利,但是遇到一个卡点就是当我们收到IM消息的时候,需要解析消息。
之前获取用户getSenderProfile是同步返回的,现在改成异步回调了。这是个坑点,先做一下记录。
项目编译的时候,被告知需要最低系统支持到12.0,之前我们是支持到9.0的。 这样无疑会损失一些低端用户。也只能如此了。
因为删除了getLastMsgs: 这个同步API,改为异步获取,这样大大增加了项目出错的概率,因为之前好多地方是用同步API获取的最后20条消息,然后将消息体放到一个临时变量里,但是现在改成异步的了。 那无疑会先执行异步下面的方法,增加了难度
用信号量解决了这个问题。参考这张图片。
编译Success,惊讶,一百多个报错修复好了,不容易,不敢轻易运行,怕好多逻辑都有问题
第六天:
这两天被各种同步异步for循环搞的身心疲惫,原业务代码,一个方法,里面包含2个For循环,每个for循环里面是一个异步请求,每次请求后会在一个数组内增改元素,最后block回调处理后的数组。因为原来的IMSDK方法是同步获取的,新SDK改成异步了。这就很矛盾了。从来没处理过这么复杂线程组合。决定先用Demo写出逻辑,并在控制台输出每一步,顺序,延迟,逻辑一切正常后移植到项目中去实现逻辑。
第七天:
方法中还包含2个同步请求,全部揉捏在一起着实有些乱,将2个同步请求改为异步,放弃使用信号量,改为使用gcd的group来实现。
dispatch_group_t group = dispatch_group_create();
dispatch_group_t group2 = dispatch_group_create();
dispatch_group_async(group, dispatch_get_global_queue(0, 0), ^{
NSLog(@"开始");
for (int i = 0; i < 10; i++) {
dispatch_group_enter(group);
dispatch_async(dispatch_get_global_queue(0, 0), ^{
sleep(1);
NSString *t = [NSString stringWithFormat:@"第一波循环,%d", i];
NSLog(@"%@", t);
dispatch_group_leave(group);
});
}
});
dispatch_group_notify(group, dispatch_get_global_queue(0, 0), ^{
NSLog(@"notify----111");
dispatch_group_async(group2, dispatch_get_global_queue(0, 0), ^{
for (int i = 0; i < 10; i++) {
dispatch_group_enter(group2);
dispatch_async(dispatch_get_global_queue(0, 0), ^{
sleep(1);
NSString *t = [NSString stringWithFormat:@"第2222,%d", i];
NSLog(@"%@", t);
dispatch_group_leave(group2);
});
}
});
dispatch_group_notify(group2, dispatch_get_main_queue(), ^{
NSLog(@"notify----22222");
});
});
最后解决了获取好友会话列表和消息缓慢的问题。同时发现一个其他问题,消息红点不准确,当好友快速连续的发送消息时,消息红点增加数会不足。明天继续修复。
第八天:
因为IMSDK给的获取unReadConversationCount是同步直接返回未读消息数,但是实际上此API会有短暂的延迟,立即使用有时会取不到最新的1条,也就是说实际是有5条未读消息,当来了第六条消息后,立刻获取未读消息数,还是返回5,所以在首页的新消息监听回调中,增加1个1s延迟的gcdAfter,再获取未读消息数,这次就准确了。
消息数,和私信列表,新消息通知都修复完毕,接着是直播间的问题。
第九天:
发现了直播间存在的几个重点问题:
1、直播间消息面板滚动卡顿
2、直播间礼物连击动画卡顿,并且有可能导致消失动画执行不了
3、直播间长时间放置后,会卡顿
4、守护位,守护时间会变慢,就是实际守护时长3h,但是通过计时器1s1s加上去的会比实际少,也就是说runloop冲突了或者卡顿了。
5、多次反复进入直播间,重启,进入直播间,重启,最后会在首页收到很多各种群消息,也就是说,当用户退出直播间时,未能退出群组,还在接收群组消息
需要修复上述问题。
第十天:
/**
* 消息回调
*/
@protocol TIMMessageListener
@optional
/**
* 新消息回调通知
*
* @param msgs 新消息列表,TIMMessage 类型数组
*/
- (void)onNewMessage:(NSArray*)msgs;
@end
不知道为什么,这个收到新消息的方法,原项目中写了2处监听,其中一处,每收到一个消息,就会做一个几十次的循环,那么在直播间中,用户发送文字,发送礼物,进入房间,退出房间,等等都是消息,那么程序就会处在一个任何时刻都在For循环的状态中,直接导致UI卡顿,CPU负荷过高。
现在先暂时将导致卡顿的这处代码整个全注掉,并进行功能测试。
确实不卡顿了。但是有一些功能受到了影响,只能去优化它了。
暂时解决办法,先增加一个主线程异步吧。
dispatch_async(dispatch_get_main_queue(), ^{});
运行后观察1h左右,确实不是很卡顿了。但是感觉上还是不流畅,不知道是不是心理作用,然而另一台手机,在没插线连代码的情况下,运行并进入直播间,持续一个半小时左右,会发热,并且很卡,切到home,随便操作几下系统设置,app就被强行杀死了,可见app当时已经占用了极大的内存或者CPU
第十一天:
首先自己对onNewMessage:这个API增加打印,通过控制台输出发现,每收到1个消息,就会输出10-50个回调,并且越来越多。
通过查询腾讯IM的官方文档,他们给出的接口描述为:
/**
* 添加消息回调(重复添加无效)
*
* @param listener 回调
*
* @return 成功
*/
- (int)addMessageListener:(id)listener;
查看自己更新后的IMSDK代码里面的注释,已经没有“重复添加无效”字样。
之前项目中的代码是在:
- (void)onRefresh
这个回调中添加了
[[TIMManager sharedInstance] addMessageListener:self.conversationMgr];
这段代码。显然,每刷新一次,就添加了一个监听者,因为新SDK取消了重复添加无效的逻辑,导致每次收到新消息,就会收到N次回调。
通过使用Time profiler检测CPU占用,用Leaks检测内存泄漏,也指向到了这里。
将添加监听者的代码,移步到IMAConversationManager的初始化代码中,默认添加1次就好了。
之前再长时间久置直播间,并未发现CPU超负荷的情况。
第十一天:
解决第九天的问题5,在消息回调的方法中,判断若是群消息,并且不是用户默认的用户大群(业务逻辑),则执行quitGroup方法,让用户退出直播间群。我看之前项目中也是有这个逻辑的,不过是写在进入直播间后,防止在B直播间,收到A直播间的消息的,现在保留原来的不变,增加一次退群操作,暂时未发现问题。
第九天的问题1,4都是由于之前多次添加监听者,多次收到回调,然后每次回调需要多次For循环,导致卡到了主线程。
解决第九天的问题2,礼物连发数字动画,之前一个开发者是每0.01s调用一次数字+1,如果连发999个礼物,那么就会循环999次,多个用户同时送,就会导致卡顿。
修改原来的方式,改为根据礼物连发数循环20-100次。
但是,同时连发1-2W个的时候还是会卡,需要继续排查问题
第十二天:
发现问题所在,当礼物连发数动画执行的时候,滑动消息面板的tableview时,连发动画就会停止,runloop冲突了。
这篇文章写的挺好的:https://www.jianshu.com/p/d260d18dd551
第十三天:
发现退出登录时会崩溃,加了僵尸,加了全局断点,就是一直崩在main,控制台也无任何输出。
最后发现崩溃的代码是
@implementation IMAConversationManager
- (void)dealloc{
// [[TIMManager sharedInstance] removeMessageListener:self]; //这么写会崩溃,不知道为什么
}
我也不清楚为什么,是因为self已经是nil了吗?那腾讯写的东西也不应该崩溃才对。
改到外面持有IMAConversationManager的类中,调用:
[[TIMManager sharedInstance] removeMessageListener:_conversationMgr];
_conversationMgr = nil;
解决了闪退问题。
第十四天:
IMSDKV1和移动直播SDKV1最高版本的更新在这个时候就已经告一段落了。初步测试已经结束,接下来就是交给测试工程师了,我接下来的任务就是继续更新IMSDKV2和移动直播V2
后续继续记录《记录更新腾讯IMSDK下(升级到V2最高版本)》
个人工作记录,不喜勿喷,若大神发现错误还望能指教一二,谢谢