一、前言
首先我們可以在官方文檔里查到RN升級的文檔Upgrading to new React Native versions
文中介紹了兩種辦法:
1.通過react-native-git-upgrade
因?yàn)檫@個(gè)方法是一鍵式升級,所以它會(huì)改變項(xiàng)目中的iOS
、Android
文件,由于我們的項(xiàng)目是混合型的,這樣嚴(yán)重破壞了客戶端的代碼,會(huì)讓解決沖突變得十分困難,不推薦。
2.通過修改package.json
中react-native
的版本號來升級
這個(gè)方案只牽涉到前端,破壞性小,還可以通過rn-diff來查看到升級的一些文件改變,通常react-native
的升級和react
的升級是綁定的,我們就可以通過rn-diff找到相應(yīng)的版本號,接下來我們就用這種辦法來進(jìn)行升級。
二、踏坑
1.修改package.json
"react": "16.4.1",
"react-native": "0.56.0",
npm i
2.運(yùn)行iOS的pod:update
發(fā)現(xiàn)pod.file
中為了兼容scrollView
的一段代碼已無用,故刪除。
3.執(zhí)行react-native run-ios
錯(cuò)誤信息:
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.啟動(dòng)后的紅屏
錯(cuò)誤信息1:
Unable to resolve module AccessibilityInfo from XXX
解決:
清除緩存
npm run reset
相當(dāng)于
watchman watch-del-all && rm -rf node_modules && npm install && npm start --reset-cache
這里還需要提到一點(diǎn),在修復(fù)過程中,經(jīng)常發(fā)現(xiàn)改動(dòng)了代碼但沒生效,這時(shí)候需要重啟服務(wù)試試
npm start --reset-cache
錯(cuò)誤信息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 {
}
錯(cuò)誤信息3:
Cannot read property 'bindings' of null at Scope.moveBindingTo
錯(cuò)誤信息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.第三方庫錯(cuò)誤
react-native-scrollable-tab-view
錯(cuò)誤信息:
A trailing comma is not permitted after the rest element
解決:
由于此庫已無人維護(hù),所以把源碼放到本地維護(hù),去除錯(cuò)誤提示代碼中的幾處逗號即可
react-native-modal
錯(cuò)誤信息:
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
錯(cuò)誤信息:
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
錯(cuò)誤信息:
Exporting local "_default", which is not declared.
解決:
由于此庫近半年無人維護(hù),所以把源碼放到本地維護(hù)
export default class {
改為
export default class xxx {
6.RN內(nèi)部組件的調(diào)整
Text/TextInput
錯(cuò)誤信息:
Text.prototype.render undefined
解決:
Text.prototype.render
改為
Text.render
create-react-class
錯(cuò)誤信息:
Module create-react-class does not exist in the Haste module map
解決:
由于把第三方庫引入本地,代碼老舊,新版已不支持create-react-class
的方式,所以逐個(gè)改造為es6的語法
7.Android上的修改
解決完上面的問題,在iOS
上就可以正常的跑起來了,但在Android
上build
都過不了。
想到客戶端同學(xué)之前提到的一個(gè)坑:
//解決同一個(gè)庫依賴不同的版本 例如react-native 有0.49.5 有的是+ 統(tǒng)一成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"
}
}
}
}
他們需要把依賴的庫統(tǒng)一版本,于是把上述的0.49.5改為0.56.0
//解決同一個(gè)庫依賴不同的版本 例如react-native 有0.56.0 有的是+ 統(tǒng)一成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
,成功了,但啟動(dòng)后馬上Crash
,打開AndroidStudio
發(fā)現(xiàn)有錯(cuò)誤信息:
解決:將這些項(xiàng)目
android
文件下的 ***.iml
文件刪掉,重新編譯錯(cuò)誤信息沒有了,但啟動(dòng)依舊
Crash
,這時(shí)候和客戶端同學(xué)溝通可能是so庫
的問題,于是替換了so庫
(這里有一個(gè)小技巧,要獲得一個(gè)新版本的so庫
,可以通過創(chuàng)建一個(gè)新版本的Demo
,然后從中獲取),依舊出錯(cuò),但錯(cuò)誤信息變了:
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"
在官網(wǎng)的升級日志中查到
Update Fresco to v1.9.0, okhttp3 to v3.10.0
于是把版本改為1.9.0
,重新編譯運(yùn)行,一切正常。
8.Android Jenkins 打包失敗
錯(cuò)誤信息:
解決:
這個(gè)問題相當(dāng)奇葩,幾乎找不到思路,試過刪除目錄,再拉代碼、拉庫都無效,最后是在
react-native bundle
命令加中增加一個(gè)--reset-cache
參數(shù),清除打包的緩存文件,終于可以了。
9.Android Code-Push錯(cuò)誤
錯(cuò)誤信息(issue):
facebook::react::Recoverable: Could not open file ReactNativeDevBundle.js: No such file or directory
解決:
暫時(shí)還未解決,code-push
的代碼中可以看到一段注釋說明解決代碼的片段,但實(shí)際仍未解決,不過好在只出現(xiàn)在本地開發(fā)模式,這個(gè)還需繼續(xù)跟進(jìn)。
三、總結(jié)
1.看升級日志
升級前,建議看一遍官方的升級日志,這樣可以對碰到的問題有預(yù)期和解決方向。
2.勤升級
有精力的話,建議更勤快的升級,這樣每次升級帶來的問題不會(huì)那么多,而且通過特定版本的升級日志通常就能定位問題。像這次跨多版本的升級,中間涉及的錯(cuò)誤修復(fù)可能需要你仔細(xì)閱讀多個(gè)版本的升級日志,困難度增大不少。
3.謹(jǐn)慎選擇第三方庫
對于第三方庫,除了高star,還要注意它的更新頻率。
如果在更新時(shí)碰到第三方庫出錯(cuò)并很長時(shí)間都無人維護(hù)了,可通過下面幾種辦法解決:
- Fork一份,修改代碼,自己發(fā)npm或者引用fork地址;
- 本地新建一個(gè)組件,利用繼承的方式,修改源碼,引用本地的新組件;
- 把GitHub上的代碼直接放在本地維護(hù)。