React-Native CodePush 之 配置Android
使用RN開發(fā)項(xiàng)目雖然已經(jīng)開發(fā)了很久了雾消,但親自操手配置 CodePush 還是第一次迅办,話不多說開始今天的 CodePush 配置之旅生巡;
簡介
CodePush 是由 Microsoft 提供的一個(gè)用于實(shí)現(xiàn) React Native 應(yīng)用程序熱更新的解決方案盒揉。它允許你在不通過應(yīng)用商店發(fā)布新版本的情況下,將更新推送到現(xiàn)有的安裝應(yīng)用程序潜秋。以下是 CodePush 的一些關(guān)鍵概念和用法:
- 部署環(huán)境: 在 CodePush 中曲掰,你可以創(chuàng)建不同的部署環(huán)境疾捍,例如 "Staging" 和 "Production"。每個(gè)環(huán)境都有自己的部署密鑰和更新栏妖。這有助于分離測試和生產(chǎn)環(huán)境的更新乱豆。
- 部署密鑰: 每個(gè)部署環(huán)境都有一個(gè)唯一的部署密鑰,用于標(biāo)識該環(huán)境的更新吊趾。你需要在應(yīng)用程序中配置正確的部署密鑰宛裕,以獲取相應(yīng)環(huán)境的更新。
- 發(fā)布更新: 使用 code-push release-react 命令發(fā)布新的更新论泛。該命令可以將 React Native 項(xiàng)目的 JavaScript bundle 和資源文件上傳到 CodePush 服務(wù)器揩尸。
開始實(shí)操
開發(fā)文檔傳送門。
1. 需要在項(xiàng)目的根目錄使用npm 下載依賴包
npm install --save react-native-code-push
2. 需要更改android的原生代碼
1)android/settings.gradle在 文件中屁奏,進(jìn)行以下添加
include ':app', ':react-native-code-push'
project(':react-native-code-push').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-code-push/android/app')
2)在文件中 android/app/build.gradle 岩榆,將 codepush.gradle 文件添加為其他生成任務(wù)定義
apply from: "../../node_modules/react-native-code-push/android/codepush.gradle"
3)MainApplication.java 更新文件,則通過以下更改使用 CodePush:
// 1. 導(dǎo)入插件
import com.microsoft.codepush.react.CodePush;
public class MainApplication extends Application implements ReactApplication {
private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) {
...
// 2. 重寫 getJSBundleFile 方法以讓 CodePush運(yùn)行時(shí)確定從那里獲取JS
@Override
protected String getJSBundleFile() {
return CodePush.getJSBundleFile();
}
};
}
添加部署密鑰
先去后臺創(chuàng)建app 微軟管理平臺(備注:創(chuàng)建完成app之后坟瓢,會自動(dòng)生成Staging和Production環(huán)境)
第一步 - 使用 appcenter-cli勇边,進(jìn)行創(chuàng)app環(huán)境密鑰
安裝 App Center CLI:
npm install -g appcenter-cli
第二步 - 登入
// 回車之后,按照提示輸入yes载绿,然后會自動(dòng)打開瀏覽給出密碼粥诫,只需要復(fù)制粘貼回終端再回車就OK了
appcenter login
第三步 - 獲取 owner名稱 和 app名稱
appcenter apps list
第四步 - 選擇你要的配置的app項(xiàng)目油航,進(jìn)行創(chuàng)建SIT和PROD環(huán)境的密鑰(一定要核對好 owner名稱 和 app名稱的單詞大小寫)
// appcenter codepush release-react -a jackteng666-gmail.com/MyApp -d Staging SIT環(huán)境(測試環(huán)境)
范例:
appcenter codepush release-react -a 123456-@gamil.com/MyApp -d Staging
// appcenter codepush release-react -a 123456-@gamil.com/MyApp -d Production PROD環(huán)境(生產(chǎn)環(huán)境)
范例:
appcenter codepush release-react -a 123456-@gamil.com/MyApp -d Production
第五步 - 獲取密鑰
appcenter codepush deployment list --app 123456-@gamil.com/MyApp -k
不出意外的話崭庸,到這一步已經(jīng)創(chuàng)建好兩個(gè)環(huán)境的密鑰并且返回兩個(gè)環(huán)境的密鑰,接下來就是在app中配置密鑰
密鑰的配置分兩種形式谊囚,a. 固定環(huán)境 b.多種環(huán)境怕享,這些根據(jù)自己的業(yè)務(wù)需求選擇
a. 固定環(huán)境:
在 android/app/src/main/res/values/strings.xml 進(jìn)行添加
<resources>
<string name="app_name">AppName</string>
<string moduleConfig="true" name="CodePushDeploymentKey">替換自己需要的環(huán)境密鑰</string>
</resources>
b.多種環(huán)境
在 android/app/build.gradle 進(jìn)行添加
android {
...
buildTypes {
debug {
...
resValue "string", "CodePushDeploymentKey", '""'
...
}
releaseStaging {
...
resValue "string", "CodePushDeploymentKey", '"<INSERT_STAGING_KEY>"'
matchingFallbacks = ['release']
...
}
release {
...
resValue "string", "CodePushDeploymentKey", '"<INSERT_PRODUCTION_KEY>"'
...
}
}
...
}
到這一步app密鑰已經(jīng)配置好了,接下來就是寫js代碼進(jìn)行發(fā)布和測試熱更新
詳細(xì)介紹可以看這里API Reference
import CodePush from 'react-native-code-push';
...
export default CodePush(App);
如果不想在啟動(dòng)app的時(shí)候镰踏,檢查的話函筋,也可以單獨(dú)寫成組建,在需要的地方進(jìn)行加載;
import React, { useState, useEffect } from "react";
import codePush from "react-native-code-push";
const CheckUpdate = () => {
/** 執(zhí)行CodePush更新 */
const processCodepushUpdate = () => {
codePush.notifyAppReady(); // 加這行避免自動(dòng)rollback, https://docs.microsoft.com/zh-tw/appcenter/distribution/codepush/rn-api-ref#codepushnotifyappready
codePush
.sync(
{
installMode: codePush.InstallMode.ON_NEXT_RESUME, // 非強(qiáng)制:下次喚起時(shí)安裝新版本
mandatoryInstallMode: codePush.InstallMode.ON_NEXT_RESUME, // 強(qiáng)制:下次喚起時(shí)安裝新版本
minimumBackgroundDuration: 0, // 背景停留多久后觸發(fā)按照新版本(預(yù)設(shè)0)
rollbackRetryOptions: { delayInHours: 1, maxRetryAttempts: 50 }, // rollback重試設(shè)定
},
(status) => {
// codePush.SyncStatus.CHECKING_FOR_UPDATE 0 : 正在查詢 CodePush 服務(wù)器是否有更新奠伪。
// codePush.SyncStatus.AWAITING_USER_ACTION 1 : 有更新可用跌帐,并向最終用戶顯示確認(rèn)對話框首懈。(僅在updateDialog使用時(shí)適用)
// odePush.SyncStatus.DOWNLOADING_PACKAGE 2 : 在從 CodePush 服務(wù)器下載可用更新。
// codePush.SyncStatus.INSTALLING_UPDATE 3 : 已下載可用更新并將安裝
// codePush.SyncStatus.UP_TO_DATE 4 :應(yīng)用程序已完全更新到配置的部署
// codePush.SyncStatus.UPDATE_IGNORED 5 : 應(yīng)用程序有一個(gè)可選更新谨敛,最終用戶選擇忽略該更新究履。(僅在updateDialog使用時(shí)適用)
// codePush.SyncStatus.UPDATE_INSTALLED 6 : 已安裝可用更新,并將在syncStatusChangedCallback函數(shù)返回后立即運(yùn)行或在下次應(yīng)用程序恢復(fù)/重新啟動(dòng)時(shí)運(yùn)
// codePush.SyncStatus.SYNC_IN_PROGRESS 7: 正在進(jìn)行的sync操作阻止當(dāng)前調(diào)用的執(zhí)行脸狸。
// codePush.SyncStatus.UNKNOWN_ERROR -1 : 同步操作發(fā)現(xiàn)未知錯(cuò)誤最仑。
switch (status) {
case codePush.SyncStatus.DOWNLOADING_PACKAGE:
console.log("在從 CodePush 服務(wù)器下載可用更新");
break;
case codePush.SyncStatus.INSTALLING_UPDATE:
console.log("有更新可用,已下載可用更新并將安裝");
break;
case codePush.SyncStatus.UPDATE_INSTALLED:
console.log("已安裝可用更新炊甲,并將在syncStatusChangedCallback函數(shù)返回后立即運(yùn)行或在下次應(yīng)用程序恢復(fù)/重新啟動(dòng)時(shí)運(yùn)");
codePush.restartApp();
break;
}
},
({ receivedBytes, totalBytes }) => {
// 計(jì)算出下載百分比
const percent = Math.floor((receivedBytes / totalBytes) * 100);
}
)
.catch((error) => {
console.log(JSON.stringify(error))
});
};
useEffect(() => {
processCodepushUpdate();
}, []);
return ...
};
export default CheckUpdate;
到這一步熱更新框架基本上完成了泥彤,接下來就是測試熱更新
發(fā)布版本指令:
當(dāng)前發(fā)布的是SIT環(huán)境,PROD環(huán)境同理
appcenter codepush release-react -a 123456-@gamil.com/MyApp -t "*" -d Staging --description "v1.0.0 測試更新" --sourcemap-output --output-dir ./build/android
備注:
-t 是指目標(biāo)版本卿啡,意思是只有是指定的目標(biāo)版本才會觸發(fā)更新吟吝,比如說,現(xiàn)在你的用戶用的版本是1.1.1 和 1.0.0這兩種版本颈娜,那么 -t "1.1.1" 就是發(fā)布之后爸黄,只有版本為1.1.1的用戶才會觸發(fā)熱更新
如果不需要指定目標(biāo)版本就輸入 -t "*" 通配符為全部版本 或者不輸入 -t
當(dāng)終端返回以下內(nèi)容,則表示已經(jīng)發(fā)布成功了(SIT環(huán)境)
Successfully released an update containing the "build/android/CodePush" directory to the "Staging" deployment of the "MyApp" app.
查看發(fā)布?xì)v史
appcenter codepush deployment history -a 123456-@gamil.com/MyApp Staging
到這里最新版本的代碼已經(jīng)發(fā)布到codPush服務(wù)器上了揭鳞,接下來就可以用已經(jīng)有熱更新代碼版本的app來測試了炕贵;
最簡單的方式就是
1、把當(dāng)前版本打包給Android手機(jī)安裝野崇,然后再改代碼(能夠明顯看到不一樣的界面称开,比較好分辨是否更新成功),然后再重新發(fā)布一次乓梨;
2鳖轰、重新打開APP檢查是否有更新提示(上面的組建,可以根據(jù)自己的想法寫出彈窗和顯示進(jìn)度條)
我當(dāng)前遇到一個(gè)錯(cuò)誤狀態(tài)碼是 codePush.SyncStatus.UNKNOWN_ERROR -1 : 同步操作發(fā)現(xiàn)未知錯(cuò)誤扶镀。蕴侣,這個(gè)錯(cuò)誤會有很多種情況,比較難查臭觉。我的app上導(dǎo)致這個(gè)狀態(tài)的原因是:
{
"nativeStackAndroid":[{"lineNumber":49,"file":"CodePush.java","methodName":"h","class":"com.microsoft.codepush.react.a"},{"lineNumber":25,"file":"CodePushNativeModule.java","methodName":"a","class":"com.microsoft.codepush.react.CodePushNativeModule$c"},{"lineNumber":3,"file":"CodePushNativeModule.java","methodName":"doInBackground","class":"com.microsoft.codepush.react.CodePushNativeModule$c"},{"lineNumber":389,"file":"AsyncTask.java","methodName":"call","class":"android.os.AsyncTask$3"},{"lineNumber":266,"file":"FutureTask.java","methodName":"run","class":"java.util.concurrent.FutureTask"},{"lineNumber":1167,"file":"ThreadPoolExecutor.java","methodName":"runWorker","class":"java.util.concurrent.ThreadPoolExecutor"},{"lineNumber":641,"file":"ThreadPoolExecutor.java","methodName":"run","class":"java.util.concurrent.ThreadPoolExecutor$Worker"},{"lineNumber":929,"file":"Thread.java","methodName":"run","class":"java.lang.Thread"}],
"userInfo":null,
"message":"Error in getting binary resources modified time",
"code":"EUNSPECIFIED"
}
解決方式是在 android/app/build.gradle 的 defaultConfig 中增加:
原文
resValue 'string', "CODE_PUSH_APK_BUILD_TIME", String.format("\"%d\"", System.currentTimeMillis())
然后重新編譯打包給Android機(jī)安裝昆雀,然后再重新改代碼,進(jìn)行發(fā)布測試熱更新
總結(jié):
1蝠筑、使用 npm 安裝 react-native-code-push 依賴
2狞膘、更改android的原生代碼進(jìn)行codePush連線
3、使用 微軟管理平臺 創(chuàng)建app
4什乙、使用 appcenter-cli 進(jìn)行指令管控
5挽封、使用 react-native-code-push 進(jìn)行編碼更新
6、發(fā)布更新測試
7臣镣、解決更新失敗的問題
以上是codePush一個(gè)簡單實(shí)用辅愿,如想更詳細(xì)更多功能智亮,建議查看官網(wǎng)文檔;