知识点:
- 适配 iPhone X
- 添加额外的线程
- 缓存
- 关于 Alert、Modal
- 样式
- 自定义组件
适配 iPhone X
RN 版本 0.52 之后提供了适配 iPhone X 的组件 SafeView,不过单独这个是不行的,还需要在 iOS 中修改配置,把视图从一个短小的区域拉伸到全屏的大小。
这里通过修改设置打开默认的安全区域。
由于之前使用的还是旧版的 RN,这里为了兼容旧的版本做了一个 JS 的判断,通过判断高度是否符合 812 来判断是否 iPhone X。同时有一个小小的缓存,不需要每次都重复判断,这里的 1.0.6 是开始使用新能力的版本号。
添加额外的线程
有些功能其实没必要跑在 UI 线程上,这些东西如果放在组件里反而不是那么融洽,甚至有时候会对正常的逻辑产生影响。
可以使用下面的方式注册一下额外的层,这个不显示 UI,但是可以用来更新一些缓存,返回远程数据等。
AppRegistry.registerRunnable('RunableTask', TaskRun)
AppRegistry.runApplication('RunableTask', {});
在线上产品中就是利用了这一个层做了一些额外的事情,这里我使用事件触发的形式来做正常组件和这一个层的通知。
需要小心一点,如果在这一层做了定时器、循环事件等操作,记得要取消掉,不然事件就会变成两次。
缓存
App 还是需要缓存的,这里可以缓存一些上次打开的数据,比如广告、用户信息等。
在打开 App 的时候可以先用这些数据走正常的流程,然后再用一个异步的任务去鉴定、更新这些数据。这样下来可以让 App 打开非常流畅,同时用户也不会发现数据变化大等异常,这些同时也是需要后端接口数据支持的。
关于 Alert、Modal
正常情况下 Alert、Modal 是独立于当前组件 View 之上的,如果这个时候遇到意外情况,比如组件销毁、暂停等情况下 Alert 还未销毁,这个时候就会发生比较严重的错误。
Alert 大多数会报错,App 闪退。
Modal 部分会报错、部分会暂停、失去事件等操作,导致 App 一直停留在 Modal 视图上,用户也不能操作任何东西,时间长了系统就会判断 App 未响应等等。
如果你不想处理这些东西,可以考虑使用一个自定义的 Alert 或者内嵌在组件中的 View 来代替 Modal。
样式
最好能将部分样式抽取出来,变成一个公共的样式库,这样的话 App 启动之后就会缓存这部分样式,同时也非常容易将已经有的部分样式替换掉。
这些可以参考开源的 RN 组件库等。
自定义组件
在 App 中其实有些属性是要经常用到的,比如 Text 组件的禁止使用系统字体大小、Image 的缩放方式等,这些组件在平常使用过程中会经常重复添加各种属性,可以将这些组件独立出来,并且使用更加语义化的属性名来代替 RN 提供的使用方式。
在这个的基础上还可以将按钮、卡片等组件进一步抽象出来,对于不使用第三方开源组件的项目来说还是很有必要的。
解决遇到的问题
使用 RN 开发会遇到很多问题,这些问题都可以在 RN 的 Issues 中找到答案,如果还没有就到 Google 搜一下。
有些问题需要修改 RN 的代码,不要怕麻烦,如果是 JS 部分的修改,直接将下载的包修改成可上传的包就行了。这里记得上传到私有 npm 库中,如果是 Native 的问题最好是在自己的 Native 代码中覆盖掉旧的代码,毕竟前端去编译 RN 的源代码还是有很大的风险的。
不要去百度,百度真的没有答案。
按钮
RN 提供的按钮其实很丑,正常开发的时候大家都是使用自定义的按钮。
使用这种模式做出来的按钮非常漂亮,也更能符合设计的结果,不过使用的时候尽量不要给按钮本身加样式,有样式尽量添加到内部的 View 等组件上。
向下兼容
RN 使用的过程中我们升级了一个大的版本,从 0.40 系列升级到了 0.50 系列,由于大部分手机用户还存在不愿意升级 App 的情况,向下兼容成了唯一的选择。
我使用的策略是修改源代码……
比如升级 0.53 的时候发现有些 Native 组件名变了,原来使用的是 RCTMultilineTextInputView,现在变成了 RCTTextView,不管 RN 出于什么理由改变了这个组件名字,造成的结果就是现在的旧代码不能跑在新的 App 壳下。
我们可以打印出 NativeModules 的 UIManager 对象看看。
而兼容也是从这里开始做的,我们判断一下当前的 RN 是否在 UIManager 中提供了对应的原生组件即可判断当前的环境是否正确的环境。
比如要升级到 53,修改 53 的源代码 react-native/Libraries/Components/TextInput/TextInput.js。
//安卓的没变化,要排除
if (Platform.OS === 'android') {
var AndroidTextInput = requireNativeComponent('AndroidTextInput', null);
} else if (Platform.OS === 'ios') {
//如果支持RCTTextView,既新APP
if(UIManager.RCTTextView){
var RCTMultilineTextInputView = requireNativeComponent('RCTTextView', null);
var RCTSinglelineTextInputView = requireNativeComponent('RCTTextField', null);
}else{
//其他情况
var RCTMultilineTextInputView = requireNativeComponent('RCTMultilineTextInputView', null);
var RCTSinglelineTextInputView = requireNativeComponent('RCTSinglelineTextInputView', null);
}
}
使用类似这样的手段就能区别两种 App 壳的环境,用户在使用的时候也不至于要必须升级 App 才能使用新版 App 的功能了。
使用 RN 开发 App 确实非常快,但是各位在开发中还是不要忘记钻研 RN 的源代码,很多解决方案其实很简单,有些时候可能只是由于低版本的 APP 不支持而导致的。
如果你想对 RN 有一个进一步的了解,还需要对原生的代码也有一定的了解,当然正常情况下还是有位这方面的同事一起开发比较好。