白屏出现
某日,测试同学和产品同学在回归版本功能的时候,突然发现在页面在返回时,Navigation的根视图突然白屏了,很是惊讶,也无法刷新使页面恢复,只能杀掉进程重新打开APP来解决。很快bug就来到了开发同学这里了
白屏调试
资源文件加载失败?
一开始调试时,发现在反复打开了3个不同的webview并关闭后,再次打开某一个特定的webview就会出现白屏,怀疑是RNCWebView
组件使用的WKWebView
进程崩溃(webViewWebContentProcessDidTerminate)引起的白屏,但打上断点调试了半天也没能复现(很是坑爹,饶了一个大圈子),最后发现似乎是跟H5那边加载到的静态资源有点关系。在didFinishNavigation
打上断点,把html body输出出来看到了正常和非正常情况下的两个不同内容:
可以看到正常页面body内容是有layaContainer存在的canvas的,但白屏时body就只有index.js了,怀疑跟index.js加载失败或者是index.js里面加载的文件失败进而导致canvas丢失的问题;然后问题就交给了H5同学去处理了,最后过了不到20分钟,H5同学告知此页面资源文件由于是非HTTPS的,导致有时加载失败,改成HTTPS就好了,我试了一下也确实如此。吐了一口血….
react-native-screens回收了?
由于项目中使用了导航控制器,在RN中常见的导航控制器做法有两种,一种是依赖原生的UINavigationController提供的功能,而另外一种是react-navigation
,其原理是通过router来管理导航状态,派发Action来获得新的State从而维护和管理导航状态。而为了节省内存项目中引入了react-native-screens
,在导航push过多的时候会将前面的页面回收,页面返回时会将State恢复。但注释下来调试了也还是会出现白屏现象。
webview content高度变化了?
接着开始怀疑conteng 高度变化导致webview没有高度,从而看起来页面是白的,但调试下来并不是如此
就是它[webViewWebContentProcessDidTerminate:]
最后,在连续打开了N多页面,并在页面中玩了N多游戏看了N多广告,终于进入断点了,果然就是它。
解决问题
问题很好解决,在监听到WKWebView进程崩溃时,调用reload刷新页面即可
const onContentProcessDidTerminate = useCallback(res => {
if (isIOS) {
if (webViewRef.current) {
webViewRef.current.reload();
}
const { nativeEvent } = res;
logger.warn('wkwebview进程崩溃', 'wkwebview:contentProcessTerminate', {
url: nativeEvent.url,
title: nativeEvent.title,
});
}
}, []);
线上跟踪
RN的代码通过CodePush发布到了生产环境,在跟踪白屏问题时,发现一天(相对)就有将近2万个白屏日志, 白屏的问题还是挺多的,难不成是js的内存泄露,或者是WKWebView的内存泄露造成的?
RNCWebView的循环引用
在RNCWebView.m
的dealloc方法打上断点,然后navigation页面在back时,发现dealloc并没有执行,吃了一惊;难不成是使用的姿势不对?于是翻了一下源码发现了WKWebViewConfiguration
,因为之前在做项目时发现WKWebViewConfiguration
的userContentController
在addScriptMessageHandler
会对handler产生强引用产生循环引用导致内存无法释放,但看了一眼他的源码并无特殊处理,于是加了一个中间者来处理delegate,再次调试,dealloc方法执行了!!! 问题迎刃而解
github提交PR
问题验证通过,于是就给react-native-webview
提交了一个PR
Fix iOS WKWebView retain cycle
目前已经合并到了8.0.2版本中,等版本发布后再持续跟踪一下白屏,看白屏现象是否能够降低
本文首次发布于 孙忠良 Blog, 作者 [@sunzhongliang] , 转载请保留原文链接.