淺談React原生APP更新
App更新流程
1.在 App 打開(kāi)時(shí)請(qǐng)求接口或文件, 獲取遠(yuǎn)程版本/版本更新說(shuō)明/地址等等重用信息
2.通過(guò)庫(kù)或者原生方案, 獲取 App 的當(dāng)前版本
3.比較遠(yuǎn)程版本和當(dāng)前版本的區(qū)別(可以使用庫(kù),也可以自己寫(xiě)一個(gè)比較方案)
4.通過(guò)獲取到的鏈接進(jìn)行操作(可以跳轉(zhuǎn)到對(duì)應(yīng)網(wǎng)站下載,類(lèi)似蒲公英這種,可以是 apk 鏈接, 通過(guò)安卓原生方法下載, 也可以是 App Store 鏈接)
大致的流程圖

詳細(xì)說(shuō)明:
1.這些遠(yuǎn)程信息,可以是接口, 這樣可以有一個(gè)中臺(tái)來(lái)控制, 當(dāng)然也可以是一個(gè)文件, 讓運(yùn)維來(lái)控制
關(guān)于信息,不止于遠(yuǎn)程版本, 在項(xiàng)目里還可以添加其他屬性,如: versionCode, versionCodeSwitch , notUpdate , deleteApp
- 1.1 versionCode 通過(guò) code 來(lái)升級(jí)版本,一般是一個(gè)數(shù)字(在 ios 里提交 App Store 的時(shí)候有需要用到的地方), 這樣 versionName 并不會(huì)增加, 但是如果添加了 versionCode, 如果要升級(jí) versionName, versionCode 也需要增加
- 1.2 versionCodeSwitch 用來(lái)控制是否要根據(jù)versionCode來(lái)更新, 一般我都是在測(cè)試和其他環(huán)境開(kāi)啟,生產(chǎn)環(huán)境關(guān)閉的
- 1.3 notUpdate 是否要根據(jù)遠(yuǎn)程信息來(lái)更新, 一般都是開(kāi)啟狀態(tài)
- 1.4 deleteApp 安卓 app 需要卸載重新安裝, 因?yàn)橹苯影惭b可能存在某些問(wèn)題, 將會(huì)使用此信息,先刪除 APP, 再重新下載
2.獲取當(dāng)前手機(jī)的信息,方案較多, 我使用的是 react-native-device-info 這個(gè)庫(kù), 這個(gè)庫(kù)里面提供的信息較全, 當(dāng)然也可以使用原生方法, 來(lái)獲取APP的信息
3.關(guān)于本地版本號(hào)和原生版本號(hào)之間的對(duì)比也是可以使用庫(kù),也可以自己寫(xiě), 這邊推薦兩個(gè)庫(kù),下載量都是百萬(wàn)以上的: semver-compare 和 compare-versions, 這邊附上我的 versionName 比較方案, 較為簡(jiǎn)陋:
/**
* 比較兩版本號(hào)
* @param currentVersion
* @return boolean
* true=需要更新 false=不需要
*/
compareVersion = (currentVersion: string): boolean => {
const {versionName: remoteVersion} = this.remoteInfo || {}
if (!remoteVersion) {
return false
}
if (currentVersion === remoteVersion) {
return false
}
const currentVersionArr = currentVersion.split('.')
const remoteVersionArr = remoteVersion.split('.')
for (let i = 0; i < 3; i++) {
if (Number(currentVersionArr[i]) < Number(remoteVersionArr[i])) {
return true
}
}
return false
}
關(guān)于下載 app 有很多方案, 最簡(jiǎn)單的就是跳轉(zhuǎn)鏈接到第三方平臺(tái), 像蒲公英這樣的, 使用 RN 提供的 Linking 方法來(lái)直接跳轉(zhuǎn)
當(dāng)然安卓是可以直接通過(guò)自己提供的地址下載的, 這里提供一個(gè)方法(此方法來(lái)源于網(wǎng)絡(luò)):
@ReactMethod
public void installApk(String filePath, String fileProviderAuthority) {
File file = new File(filePath);
if (!file.exists()) {
Log.e("RNUpdater", "installApk: file doe snot exist '" + filePath + "'");
// FIXME this should take a promise and fail it
return;
}
if (Build.VERSION.SDK_INT >= 24) {
// API24 and up has a package installer that can handle FileProvider content:// URIs
Uri contentUri;
try {
contentUri = FileProvider.getUriForFile(getReactApplicationContext(), fileProviderAuthority, file);
} catch (Exception e) {
// FIXME should be a Promise.reject really
Log.e("RNUpdater", "installApk exception with authority name '" + fileProviderAuthority + "'", e);
throw e;
}
Intent installApp = new Intent(Intent.ACTION_INSTALL_PACKAGE);
installApp.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
installApp.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
installApp.setData(contentUri);
installApp.putExtra(Intent.EXTRA_INSTALLER_PACKAGE_NAME, reactContext.getApplicationInfo().packageName);
reactContext.startActivity(installApp);
} else {
// Old APIs do not handle content:// URIs, so use an old file:// style
String cmd = "chmod 777 " + file;
try {
Runtime.getRuntime().exec(cmd);
} catch (Exception e) {
e.printStackTrace();
}
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setDataAndType(Uri.parse("file://" + file), "application/vnd.android.package-archive");
reactContext.startActivity(intent);
}
}
如果是我們自己提供下載服務(wù),需要注意的是帶寬, 如果網(wǎng)速過(guò)慢則用戶(hù)體驗(yàn)過(guò)差, 還有就會(huì)帶來(lái)更多的流量消耗, 其中的取舍,需要開(kāi)發(fā)者決定
更新APP信息
在打包時(shí), 通過(guò)腳本更新接口或者文件信息, 當(dāng)然這個(gè)得看具體的打包方案
比如我現(xiàn)在的方案是使用 Jenkins 打包, 在打包時(shí)使用 shell 腳本更新對(duì)應(yīng)信息(有需要也可以使用其他語(yǔ)言腳本):
1.首先定義需要獲取的文件地址
androidVersionFilePath="$WORKSPACE/android/app/build.gradle" // 通過(guò)此文件獲取安卓的版本信息 iosVersionFilePath="$WORKSPACE/ios/veronica/Info.plist" // 通過(guò)此文件獲取iOS的版本信息 changeLogPath="$WORKSPACE/change.log" // 將版本更新信息存儲(chǔ)在此文件中
2.通過(guò)文件地址, 獲取打完包后的版本信息
getAndroidVersion(){
androidVersion=$(cat $androidVersionFilePath | grep "versionName" | awk '{print $2}' | sed 's/\"http://g')
androidCode=$(cat $androidVersionFilePath | grep "versionCode " | awk '{print $2}' | sed 's/\"http://g')
androidDelete=$(cat $androidVersionFilePath | grep "deleteApp" | awk '{print $4}' | sed 's/\"http://g')
return 0
}
getIOSVersion(){
rows=$(awk '/CFBundleShortVersionString/ {getline; print}' $iosVersionFilePath)
iosVersion=$(echo "$rows" | sed -ne 's/<string>\(.*\)<\/string>/\1/p')
iosVersion=$(echo "$iosVersion" | sed 's/^[[:space:]]*//')
rows2=$(awk '/VersionCode/ {getline; print}' $iosVersionFilePath)
iosCode=$(echo "$rows2" | sed -ne 's/<string>\(.*\)<\/string>/\1/p')
iosCode=$(echo "$iosCode" | sed 's/^[[:space:]]*//')
return 0
}
desc=$(cat $changeLogPath | tr "\n" "#")
3.替換現(xiàn)有文件中的信息
sed -i '' "s/\"releaseInfo\":.*$/\"releaseInfo\": \"$desc\"/" $JsonPath/$fileName sed -i '' "s/\"versionName\":.*$/\"versionName\": \"$versionName\",/" $JsonPath/$fileName sed -i '' "s/\"versionCode\":.*$/\"versionCode\": \"$versionCode\",/" $JsonPath/$fileName sed -i '' "s/\"deleteApp\":.*$/\"deleteApp\": \"$deleteApp\",/" $JsonPath/$fileName
我的文件是以 json 作為格式的,說(shuō)明文字是可以任意填寫(xiě)的,會(huì)觸發(fā)一些解析問(wèn)題:
- 不允許出現(xiàn)會(huì)造成 JSON.parse 解析失敗的符號(hào), 如 \ , ````, \n ,\r, \" 等等
- 因?yàn)檎f(shuō)明文字的換行我是通過(guò) # 切割的, 所以也不允許出現(xiàn)這個(gè)符號(hào)
大致流程圖

總結(jié)
關(guān)于 APP 原生版本的更新流程基本就是這樣,當(dāng)然這個(gè)流程不光適用 APP, 也可以用于 PC 軟件的更新
除了原生版本的更新,還有熱更新, 也是非常重要的,
以上就是淺談React原生APP更新的詳細(xì)內(nèi)容,更多關(guān)于React原生APP更新的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
每天一個(gè)hooks學(xué)習(xí)之useUpdateEffect
這篇文章主要為大家介紹了每天一個(gè)hooks學(xué)習(xí)之useUpdateEffect使用示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-05-05
jenkins分環(huán)境部署vue/react項(xiàng)目的方法步驟
這篇文章主要介紹了jenkins分環(huán)境部署vue/react項(xiàng)目的方法,本文分步驟給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-02-02
React函數(shù)組件與類(lèi)組件使用及優(yōu)劣對(duì)比
本文主要介紹了React函數(shù)組件與類(lèi)組件使用及優(yōu)劣對(duì)比,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-04-04
在Ant Design Pro登錄功能中集成圖形驗(yàn)證碼組件的方法步驟
這篇文章主要介紹了在Ant Design Pro登錄功能中集成圖形驗(yàn)證碼組件的方法步驟,這里的登錄功能其實(shí)就是一個(gè)表單提交,實(shí)現(xiàn)起來(lái)也很簡(jiǎn)單,具體實(shí)例代碼跟隨小編一起看看吧2021-05-05
nodejs和react實(shí)現(xiàn)即時(shí)通訊簡(jiǎn)易聊天室功能
這篇文章主要介紹了nodejs和react實(shí)現(xiàn)即時(shí)通訊簡(jiǎn)易聊天室功能,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-08-08
antd-react使用Select組件defaultValue踩的坑及解決
這篇文章主要介紹了antd-react使用Select組件defaultValue踩的坑及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-05-05

