前言
React Native 作為一款跨端框架,有一個(gè)最讓人頭疼的問題,那就是版本更新。尤其是遇到大版本更新,JavaScript、iOS 和 Android 三端的配置構(gòu)建文件都有非常大的變動(dòng),有時(shí)候三者的配置文件又互相耦合在一起,往往牽一發(fā)而動(dòng)全身。
本文假定 React Native 升級(jí)的主導(dǎo)者是前端同學(xué),比較熟悉 javaScript 為主的一套前端構(gòu)建流程。如果有條件,升級(jí)時(shí)強(qiáng)烈建議拉上 iOS 和 Android 開發(fā),對(duì)于一些瑣碎的升級(jí)細(xì)節(jié),當(dāng)面溝通遠(yuǎn)比搜索引擎高效。
提示:因?yàn)槊看涡薷暮托略鰞?nèi)容都會(huì)隱藏文章重新審核,建議閱讀博客原文獲得最佳閱讀體驗(yàn)
?? 閱讀博客原文
覺得文章對(duì)你有用的話一定要記得點(diǎn)贊哦 ??,謝謝你,這對(duì)我來說真的很重要!
<br />
一、磨刀不誤砍柴工
這部分知識(shí)我認(rèn)為是最重要的,畢竟版本更新是永恒的,操作流程卻是不變的。
詳細(xì)介紹各端構(gòu)建工具前,我們拋開各種技術(shù)細(xì)節(jié),從整個(gè)項(xiàng)目的生命周期出發(fā),看看大部分產(chǎn)品是怎么做技術(shù)規(guī)劃的:
- 產(chǎn)品早期:架構(gòu)都比較簡(jiǎn)單,整個(gè)項(xiàng)目拿個(gè)配置文件做配置就好了,配置文件越簡(jiǎn)單越好,xml、json 就被拿出來用了
- 產(chǎn)品發(fā)展期:需要配置的地方變多了,這時(shí)候多加幾個(gè)配置項(xiàng)多加幾個(gè)參數(shù),雖然有些繁瑣,但靜態(tài)的配置文件還夠用
- 產(chǎn)品成熟期:人員擴(kuò)增代碼膨脹,靜態(tài)的配置文件完全不夠用了,為了達(dá)到動(dòng)態(tài)配置的目的,往往會(huì)引入一門腳本語言或自創(chuàng)一套 DSL 來管理相關(guān)配置
產(chǎn)品晚期:一把火燒了另起爐灶(記得刪掉)
理清一個(gè)技術(shù)產(chǎn)品的生命周期后,你就會(huì)對(duì)日常開發(fā)中配置文件有了整體的認(rèn)知:那些又臭又長(zhǎng)的配置項(xiàng),亂七八糟的兼容寫法,毫無美感的 DSL,最神奇的是這些七拼八湊的東西還能把項(xiàng)目跑起來,Build 成功的那一刻你一定會(huì)對(duì)這種人類奇跡發(fā)出由衷的敬佩之情——原來這就叫專業(yè)啊!
收一收澎湃的情緒,牢記上面的指導(dǎo)經(jīng)驗(yàn),我們下面開始討論技術(shù)細(xì)節(jié)。
<br />
1.【W(wǎng)eb 前端】項(xiàng)目配置
前端工程化一直是前端里面的熱點(diǎn),雖然一直很熱,但是具體實(shí)現(xiàn)還是一團(tuán)糟。個(gè)人認(rèn)為原因主要有兩點(diǎn),一個(gè)是前端構(gòu)建從無到有,相對(duì)而言基礎(chǔ)薄弱;一個(gè)是社區(qū)推動(dòng),百花齊放的同時(shí)又沒有統(tǒng)一標(biāo)準(zhǔn)。就拿現(xiàn)在前端的主要配置文件來說:
- 用
package.json管理 npm 包 - 用 npm script 實(shí)現(xiàn)流程管理,有時(shí)候還要把相關(guān)腳本塞到
package.json里 - 用 eslint 進(jìn)行編碼規(guī)范,有時(shí)候還要寫個(gè)
.eslintrc.js - 用 babel 處理語法兼容,有時(shí)候還要寫個(gè)
babel.config.js - 用 webpack 進(jìn)行項(xiàng)目構(gòu)建和打包發(fā)布
- ......
上面只是列出了幾個(gè)主流配置,不出意外的話,現(xiàn)在你的項(xiàng)目里已經(jīng)有 5 個(gè)配置文件了,在 JavaScript 這個(gè)前端萬能腳本語言的粘合下,這些配置文件還可以互相引用互相耦合,復(fù)雜度搞成這樣,開發(fā)體驗(yàn)還沒有 iOS Android 的一半好。
如果你認(rèn)為我只是單純的批評(píng)前端那你就理解錯(cuò)了,我想表達(dá)的是,這么復(fù)雜的配置都能搞定,iOS Android 的項(xiàng)目配置還不是手到擒來?
<br />
2.【iOS】項(xiàng)目配置
iOS 項(xiàng)目主要有兩個(gè)點(diǎn):project.pbxproj 和 CocoaPods。這兩塊兒的知識(shí)了解后,升級(jí) RN 就完全不虛了。
1?? project.pbxproj 與 Xcode
project.pbxproj 就是一個(gè) iOS 項(xiàng)目的配置文件,從數(shù)據(jù)結(jié)構(gòu)特點(diǎn)上有些像 JSON,年齡可以追溯到 NeXT,可讀性基本為 0,每次 git 合并都是純黑的噩夢(mèng)。不信你瞅瞅下圖,這是給人看的嗎。

可讀性這么差的東西能傳下來,其實(shí)全靠 XCode 這個(gè) IDE 給它續(xù)命。我們每次在 XCode 里修改的配置,例如 Build Settings 等選項(xiàng),最后都會(huì)反映到 project.pbxproj 這個(gè)配置文件上,也算是一種另類 DSL 了。
project.pbxproj 相關(guān)的知識(shí)我推薦下面幾篇文章,閱讀后會(huì)讓你對(duì) iOS 編譯打包流程有個(gè)更深的了解:
iOS 開發(fā) xcode 中的 project.pbxproj -- 深入剖析:介紹了
project.pbxproj文件的一些特點(diǎn)Xcode 工程文件 project.pbxproj 小結(jié):看完后會(huì)對(duì) XCode 配置和
project.pbxproj文件的對(duì)應(yīng)關(guān)系有著更深刻的了解Xcode - Target , PROJECT 區(qū)別:介紹了 Xcode 中各個(gè)配置項(xiàng)是什么意思
2?? CocoaPods
CocoaPods 是一個(gè)負(fù)責(zé)管理 iOS 項(xiàng)目中第三方開源庫的工具,目前主流 iOS 工程都是用 CocoaPods 管理第三方庫的。
React Native 在 0.60 里終于用上了 CocoaPods,和 iOS 社區(qū)步調(diào)一致了起來。這樣做的好處就是后續(xù)維護(hù)和迭代的壓力會(huì)小很多,鬼知道我以前升級(jí)各種 iOS SDK 的日子是怎么熬過來的。
相對(duì) project.pbxproj,CocoaPods 無疑簡(jiǎn)單了不少,寫配置腳本的 Ruby 語言也比較清爽,Podfile 的可讀性要高很多。
platform :ios, '9.0'
require_relative '../node_modules/@react-native-community/cli-platform-ios/native_modules'
target '項(xiàng)目名稱' do
pod 'React', :path => '../node_modules/react-native/'
pod 'React-Core', :path => '../node_modules/react-native/React'
use_native_modules!
end
CocoaPods 的學(xué)習(xí)資料可以參考下文,不夠的話自行搜索即可:
<br />
3.【Android】項(xiàng)目配置
Android 的項(xiàng)目配置主要是由 gradle 文件控制的,gradle 文件又由 Groovy 這門 JVM 系的腳本語言書寫。到這里思路就很明顯了,我們只要了解一些 Groovy 的語法和 gradle 的寫法,就能讀懂和修改 Android 的配置文件了。在這里我推薦一些相關(guān)教程,讀完后就會(huì)有個(gè)大致的了解:
學(xué)習(xí)了基礎(chǔ)的語法后,再回到 Android 工程上來。Android 的項(xiàng)目配置主要由 3 個(gè)文件控制,升級(jí)時(shí)沖突較多的也是這 3 個(gè)文件:
-
settings.gradle:用來指示 Gradle 在構(gòu)建應(yīng)用時(shí)應(yīng)將哪些模塊包含在內(nèi) -
build.gradle:定義適用于項(xiàng)目中所有模塊的構(gòu)建配置 -
app/build.gradle:定義 App 的構(gòu)建配置
個(gè)人認(rèn)為 Android 的 Gradle 配置還是比較容易入門的,因?yàn)?gradle 文件有個(gè)好處,可以隨意的添加注釋。大家可以花點(diǎn)兒時(shí)間把每個(gè)配置項(xiàng)都加上注釋,這樣在升級(jí)改動(dòng)過程中就不容易發(fā)怵。
<br />
4.RN 官方升級(jí)助手
React Native 官方在 2019 年 7 月 0.60 大版本更新時(shí),推出了 Upgrade Helper 這個(gè) Diff 小工具。通過這個(gè)工具我們可以方便的看出版本更新時(shí)各個(gè)配置腳本的改動(dòng),非常的方便。

<br />
二、升級(jí)流程
RN 版本升級(jí)時(shí),我的升級(jí)流程一般是這樣的:
- 通暢的網(wǎng)絡(luò)環(huán)境,可以自由訪問 Google 那種
- 查看官方博客,獲取版本更新的主要內(nèi)容
- 閱讀 RN GitHub 上的 CHANGELOG,獲取版本更新的具體改動(dòng),適配 API 變更
- 閱讀第三方依賴的
README.md文件,是否需要同步升級(jí) - 使用 Upgrade Helper 做版本 Diff,并閱讀 upgrading-react-native 的相關(guān)博文,修改項(xiàng)目配置文件與配置腳本
- 刪除 node_modules 與緩存,重新 Build 項(xiàng)目,如果 Build 失敗,根據(jù)報(bào)錯(cuò)信息搜索 or 詢問 Native 開發(fā)同學(xué)
- 回歸測(cè)試
在更新過程中,個(gè)人建議 git commit 操作要盡量原子化,方便后續(xù)復(fù)盤和回滾,小心駛得萬年船。
在我實(shí)際升級(jí)中,因?yàn)?React Native 0.59 到 0.60 有非常大的變動(dòng),并且業(yè)務(wù)較為復(fù)雜,升級(jí) 0.60 花了兩個(gè)星期的時(shí)間:iOS 一周,Android 一周;0.61 和 0.62 的升級(jí)就比較簡(jiǎn)單了,大概一兩個(gè)小時(shí)就可以升級(jí)好。
<br />
三、React Native 0.60 升級(jí)
2019 年 7 月 3 日 Facebook 官方發(fā)布了 React Native 0.60,這是一次非常大的版本更新,雖然沒有添加新的功能,但是在底層上做了很多優(yōu)化,向主流配置靠齊:
- 移除 WebView 等組件交給 react-native-community 社區(qū)維護(hù)
- 利用 CocoaPods 管理 iOS 的第三方依賴,向 iOS 主流配置靠齊
- Android 遷移到 AndroidX,方便后續(xù)的升級(jí)與更新
- React Native 的一些第三方包會(huì)自動(dòng)鏈接,不再需要手動(dòng)使用
react-native link *了
0.60 升級(jí)時(shí)一定要有耐心,不可能一次性成功的,建議參考 Upgrade Helper 和 Upgrade to React Native 0.60 這篇博文,我會(huì)對(duì)文中沒有說明的地方進(jìn)行補(bǔ)充。
升級(jí)前先確保相關(guān)第三方包已經(jīng)是最新版本。
<br />
1.React Native
JavaScript 這里相對(duì)來說好升級(jí)一些,畢竟是前端程序員的主場(chǎng)。根據(jù) Diff 差異升級(jí)版本號(hào)后,還需要注意以下幾點(diǎn):
1?? 部分 RN 內(nèi)置組件交給社區(qū)維護(hù)
NetInfo、WebView 和 Geolocation 從 React Native 中移除,交給 react-native-community 社區(qū)維護(hù)。所以我們需要修改 import 時(shí)的路徑。
Slider、AsyncStorage、CameraRoll、Clipboard 等組件也有移除計(jì)劃,這次升級(jí)也可以順便遷移一下。
值得注意的是,react-native-webview 在一次更新中為了響應(yīng) App Store 政策,已經(jīng)移除了 UIWebView,只支持 WKWebView。如果你做過移動(dòng)端的適配,你肯定明白 WKWebview 對(duì) cookie 支持不太友好,這里需要重點(diǎn)回歸測(cè)試一下;另外一點(diǎn)是如果 RN 和 H5 網(wǎng)頁是通過 postMessage 的方式交互,相關(guān) API 也有一些不兼容更新,這里需要重點(diǎn)適配一下,具體細(xì)節(jié)可以看文檔。
2?? SwipeableFlatList 移除
SwipeableFlatList 是 React Native 在 0.5X 某個(gè)版本提供的側(cè)滑刪除列表組件,雖然一直沒有官方文檔中放出來,但是社區(qū)上已經(jīng)有很多人在使用了。可能對(duì)這個(gè)組件的實(shí)現(xiàn)不太滿意,官方在 0.60 里刪除了這個(gè)組件。為了不讓項(xiàng)目報(bào)錯(cuò),我們可能需要把 SwipeableFlatList 相關(guān)的源碼拿出來自己手動(dòng)維護(hù)一下,有人把相關(guān)代碼提出來維護(hù)了一個(gè) npm 包——react-native-swipeable-lists,大家可以引入暫時(shí)過度一下。
<br />
2.iOS
0.60 版本的 React Native 支持 CocoaPods,2020 年了,RN 終于支持 CocoaPods 了,沒有 CocoaPods 的時(shí)代,為了使用一些 iOS 第三方庫,我們必須手動(dòng)把庫文件拖到主工程里,升級(jí)和維護(hù)非常不方便。因?yàn)?0.61 版本 CocoaPods 是唯一可選包管理方案,所以強(qiáng)烈建議直接升級(jí)使用。
1?? 遷移到 CocoaPods & Autolinking 支持
遷移 CocoaPods 前,先在 CLI 里輸入一下命令 unlink Native Modules:
react-native unlink
unlink 后就要遷移到 CocoaPods 了。遷移前確保 Ruby 和 CocoaPods 已經(jīng)安裝成功,具體的安裝過程不是本文重點(diǎn)就不展開了,沒有安裝的同學(xué)自行 Google 搜索。
我們?cè)?ios 目錄里新建一個(gè)文件 Podfile,在里面輸入以下代碼:
platform :ios, '9.0'
require_relative '../node_modules/@react-native-community/cli-platform-ios/native_modules'
target '項(xiàng)目名稱' do
pod 'React', :path => '../node_modules/react-native/'
pod 'React-Core', :path => '../node_modules/react-native/React'
pod 'React-DevSupport', :path => '../node_modules/react-native/React'
pod 'React-RCTActionSheet', :path => '../node_modules/react-native/Libraries/ActionSheetIOS'
pod 'React-RCTAnimation', :path => '../node_modules/react-native/Libraries/NativeAnimation'
pod 'React-RCTBlob', :path => '../node_modules/react-native/Libraries/Blob'
pod 'React-RCTImage', :path => '../node_modules/react-native/Libraries/Image'
pod 'React-RCTLinking', :path => '../node_modules/react-native/Libraries/LinkingIOS'
pod 'React-RCTNetwork', :path => '../node_modules/react-native/Libraries/Network'
pod 'React-RCTSettings', :path => '../node_modules/react-native/Libraries/Settings'
pod 'React-RCTText', :path => '../node_modules/react-native/Libraries/Text'
pod 'React-RCTVibration', :path => '../node_modules/react-native/Libraries/Vibration'
pod 'React-RCTWebSocket', :path => '../node_modules/react-native/Libraries/WebSocket'
pod 'React-cxxreact', :path => '../node_modules/react-native/ReactCommon/cxxreact'
pod 'React-jsi', :path => '../node_modules/react-native/ReactCommon/jsi'
pod 'React-jsiexecutor', :path => '../node_modules/react-native/ReactCommon/jsiexecutor'
pod 'React-jsinspector', :path => '../node_modules/react-native/ReactCommon/jsinspector'
pod 'yoga', :path => '../node_modules/react-native/ReactCommon/yoga'
pod 'DoubleConversion', :podspec => '../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec'
pod 'glog', :podspec => '../node_modules/react-native/third-party-podspecs/glog.podspec'
pod 'Folly', :podspec => '../node_modules/react-native/third-party-podspecs/Folly.podspec'
target '項(xiàng)目名稱Tests' do
inherit! :search_paths
# Pods for testing
end
use_native_modules!
end
上面這段代碼,pod 開頭的都是從 node_modules 目錄導(dǎo)入 react-native 相關(guān)的官方代碼。下面兩行代碼是實(shí)現(xiàn) autolink 的功能:
require_relative '../node_modules/@react-native-community/cli-platform-ios/native_modules'
target '項(xiàng)目名稱' do
...
use_native_modules!
end
Podfile 配置好后,就在 ios 文件夾下運(yùn)行 pod install,安裝相關(guān)依賴。
安裝成功后會(huì)生成一個(gè) xcworkspace 空間,這時(shí)候你需要退出當(dāng)前的 xcodeproj 項(xiàng)目,打開 xcworkspace。
在 xcworkspace 里,首先有兩個(gè)頂層文件夾,一個(gè)是你的 xcodeproj 項(xiàng)目,一個(gè)是 Pods 文件夾(左圖):前者包含著你的業(yè)務(wù)代碼,后者管理者安裝的第三方庫文件。這時(shí)候需要手動(dòng)把 你的項(xiàng)目/Libraries 目錄下的 *.xcodeproj 文件手動(dòng)刪除(右圖紅框 ?),因?yàn)樗麄円呀?jīng)存在于 Pods 文件夾里了(右圖紅框 ?)。

2?? 修改 Header Search Path
上一步修改了 React Native 項(xiàng)目的引用方式,但還有一個(gè)問題,那就是尋址的頭文件路徑并沒有修改過來,我們可以觀察下面兩張圖:
原來的 Header Search Path 指向的是
$(SRCROOT)/../node_modules/*使用 CocoaPods 后路徑發(fā)生了變化,變成了
$(PODS_CONFIGURATION_BUILD_DIR)/*
當(dāng)時(shí)這個(gè)變化卡了我一天,而且這個(gè)變化是在 project.pbxproj 中的,非常難以閱讀就忽略掉了。后來通過新建一個(gè) RN 新項(xiàng)目發(fā)現(xiàn)了問題。解決方法是刪除原來的 Header Search Path 內(nèi)容,手動(dòng)把新的路徑添加進(jìn)去。


上面兩步做完后可以嘗試 build 一下項(xiàng)目,大概率你會(huì)發(fā)現(xiàn)還是 build 不起來。因?yàn)殄e(cuò)誤原因千奇百怪我也無法一一覆蓋,這里還是問 Google 比較方便。
3?? 新增 Start Packager 腳本
到這一步假設(shè)你已經(jīng) Build 起來 iOS 項(xiàng)目了,這時(shí)候你會(huì)發(fā)現(xiàn)一個(gè)問題,之前 iOS build 成功后,會(huì)自動(dòng)啟動(dòng)一個(gè) node 服務(wù)器編譯 javascript 文件,更新后并沒有自動(dòng)啟動(dòng) node 服務(wù)器,需要我們手動(dòng) npm run start 啟動(dòng) node 服務(wù)器,非常的不方便。
問題出在哪里呢?原因是在原來的構(gòu)建方式里,Libraries 下的 React.xcodeproj 有個(gè) Start Packager 腳本,這個(gè)腳本會(huì)在項(xiàng)目 build 成功后自動(dòng)啟動(dòng)一個(gè) node 服務(wù)器:

遷移到 Pods 后,這個(gè)腳本就沒有了,需要我們?cè)谥鞴こ汤锸謩?dòng)添加一下。添加方式也很簡(jiǎn)單,我在下圖也標(biāo)注好了,點(diǎn)擊項(xiàng)目文件夾,在 TARGETS 的 Build Phases 里點(diǎn)擊 ?,再點(diǎn)擊 New Run Script Phase 新增一個(gè)腳本區(qū)域,然后把下面的代碼填寫進(jìn)去:

export RCT_METRO_PORT="${RCT_METRO_PORT:=8081}"
echo "export RCT_METRO_PORT=${RCT_METRO_PORT}" > "${SRCROOT}/../node_modules/react-native/scripts/.packager.env"
if [ -z "${RCT_NO_LAUNCH_PACKAGER+xxx}" ] ; then
if nc -w 5 -z localhost ${RCT_METRO_PORT} ; then
if ! curl -s "http://localhost:${RCT_METRO_PORT}/status" | grep -q "packager-status:running" ; then
echo "Port ${RCT_METRO_PORT} already in use, packager is either not running or not running correctly"
exit 2
fi
else
open "$SRCROOT/../node_modules/react-native/scripts/launchPackager.command" || echo "Can't start packager automatically"
fi
fi
這個(gè) Start Packager 腳本的位置也有些講究,最好放在 Check Pods Manifest.lock 和 Compile Sources 之間,要不然啟動(dòng) node 服務(wù)器時(shí)會(huì)導(dǎo)致報(bào)錯(cuò)。
4?? 新增 LaunchScreen.storyboard
隨著 iPhone 產(chǎn)品線的增多,iPhone手機(jī)的尺寸也多了起來,原來一個(gè)尺寸配一個(gè) LaunchImage 的方式逐漸變的不再適用,這時(shí)候 ? 官方建議用 LaunchScreen.storyboard 來制作啟動(dòng)屏,并且要求 2021 年所有 APP 都得改為此方案。
具體的配置網(wǎng)上有很多教程了,大家搜索參考配置就好。我個(gè)人參考了以下教程:
- iOS 開發(fā)時(shí)如何使用 Launch Screen Storyboard
- 通過 LaunchScreen.storyboard 來為 RN 應(yīng)用添加啟動(dòng)屏
- iOS 13 使用 LaunchScreen.storyboard 適配各尺寸啟動(dòng)圖
5?? 修改 xcodebuild 腳本
如果項(xiàng)目之前有配置過自動(dòng)打包腳本,因?yàn)檫@次升級(jí)遷移到 workspace,所以也得對(duì)原來的打包腳本做一些修改:
xcodebuild archive -project 項(xiàng)目名稱.xcodeproj
??
xcodebuild archive -workspace 項(xiàng)目名稱.xcworkspace
關(guān)于 xcodebuild 可以參考這兩篇文章:
<br />
3.Android
0.60 的 Android 更新主要是 3 點(diǎn):
- React Native 項(xiàng)目升級(jí)到 AndroidX
- React Native 第三方依賴支持 autolink
- 支持 Hermes,一個(gè) Facebook 開源的 Javascript 引擎
升級(jí)前先需要升級(jí) Gradle 和 Groovy 的版本。具體細(xì)節(jié)參考 Upgrade Helper。
1?? 升級(jí)到 AndroidX
AndroidX 的推進(jìn)主要是 Google 官方受夠了 Android 目前混亂不堪的 android.support ,用一個(gè)統(tǒng)一的 androidx 來代替。升級(jí)跟著 Android 官方文檔走就行,我主要參考了以下文檔:
遷移工作主要是修改 import 路徑,工作量可能有些大,但心理負(fù)擔(dān)較小,本質(zhì)上就是改了個(gè)名字,問題不大。
2?? Autolinking 支持
Autolinking 功能集成前先試試運(yùn)行 react-native unlink,看看能不能自動(dòng)取消鏈接。如果取消失敗,就要自己手動(dòng)刪除舊的 link 代碼,加入新的 Autolinking 代碼。下面我以 react-native-svg 這個(gè)第三方庫為例進(jìn)行說明:
1.檢查 android/settings.gradle,刪除舊的 include 配置,加入下面新的代碼:
rootProject.name = '你的項(xiàng)目'
- include ':react-native-svg'
- project(':react-native-svg').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-svg/android')
+ apply from: file("../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesSettingsGradle(settings)
include ':app'
2.檢查 android/app/build.gradle,刪除舊的配置,文件的最后一行加入一行配置:
dependencies {
- implementation project(':react-native-svg')
}
+ apply from: file("../../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesAppBuildGradle(project)
3.檢查 MainApplication.java,刪除舊的引用:
- @Override
- protected List<ReactPackage> getPackages() {
- return Arrays.<ReactPackage>asList(
- new MainReactPackage(),
- new SvgPackage()
- );
+ @SuppressWarnings("UnnecessaryLocalVariable")
+ List<ReactPackage> packages = new PackageList(this).getPackages();
+ return packages;
- }
值得注意的是,我們業(yè)務(wù)中很有可能會(huì)自己封裝一些 Native Module,經(jīng)過上面的修改后,導(dǎo)入 Native Module 的方式也要做相應(yīng)的修改,這里可以參考官方文檔 Android Register the Module:
+ import com.your-app-name.CustomToastPackage; // <-- Add this line with your package name.
protected List<ReactPackage> getPackages() {
@SuppressWarnings("UnnecessaryLocalVariable")
List<ReactPackage> packages = new PackageList(this).getPackages();
+ packages.add(new CustomToastPackage()); // <-- Add this line with your package name.
return packages;
}
3?? Hermes 支持

Hermes 是一個(gè) Facebook 開源的 Javascript 引擎,和現(xiàn)在的 JSC 相比,在包體積和啟動(dòng)速度上有所優(yōu)化。社區(qū)上已經(jīng)有很多介紹 Hermes 的文章了,我找了幾篇比較好的,如果對(duì) Hermes 感興趣可以移步查看。
Hermes 的相關(guān)特性不是本文重點(diǎn),所以就不多介紹了。
Android 想要使用 Hermes 的話,必須得使用版本號(hào)大于 0.60.4 的 React Native,并且要對(duì) android/app/build.gradle 做一些修改:
project.ext.react = [
- entryFile: "index.js"
+ entryFile: "index.js",
+ enableHermes: false, // clean and rebuild if changing
]
- def useIntlJsc = false
+ def jscFlavor = 'org.webkit:android-jsc:+'
dependencies {
- if (useIntlJsc) {
- implementation 'org.webkit:android-jsc-intl:+'
- } else {
- implementation 'org.webkit:android-jsc:+'
- }
+ if (enableHermes) {
+ def hermesPath = "../../node_modules/hermesvm/android/";
+ debugImplementation files(hermesPath + "hermes-debug.aar")
+ releaseImplementation files(hermesPath + "hermes-release.aar")
+ } else {
+ implementation jscFlavor
+ }
}
上面只列出了主要變更,如果不想用 Hermes,可以完全不做更改;如果想要嘗試一下,最好還是根據(jù) Upgrade Helper 列出的詳細(xì)變更進(jìn)行修改,然后閱讀 React Native 官網(wǎng)的 Using Hermes 進(jìn)行配置與調(diào)試。
<br />
四、React Native 0.61 升級(jí)
React Native 0.61 最主要的更新就是 Fast Refresh 的引入了,這個(gè)功能大大提升了開發(fā)體驗(yàn)。
Fast Refresh 的加入有兩個(gè)好處,第一個(gè)是把 live reloading 和 hot reloading 兩個(gè)功能合二為一并做了功能加強(qiáng);第二個(gè)終于支持 Hooks 熱更新了。雖然 0.59.10 已經(jīng)支持 hooks,但是當(dāng)時(shí)的函數(shù)式組件不支持熱更新,開發(fā)體驗(yàn)過于差勁。升級(jí)到 React Native 0.61 后就可以使用了。
整體來說 0.61 的更新很小,一兩個(gè)小時(shí)就可以完成升級(jí)。升級(jí)前建議參考 Upgrade Helper 和 Upgrade to React Native 0.61 這篇博文,我會(huì)對(duì)文中沒有說明的地方進(jìn)行補(bǔ)充。
1.React Native
JavaScript 這里主要是一些 API 的變動(dòng)和升級(jí),跟著報(bào)錯(cuò)信息修改就好,難度并不大。
1?? React 升級(jí)到 16.9
React 升級(jí)到 16.9 后,componentWillMount 等 API 廢棄,必須遷移到 UNSAFE_componentWillMount 等帶有 UNSAFE_ 前綴的 API。
主工程里這些 API 比較容易重構(gòu)和替換,麻煩的是一些很久沒有維護(hù)的第三方 JS 包,這時(shí)候需要自己手動(dòng) Fork 一份代碼維護(hù),或者替換同功能的正在維護(hù)的第三方包,這個(gè)屬于技術(shù)債,只能一點(diǎn)一點(diǎn)克服。
2?? 引用路徑改動(dòng)
更新后有些方法和組件的引用路徑發(fā)生了變更,需要我們適配一下:
1.ErrorUtils 默認(rèn)綁定到 global 上,不需要 import ErrorUtils from ErrorUtils 導(dǎo)入了
2.RCTNetworking 引用路徑發(fā)生改變,需要修改為:
const RCTNetworking = require('react-native/Libraries/Network/RCTNetworking');
3.Dimensions 導(dǎo)入方式也發(fā)生了改變,需要修改:
import Dimensions from 'Dimensions';
??
import { Dimensions } from 'react-native';
2.iOS
0.61 之后,React Native iOS 端只支持通過 Cocoapods Link 了,如果 0.60 已經(jīng)升級(jí)到 Cocoapods 了,那么這次的 iOS 升級(jí)將會(huì)非???,只需要改動(dòng) Podfile 中一些庫的導(dǎo)入路徑就可以了。
具體的差異可見 Upgrade Helper,非常簡(jiǎn)單,比對(duì)修改后重新 pod install 就可以了。
3.Android
0.61 的 Android 升級(jí)也比較簡(jiǎn)單,升級(jí)了 Gradle 版本,修改了 Hermes 的引用路徑,跟著 Upgrade Helper 的 Diff 依次修改就可。
<br />
五、React Native 0.62 升級(jí)
React Native 0.62 也是加強(qiáng)了開發(fā)者體驗(yàn),RN 項(xiàng)目默認(rèn)引入了 Flipper 這個(gè) Facebook 制作的移動(dòng)端調(diào)試工具,支持了 React DevTools v4,錯(cuò)誤提示可以選擇新的 LogBox,比原來的錯(cuò)誤提示更加友好從而更容易定位問題。
除了開發(fā)體驗(yàn)的加強(qiáng),這次更新還支持了 Dark Mode 模式,RN 之后就可以做暗黑模式的適配了。
整體來說 0.62 的更新也很小,一兩個(gè)小時(shí)就可以完成升級(jí)。升級(jí)前建議參考 Upgrade Helper 和 Upgrade to React Native 0.62 這篇博文,我會(huì)對(duì)文中沒有說明的地方進(jìn)行補(bǔ)充。
1.React Native
1?? useNativeDriver 顯式指定
React Native 之前使用 Animated API 時(shí),useNativeDriver 默認(rèn)值為 false,也就是說默認(rèn)都是 JS 線程繪制動(dòng)畫。版本升級(jí)后需要顯式指定 useNativeDriver 的值。我認(rèn)為這個(gè)更新的意義在于每次使用 Animated 時(shí),強(qiáng)迫開發(fā)者思考能不能讓動(dòng)畫在 Native 線程運(yùn)行,優(yōu)化動(dòng)畫體驗(yàn)。
2?? LogBox 開啟
LogBox 這個(gè)功能在 0.62 里是默認(rèn)關(guān)閉的,0.63 版本默認(rèn)開啟。0.62 里開啟方式比較 Hack,需要按以下步驟操作:
1.項(xiàng)目根目錄新建一個(gè) before.js,然后里面只寫一行代碼:
require('react-native').unstable_enableLogBox();
2.在 JS 所有文件的入口文件 index.js 的第一行里導(dǎo)入這個(gè)文件:
import './before';
上面兩步必須嚴(yán)格執(zhí)行,不然的話會(huì)有紅屏報(bào)錯(cuò)。
2.iOS
1?? CocoaPods 更新
Cocoapods 在這個(gè)版本里也有些改動(dòng),除去 Flipper 相關(guān)的 pod,改動(dòng)非常小,根據(jù) Upgrade Helper 中的 Diff 差異修改就好。
2?? Swift 支持
0.62 升級(jí)需要修改一些 Swift 相關(guān)的配置,具體升級(jí)流程可見 React Native 0.62 upgrade (Xcode)
3.Android
0.61 的 Android 升級(jí)也比較簡(jiǎn)單,升級(jí)了 Gradle 版本,除去 Flipper 相關(guān)的更新,改動(dòng)非常小,跟著 Upgrade Helper 的 Diff 依次修改就可。
4.Flipper
[圖片上傳失敗...(image-981308-1598410413140)]
0.62 之后,Flipper 在 RN 的項(xiàng)目里是默認(rèn)添加的,可以方便的查看 Layout、network 和 log 等信息。
舊項(xiàng)目升級(jí)時(shí),Flipper 其實(shí)是可選的,安裝有些波折,上手體驗(yàn)了一下感覺如下(版本為 0.52.1):
- 把 React Native 的
console.log信息和 Native 的 log 信息和在一個(gè)應(yīng)用里,比較方便查看 - 可以查看 Native Layout 布局,并且內(nèi)置了
React DevTools v4,兩者比對(duì)可以方便查看布局 - Network 可以方便查看網(wǎng)絡(luò)信息,這個(gè)一直是 RN 調(diào)試的一個(gè)痛點(diǎn)
- 可以快速的截屏錄屏,有助于和 UED 溝通
- 支持自定義插件
上面都是優(yōu)點(diǎn),缺點(diǎn)還是有不少的,下面我說說我用下來感覺到的不足:
- network 對(duì) UTF-8 支持不太好。Flipper 對(duì)編碼沒有處理好,導(dǎo)致中文顯示亂碼,我已經(jīng)給官方提了 issues,但是一直沒有理我
- network 圖片解析也有問題,被解析為亂碼的文本
- log 模塊的數(shù)據(jù)都是字符串,即使你 log 的是 object,它也只是展示
JSON.stringify后的數(shù)據(jù)
上面就是我的使用體驗(yàn),要不要在項(xiàng)目中使用,我覺得大家還是親自體驗(yàn)一下比較好。
如果要在項(xiàng)目中集成 Flipper,根據(jù) Upgrade Helper 進(jìn)行集成就好,難度不是很大。
<br />
后記
上面就是 React Native 版本升級(jí)指南的內(nèi)容了,本升級(jí)教程會(huì)持續(xù)更新,為了獲得最佳體驗(yàn)可以查看閱讀博客原文。
覺得文章對(duì)你有用的話一定要記得點(diǎn)贊哦 ??,謝謝你,這對(duì)我來說真的很重要!
<br />
更多優(yōu)秀文章推薦:
- React Native 性能優(yōu)化指南從渲染層的角度分析了 RN 性能優(yōu)化的 6 個(gè)點(diǎn),并以圖文形式講解了 FlatList 的實(shí)現(xiàn)原理
- 一篇介紹了 webpack 中最易混淆的 5 個(gè)知識(shí)點(diǎn),掘金快 800 贊了,一文講清楚 Webpack 中那些長(zhǎng)得像卻意義不同的概念
- 一篇詳細(xì)介紹了 webpack dll 是個(gè)什么東西,并且給出了 2 條最佳實(shí)踐,擺脫繁瑣的 dll 配置