RN - iOS端后台挂起后30s重启问题处理过程与心得

Posted iOSTianNan

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了RN - iOS端后台挂起后30s重启问题处理过程与心得相关的知识,希望对你有一定的参考价值。

RN版本 0.61.0
Xcdoe版本:13.3.1
Macos: 蒙特利

资料传送门

1.iOS后台运行的相关方案总结
2.iOS 后台挂起的一些坑
3.React Native iOS应用在后台状态下的相关问题
4.iOS App后台保活
5.iOS 后台永久保活,亲测有效
6.QiAppRunInBackground

现状与囧境

RN-ios端项目启动后, 频繁杀后台.基本上撑不过30s.并且毫无日志可以查看。
于此同时,由于上海疫情原因居家办公。手头仅有安卓手机,并无iOS测试手机(为了重新启用模拟器,把Macos系统升级到最高,Xcode升级到13.3.1,其中酸爽不再细表)。

在这里先说一下,iOS模拟器可以作为测试真机使用,在处理挂起的问题上与真机效果相同,不必担心(当然,这仅是一家之言。。。)

总结与原因

心急的小伙伴看这里就好
总结
1.setTimeout setInterVal代码,是否存在在挂起状态调用的情况,如有请终止,否则30s妥妥的

2.Animated.timing() Animated.loop() 代码调用的时候,是否存在在挂起状态调用的情况,如有请终止,否则30s妥妥的,会出现 rct.timing.gb.task 报错

3.react-native-snap-carousel 组件的使用要注意,autoplay=true在前台没有问题,如果在后台挂起,同样会造成 rct.timing.gb.task 报错,30s妥妥的。

4@react-native-community/netinfo 网络监听组件的问题 NetInfo.addEventListener()在后台挂起状态下,同样造成了 rct.timing.gb.task 报错,如果有请处理,起码做个前后台判断。我这边移除最省事儿。

5.GIF图片后台挂起无关,GIF图片不会影响

6.目前RN框架的iOS项目,至少在本项目中,不使用无声音频方式,只要解决以上问题,同样可以做到长时间保活,因此,无声音频方案并非必要(可用于配合排查问题)

看到这里本帖可以完结了。愿意看我心酸历程的可以继续看下去…

解决过程分享

一开始遇到该问题,确实毫无头绪,一时间各种猜想冒出来,也不确定处理的方向
是从性能角度出发还是因为代码层面的Bug

看到这种性能消耗,是不是第一时间就的怀疑是不是功耗太大,以至于被系统Kill,一度我也是从这种角度去尝试,奈何路子没走通,浪费了一些时间。
也尝试过移除RN的JSBundle资源,直接跑iOS原生项目,确实可以保活很久。所以一段时间里,在性能层面打转许久。。。

而且,真机以及模拟器如果只是看APP效果,那么连着xcode是一点也看不出被Kill的情况,所以为了确保验证效果准确,务必要将手机与Xcode断开验证
其次,xcode中一开始报错日志都是没有的,压根儿不知道从何下手。

所以,如果你看到这里,我推荐你不管三七二十一,先集成一下手机播放无(有)声音频,这样的好处是,一旦系统杀死了APP,你可以瞬间得知,最重要的好处是(我也是得益于此),有错误日志了!!!

就不详细贴音频的OC代码,其实在这里就有 6.QiAppRunInBackground
这边简单贴一下调用

#pragma mark - keepAlive
- (void)applicationWillEnterForeground:(UIApplication *)application 
    NSLog(@"%s:应用将进入前台WillEnterForeground", __FUNCTION__);
    if ([QiAudioPlayer sharedInstance].needRunInBackground) 
        [[QiAudioPlayer sharedInstance].player pause];
    
    [[UIApplication sharedApplication] endBackgroundTask: self.backgroundTaskIdentifier];


- (void)applicationDidEnterBackground:(UIApplication *)application 
    NSLog(@"%s:应用进入后台DidEnterBackground", __FUNCTION__);
    self.backgroundTaskIdentifier = [[UIApplication sharedApplication] beginBackgroundTaskWithName:kBgTaskName expirationHandler:^

       if ([QiAudioPlayer sharedInstance].needRunInBackground) 
           [[QiAudioPlayer sharedInstance].player play];
       
       if (self.backgroundTaskIdentifier != UIBackgroundTaskInvalid) 
           [[UIApplication sharedApplication] endBackgroundTask:self.backgroundTaskIdentifier];
           self.backgroundTaskIdentifier = UIBackgroundTaskInvalid;
       
    ];

音频播放的好处如上所述了,剩下的就是水磨工夫了,每个RN项目各不相同,就用排除法一个个定位即可。
顺便说一下
iOS12、iOS12以上,表现也不相同。
已经明确的是
目前iOS12系统, 基本可保活180s 、 iOS 以上系统,30s左右即被系统kill.
所以不用纠结iOS12系统的问题了。

一些报错与截图

1.<Error Domain=RBSAssertionErrorDomain Code=2 "Assertion's invalidation time is in the past" UserInfo=IgnoreOnReconnect=true, NSLocalizedFailureReason=Assertion's invalidation time is in the past>
造成该断言失败的原因,经过大量的排查和测试结果,定位在这样一段代码
会发现,这段代码调用,如果APP在前台的时候,那是没什么大问题,一旦进入后台setTimeout由于在RN层面,其实是调用的原生的代码处理,所以导致了iOS挂起后,出现如上断言报错。

2.Background Task 9 ("rct.timing.gb.task"), was created over 30 seconds ago. In applications running in the background, this creates a risk of termination. Remember to call UIApplication.endBackgroundTask(_:) for your task in a timely manner to avoid this.
这里的loop循环就是导致RN层面在后台挂起的元凶。。。。

这里也是,可以看到整理是做了个定时调用,这在APP处于前台没有问题,一旦iOS挂起到后台,那么就会引起30s重启。。。


排查笔记…

(无参考价值,仅供个人回顾查阅)

针对一部分处理, 大体思路还是通过iOS applicationDidEnterBackground
applicationWillEnterForeground
项RN发送消息的方式,让RN端监听状态来切换以上代码的处理
RN-iOS 原生向RN发送消息
不过貌似好像可以通过RN直接获取APP前后台挂起状态的API…

1.setTimeout循环打破
此处将 handler 在挂起时, cleanTimeout 即可

此处,增加状态拦截即可

2.Animated.loop()循环打破 :失败,只好移除
尝试过调用stop方法,但实际测试下来 动画是停止的,但是依然会造成闪退,这个待得空了 继续探索

3.setInterval处理 记得及时clean即可
只要及时 clearInterval 清除即可

4.autoPlay=true 问题处理,未做兼容,属性设置初始化不可更改,可采用两个组件实例切换的方案做兼容,此处直接改为禁止自动播放

5.NetInfo.fetch() 网络监听代码, 因为不需要. 所以没做兼容,直接此处移除

以上是关于RN - iOS端后台挂起后30s重启问题处理过程与心得的主要内容,如果未能解决你的问题,请参考以下文章

linux挂起后怎么唤醒

虚拟机挂起后无法恢复

RN - iOS - ScrollView联动滚动卡顿问题处理记录

RN - iOS - ScrollView联动滚动卡顿问题处理记录

每次挂起ubuntu虚拟机就会黑屏卡住,请问怎么解决?

ubuntu挂起后的程序运行?