在之前的一篇博客中,Allen 已经为大家介绍了 React Native 在 Glow 的应用以及大体架构。由于 React Native 库本身的一些原因,其在 Android 的成熟度远不及 iOS,因此也给在 Android 的应用带来了更多的挑战。
在本文中,给大家分享一下在 Android 平台上集成 React Native 的过程中碰到的一些问题和解决办法。
目前 React Native 的二进制库还不支持 64 位,而 Android 并不支持 32 位和 64 位二进制库的混合加载(详见 Mixing 32- and 64-bit Dependencies in Android )。 因此如果应用中已经包含了 64 位的二进制库,必须用
去掉 64 位二进制库。
- abiFilters
- ndk {
- abiFilters "armeabi",
- "mips",
- "armeabi-v7a",
- "x86"
- }
React Native 社区也在努力解决这一问题( React Native for Android is incompatible with 3rd-party 64-bit libraries ),目前看起来只有
这个依赖还没解决了,而且 PR 也已经有了,可以期待一下。
- android-jsc
React Native 带来的另一个问题就是 apk 文件变大,仅 32 位的支持大概就会使 APK 增大 8MB。对此比较敏感的话可以考虑使用多 apk 技术来解决,但因为会造成版本管理变得复杂,我们并未采用。
因为 x86 机型市场上比较少,我们曾经尝试过去掉对 x86 的支持,这样大概可以节省 4MB 的空间。但效果并不好,原因是 Play Store 似乎无法 100% 正确识别 x86 设备,造成在某些设备上下载了无法使用。也许这跟我们的应用是中途去掉了 x86 的支持有关,但无法验证,最后也只能放弃。
另外建议仔细阅读 Google 减小 APK 大小的建议 Reduce APK Size ,对减小 APK 尺寸也有不小的帮助。
对于 JS 内部的错误捕获,我们使用的是
+
- Sentry
的解决方案。但使用中发现 Android 系统上无法正确捕获 JS 堆栈记录,原因是 Raven-js cannot correctly parse android stacktrace 这个 bug。最后的解决方案是在打包脚本中给
- Raven-js
打一个补丁。
- Raven-js
另外发现的一个问题是 Android 上的堆栈记录在某些情况下会产生偏移,而且只在 minify 过的 JS 代码上出现。这个问题目前还没有得到解决,幸好大多数情况下都可以根据异常本身的信息来找出正确的错误代码。如果有读者了解这个问题,还望不吝赐教。
在最初使用的 React Native 0.42.3 中,发现
在 Android 上有一个很严重的问题:
- ListView
滚动结束后往往有一秒以上的时间内整个
- ListView
停止响应,期间不能响应任何的点击事件。
- ListView
花费大量时间调试后发现,
滚动过程中 React Native 的某个计算 layout 的函数占据了相当多的 CPU 时间。最后发现这也是 React Native 在 0.40.0 之后引入的一个 bug,React Native 做了过多的没有必要的 layout 计算,详见 Extreme lag after upgrade to 0.39.2 and 0.40.0 。
- ListView
通过升级 React Native 到 0.44.0,问题得到了解决,但相关 fix 也导致了另外一个 bug,这个在后面
一节会讲到。
- ViewPagerAndroid
集成 React Native 后的第一个版本出现了不少 crash,其中很大一部分的原因是内存不足。使用 Android Studio 自带的内存分析工具可以发现,在某些场景下有些图片占用了太多的内存(有的图片甚至可以达到 20M)。进一步分析确定了原因:图片没有经过尺寸调整。我们的应用允许用户自己上传图片,而一旦某些图片尺寸比较大(注意不是文件大小,而是图片的长和宽),经过解码后就会占用很大的内存。
解决方案有两点:
必须指定
- Image
,对于尺寸和显示大小差不多的图片(例如图标),使用
- resizeMethod
,对于可能超出显示尺寸很多的图片则一定要用
- scale
来减少内存开销(具体说明可以参考 React Native 的官方文档)。
- resize
为了防止以后的开发过程中遗漏
,我们定义了如下两个组件来代替原生的
- resizeMethod
组件。
- Image
- export
- function ResizeImage({...props
- }: Object) : ReactNative.ReactElement {
- return < ReactNative.Image resizeMethod = {
- 'resize'
- } {...props
- }
- />;
- }
- export function ScaleImage({...props}: Object): ReactNative.ReactElement {
- return <ReactNative.Image resizeMethod={'scale'} {...props} / > ;
- }
在刚才提到的 crash 中,另一部分是 React Native 自身引起的,而且用 Monkey Test 工具可以部分重现。通过在 React Native 加 log 调试可以发现,
会被多个线程访问,但没有做保护。简单的加入
- ShadowNodeRegistry
关键字可以修复很大一部分的 crash。
- synchronized
具体代码参见 Make ShadowNodeRegistry thread safe 。
通过这两个 fix,各个应用的 crash free rate 还是很好的得到的保持
在开发过程中发现的另一个问题是,给
动态添加页面后,新的页面不会显示。调试后发现这个问题实际上跟
- ViewPagerAndroid
的性能 fix 有关,性能优化用力过猛,导致
- ListView
应该进行的 layout 计算也被省略了。
- ViewPagerAndroid
比较详细的说明和示例代码都可以在 React Native v0.43 ViewPagerAndroid work not well when detached then attach 中找到。
为此我们的解决方案是将
绕开 layout 优化,代码可以参考 Fix ReactViewPager layouting 。
- ViewPagerAndroid
最后,如果有什么问题欢迎留言来信交流。
来源: http://www.tuicool.com/articles/eYFzYnj