在React Native中整合熱更新
最近,在專案DYTT集成了熱更新,簡單來說,就是不用重新下載安裝包即可達到更新應用的目的,也不算教程吧,這裡記錄一下。
1.熱更新方案
目前網上大概有兩個比較廣泛的方式,分別是
前者是由ReactNative中文網推出的程式碼熱更新服務,後者是由微軟老大哥推出的,當然不僅僅是為React Native
,還包括其他原生方式。
綜合考慮之下,選擇了react-native-code-push
。
2.安裝code-push
1.安裝code-push
npm install -g code-push-cli
2.註冊登入賬號
code-push register
這時候會自動啟動瀏覽器開啟網頁並提供一個codePush AccessKey
,然後命令列裡出現需要輸入access key
輸入之後就登入成功了。
(貌似在本機上以後都不用登入了,暫不清楚保持登入持續多久)
3.新增一個CodePush應用
code-push app add myProject android react-native
注意填寫app的名稱,OS(android
/ios
),平臺(react-native
),並且android
和ios
需要建立兩個應用
建立完成會出現兩個key
name | Deployment Key |
---|---|
Production | (一串37位的key) |
Staging | (一串37位的key) |
Production
是對應生產環境的,Staging
是對應開發環境的。
這個對於我們來說其實沒什麼區別,只是為了方便測試,所以搞了兩個環境
3.react-native應用接入code-push
1.安裝react-native-code-push
yarn add react-native-code-push
link
react-native link react-native-code-push
2.原生配置
目前只測試了android
,ios
有興趣的可以自行測試
上面提到了兩個key
值,現在需要配置在原生目錄裡
1.開啟android/app/build.gradle
android { ... buildTypes { debug { ... // Note: CodePush updates should not be tested in Debug mode as they are overriden by the RN packager. However, because CodePush checks for updates in all modes, we must supply a key. buildConfigField "String", "CODEPUSH_KEY", '""' ... }
releaseStaging { ... buildConfigField "String", "CODEPUSH_KEY", '"<INSERT_STAGING_KEY>"'//注意這裡的引號 ... } release { ... buildConfigField "String", "CODEPUSH_KEY", '"<INSERT_PRODUCTION_KEY>"' ... } } ...
}
如果遇到打包錯誤,可加上matchingFallbacks = ['release', 'debug']
,不知道是不是個別情況,如果沒有的請忽略。
修改versionName
為3位數的版本號(code-push要求)
defaultConfig {
applicationId "com.dytt"
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
versionCode 2
versionName "2.1.0"//預設為2位版本號
// ndk {
// abiFilters "armeabi-v7a", "x86"
// }
}
release {
//...
matchingFallbacks = ['release', 'debug']//加上這一句
buildConfigField "String", "CODEPUSH_KEY", '"<INSERT_PRODUCTION_KEY>"'
//...
}
2.開啟MainApplication.java
@Override
protected List<ReactPackage> getPackages() {
return Arrays.<ReactPackage>asList(
...
new CodePush(BuildConfig.CODEPUSH_KEY, MainApplication.this, BuildConfig.DEBUG), // Add/change this line.
...
);
}
這樣就實現了key
的動態部署,即在什麼環境下使用什麼key
4.客戶端更新策略
1.匯入react-native-code-push
這裡需要在應用的根元件上新增CodePush
配置
import CodePush from "react-native-code-push";
如果你的環境支援Decorator(修飾符)
,可以這樣
@codePush(options: CodePushOptions) class MyApp extends Component<{}> {}
普通的寫法
class MyApp extends Component<{}> {} MyApp = codePush(codePushOptions)(MyApp); export default MyApp;
這裡的codePushOptions
是更新的配置選項
- checkFrequency (codePush.CheckFrequency) 指定您要檢查更新的時間,預設為
codePush.CheckFrequency.ON_APP_START
。 - installMode (codePush.InstallMode) 指定何時安裝可選更新,預設為
codePush.InstallMode.ON_NEXT_RESTART
。 - ...
詳細的配置可參考https://github.com/Microsoft/react-native-code-push/blob/master/docs/api-js.md
2.更新策略
預設情況下,CodePush
會在app
每次啟動的時候去檢測是否有更新,如果有,app
會自動下載並在下次開啟app
時安裝
這種更新方式是靜默的,使用者根本察覺不到。
如果我們需要給一點更新提示,可以使用預設的彈出框,也就是react-native
自帶的Alert
,點選後立即安裝
class MyApp extends Component {} MyApp = codePush({ updateDialog: true, installMode: codePush.InstallMode.IMMEDIATE })(MyApp);
當然,你可以對彈出框做少量的自定義,比如標題,按鈕的文字等
updateDialog: { optionalIgnoreButtonLabel: '稍後', optionalInstallButtonLabel: '立即更新', optionalUpdateMessage: '有新版本了,是否更新?', title: '更新提示' },
這些是預設的更新方式,那麼如何自定義呢。
我們可以用到CodePush.checkForUpdate
來手動檢查更新,然後彈出一個自定義視窗
const RemotePackage = await CodePush.checkForUpdate(deploymentKey); if(RemotePackage){ this.modal.init(RemotePackage);//開啟彈窗 }
這裡需要注意的是,在checkForUpdate
(或其他需要填寫deploymentKey的地方)的時候,如果在debug
模式下,如果不填寫deploymentKey
,會提示缺少deploymentKey
,我們可以臨時寫一個固定的方便測試。在正式環境下,這裡是不需要填寫,它會根據系統自動獲取我們在之前配置的那些deploymentKey
值
然後可以通過RemotePackage.download
和LocalPackage.install
來完成下載和安裝
install = async () => { LayoutAnimation.easeInEaseOut(); this.setState({status:1})//download const LocalPackage = await this.RemotePackage.download((progress)=>{ this.setState({ receivedBytes:progress.receivedBytes }) Animated.timing( this.width, { toValue: parseFloat(progress.receivedBytes / progress.totalBytes).toFixed(2), duration: 150 } ).start(); }) this.setState({status:2})//downloadComplete await LocalPackage.install(LocalPackage.isMandatory?CodePush.InstallMode.IMMEDIATE:CodePush.InstallMode.ON_NEXT_RESUME); if(!LocalPackage.isMandatory){ this.setState({status:3}) this.setVisible(false); }else{ ToastAndroid && ToastAndroid.show('下次啟動完成更新', ToastAndroid.SHORT); } }
具體實現可以參考專案DYTT
3.打包Release
cd android
生成Release(Production)包
gradlew assembleRelease
生成Release(Staging)包
gradlew assembleReleaseStaging
其實都一樣,只是環境區別
5.釋出code-push更新
這一步很簡單,集成了打包和釋出
code-push release-react dyttAndroid android --t 2.1.0 --dev false --d Production --des "1.修復了已知BUG\n 2.測試code push" --m true
這裡注意--t 2.1.0
,有以下幾種規則
1.2.3 僅僅只有1.2.3的版本
- 所有版本
1.2.x 主要版本1,次要版本2的任何修補程式版本
1.2.3 - 1.2.7 1.2.3版本到1.2.7版本
>=1.2.3 <1.2.7 大於等於1.2.3版本小於1.2.7的版本
~1.2.3 大於等於1.2.3版本小於1.3.0的版本
^1.2.3 大於等於1.2.3版本小於2.0.0的版本
--d
表示開發版本,可選擇Production
和Staging
--m
表示是否強制更新
當然還有很多操作,比如刪除某些更新,回滾等,可以參考官方文件https://github.com/Microsoft/react-native-code-push
小節
總的來說,這次熱更新整合還是挺容易,裡面碰到的幾個誤區在上面也已經提到過,歡迎大家多多關注我的專案DYTT^^