一、前言
首先我们可以在官方文档里查到RN升级的文档Upgrading to new React Native versions
文中介绍了两种办法:
1.通过react-native-git-upgrade
因为这个方法是一键式升级,所以它会改变项目中的iOS
、Android
文件,由于我们的项目是混合型的,这样严重破坏了客户端的代码,会让解决冲突变得十分困难,不推荐。
2.通过修改package.json
中react-native
的版本号来升级
这个方案只牵涉到前端,破坏性小,还可以通过rn-diff来查看到升级的一些文件改变,通常react-native
的升级和react
的升级是绑定的,我们就可以通过rn-diff找到相应的版本号,接下来我们就用这种办法来进行升级。
二、踏坑
1.修改package.json
"react": "16.4.1",
"react-native": "0.56.0",
npm i
2.运行iOS的pod:update
发现pod.file
中为了兼容scrollView
的一段代码已无用,故删除。
3.执行react-native run-ios
错误信息:
Failing run on IOS and Android because a syntax error in `local-cli`
解决:
需要升级 node
,版本大于8.3
sudo npm cache clean -f && sudo npm install -g n install "n" && sudo n stable
4.启动后的红屏
错误信息1:
Unable to resolve module AccessibilityInfo from XXX
解决:
清除缓存
npm run reset
相当于
watchman watch-del-all && rm -rf node_modules && npm install && npm start --reset-cache
这里还需要提到一点,在修复过程中,经常发现改动了代码但没生效,这时候需要重启服务试试
npm start --reset-cache
错误信息2:
Using the export keyword between a decorator and a class is not allowed
解决:
将
@dec1
@dec2({
option1: "foo"
})
export class C {
}
改为
export
@dec1
@dec2({
option1: "foo"
})
class C {
}
错误信息3:
Cannot read property 'bindings' of null at Scope.moveBindingTo
错误信息4:
Property right of AssignmentExpression expected node to be of a type ["Expression"] but instead got null
解决:
3和4都是由于在0.56
版本,RN
需要使用babel7+
package.json
"dependencies": {
"react": "16.4.1",
"react-native": "0.56.0",
"@babel/core": "7.0.0-beta.47",
"@babel/plugin-proposal-decorators": "7.0.0-beta.47",
"@babel/plugin-transform-classes": "7.0.0-beta.47",
"@babel/register": "7.0.0-beta.47",
}
"devDependencies": {
"babel-jest": "23.4.0",
"babel-preset-react-native": "^5",
"jest": "23.4.1",
"react-test-renderer": "16.4.1"
}
.babelrc
{
"presets": ["react-native"],
"plugins": [
["@babel/plugin-proposal-decorators", { "legacy": true }]
]
}
5.第三方库错误
react-native-scrollable-tab-view
错误信息:
A trailing comma is not permitted after the rest element
解决:
由于此库已无人维护,所以把源码放到本地维护,去除错误提示代码中的几处逗号即可
react-native-modal
错误信息:
bundling failed: Error: We don't know what to do with this node type. We were previously a Statement but we can't fit in here?
解决:
升级库
"react-native-modal": "^6.5.0"
react-native-svg-uri
错误信息:
element type is invalid expected a string (for built-in components) or a class/function check
解决:
升级库
"react-native-svg": "^6.5.2",
"react-native-svg-uri": "^1.2.3"
react-native-root-siblings
错误信息:
Exporting local "_default", which is not declared.
解决:
由于此库近半年无人维护,所以把源码放到本地维护
export default class {
改为
export default class xxx {
6.RN内部组件的调整
Text/TextInput
错误信息:
Text.prototype.render undefined
解决:
Text.prototype.render
改为
Text.render
create-react-class
错误信息:
Module create-react-class does not exist in the Haste module map
解决:
由于把第三方库引入本地,代码老旧,新版已不支持create-react-class
的方式,所以逐个改造为es6的语法
7.Android上的修改
解决完上面的问题,在iOS
上就可以正常的跑起来了,但在Android
上build
都过不了。
想到客户端同学之前提到的一个坑:
//解决同一个库依赖不同的版本 例如react-native 有0.49.5 有的是+ 统一成0.49.5
subprojects {
project.configurations.all {
resolutionStrategy.eachDependency { details ->
if (details.requested.group == 'com.facebook.react'
&& details.requested.name.contains('react-native')) {
details.useVersion "0.49.5"
}
if (details.requested.group == 'com.airbnb.android'
&& details.requested.name.contains('lottie')) {
details.useVersion "2.5.0"
}
}
}
}
他们需要把依赖的库统一版本,于是把上述的0.49.5改为0.56.0
//解决同一个库依赖不同的版本 例如react-native 有0.56.0 有的是+ 统一成0.56.0
subprojects {
project.configurations.all {
resolutionStrategy.eachDependency { details ->
if (details.requested.group == 'com.facebook.react'
&& details.requested.name.contains('react-native')) {
details.useVersion "0.56.0"
}
if (details.requested.group == 'com.airbnb.android'
&& details.requested.name.contains('lottie')) {
details.useVersion "2.5.0"
}
}
}
}
重新build
,成功了,但启动后马上Crash
,打开AndroidStudio
发现有错误信息:
解决:将这些项目
android
文件下的 ***.iml
文件删掉,重新编译错误信息没有了,但启动依旧
Crash
,这时候和客户端同学沟通可能是so库
的问题,于是替换了so库
(这里有一个小技巧,要获得一个新版本的so库
,可以通过创建一个新版本的Demo
,然后从中获取),依旧出错,但错误信息变了:
java.lang.NoClassDefFoundError: Failed resolution of: Lcom/facebook/common/soloader/SoLoaderShim;
通过Google大致猜测是gif库
出了问题
//fresco
compile "com.facebook.fresco:animated-gif:$rootProject.ext.frescoVersion"
compile "com.facebook.fresco:fresco:$rootProject.ext.frescoVersion"
在官网的升级日志中查到
Update Fresco to v1.9.0, okhttp3 to v3.10.0
于是把版本改为1.9.0
,重新编译运行,一切正常。
8.Android Jenkins 打包失败
错误信息:
解决:
这个问题相当奇葩,几乎找不到思路,试过删除目录,再拉代码、拉库都无效,最后是在
react-native bundle
命令加中增加一个--reset-cache
参数,清除打包的缓存文件,终于可以了。
9.Android Code-Push错误
错误信息(issue):
facebook::react::Recoverable: Could not open file ReactNativeDevBundle.js: No such file or directory
解决:
暂时还未解决,code-push
的代码中可以看到一段注释说明解决代码的片段,但实际仍未解决,不过好在只出现在本地开发模式,这个还需继续跟进。
三、总结
1.看升级日志
升级前,建议看一遍官方的升级日志,这样可以对碰到的问题有预期和解决方向。
2.勤升级
有精力的话,建议更勤快的升级,这样每次升级带来的问题不会那么多,而且通过特定版本的升级日志通常就能定位问题。像这次跨多版本的升级,中间涉及的错误修复可能需要你仔细阅读多个版本的升级日志,困难度增大不少。
3.谨慎选择第三方库
对于第三方库,除了高star,还要注意它的更新频率。
如果在更新时碰到第三方库出错并很长时间都无人维护了,可通过下面几种办法解决:
- Fork一份,修改代码,自己发npm或者引用fork地址;
- 本地新建一个组件,利用继承的方式,修改源码,引用本地的新组件;
- 把GitHub上的代码直接放在本地维护。