近段时间在研究react native(以下简称rn),Facebook的确是有心了,出来了一个这么好的东西,感觉自己能够多渠道的开发iOS(甚至整个移动端和前端),想想还是很开心的。好了,废话不多说,谈谈自己在当时遇到白屏以及内存一直上涨的问题上开始研究rn的拆分包技术吧,后来才知道是架构之路!!
我们是原生项目里面接入rn技术,替换一些原先由H5实现的业务,从而大大提高用户体验,对,大大的提高!
刚开始写的时候,一目了然用的是
这样的初始化方式,当时也是因为业务比较多,上头又催促的比较紧,也没有细细看。
然后一直以来以为只有android会出现白屏的问题,然后就没有在意这块,后来发现iOS也会有,这种体验是不允许的。所以当务之急是怎样去掉这个白屏!然后踩坑之路开始了。。。
非常惊喜,偶然的一次机会在运行xcode看内存、cpu、电量等问题的时候又发现这种初始化方式只要点开一个rn业务内存就会上涨且不会消亡,真是祸不单行。
一、网上有方案是通过一个闪屏页作为过渡,这种方式虽然可以但不是很理想,每次进入一个rn的业务就会出现这么一个过渡页面是怎么回事,后来想想果断放弃。
二、拆分包之路开始了!查看RCTRootView的初始化方法,原来他的初始化方法还有一个
然后发现原来之前的这种也是需要这个bridge对象,且每次都会创建,内存只会上涨的“元凶”找到了,然后自然而然的想到bridge对象的单例模式,这时候问题又来了
因为需要RCTBridge对象,看看他的初始化方式
1)之前我先用的第一种initWithDelegate方式,但是结合他的代理方法- (NSURL*)sourceURLForBridge:(RCTBridge*)bridge;使用RCTBundleURLProvider把本地文件进行初始化
但是只能有一个路径啊,而且经过测试,用各种方式在之前传入不一样的路径完全没有效果,编译器只会使用第一次的路径,所以造成不同的业务打开的还是第一次的业务,坑......
总结:这种形式的只能适用于rn业务只有一个入口,然后这边可以给一个总root的路径,然后在传入rn里面的对象中加入你要进入的业务title。 实现:解决白屏,解决内存,提高用户体验!
2)那么就使用RCTBridge的第二个初始化的方式吧,传入initWithBundleURL,这点就符合js的动态注入的特性了,因为这个地方传入的url是公共bundle包路径,后面通过enqueueApplicationScript或者是executeApplicationScript传入业务包的路径实现
总结:这里讲到的就是后面研究的拆分包方案,大体的思路就是每个业务的jsbundle里面都有一些系统的三方的库,所以是没有必要打进每个包里面,造成重复的现象,所以按照架构的方案肯定是把公共的拿出来,进行预加载,而且恰恰是这个预加载的时机就可以把白屏的时机过滤掉,之前我们想的bridge亦可以弄成单例,每个包的大小亦可以减少,对以后实现热更新有百利而无一害!
所以实现的思路就是新建一个manager类,单例一个bridge,通过initWithBundleURL传入公共包的路径实现预加载,锦上添花的可以加一个内存缓存,毕竟好的方案都是先检查缓存,没有加载到才加载业务包。
虽然思路和架构想的很清楚,但是实施起来还是很困难!
2.1).最早看到的文章用的是rnpackager bundle或者是携程出来的方案都是比较老的分包工具,用起来各种报错,针对现在的版本感觉不是很实用。
2.2).diff方案,这种方案就是我们新建一个js文件,然后里面只放入系统库的代码,diff-patch会帮助我们检查不同点从而得到patch包,不知道我使用的是否不对,拿到的.patch文件比原先的jsbundle文件还要大,而且这种方式费时费力,电脑配置不行的可能都无法成功,这里推荐一个链接吧,可用于检查差异,有兴趣的简友可以尝试一下哈
https://neil.fraser.name/software/diff_match_patch/svn/trunk/demos/demo_patch.html
2.3).讲到最重要的了,就是现在Facebook大佬推出的metro bundle,这是目前最好的分包拆包方案,跟随官网总没有错。然后根据网上大牛的方法开始做https://github.com/smallnew/react-native-multibundler,最后的确是成功了,但是存在两个问题,第一个是第三方的库必须加到基础包里面,第二个问题也是图片必须加到基础包里面,根据我们现在热更新的方案,只能每次上传业务包,所以最后只能导致这种方案也不能实施。感觉我提到的两个问题需要修改源代码,但是对于小白来说有点超纲了啊,看看以后有没有机会结束这篇文章,也希望大牛可以指点一二。
这是我遇到问题到拆包分包的历程,虽然到最后结果差强人意,但是这种探索之路还是难能可贵的(对了,那个内存的问题可以在dealloc方法之中执行 [self.bridge invalidate];就可以解决了)