這里給大家分享我在網上總結出來的一些知識,希望對大家有所幫助

我們知道,在打包Android App之前,我們需要先通過HX生成打包資源,如果是通過cli創建的專案,則通過以下命令生成打包資源:
yarn build:app-plus
生成打包資源后的目錄長這樣:

然后將整個目錄中的所有檔案拷貝到Android專案的 assets/apps/<appid>/www 中:
可以看出,所有生成的檔案,其實只是一個資源目錄,
熱更新的原理就是:替換資源目錄中的所有打包資源
熱更新包分析
我們通過HX生成的熱更新包:
生成的熱更新包長這樣:

可以看出,wgt其實就是一個壓縮檔案,將生成的資源檔案全部打包,
知道原理后,我們就不一定需要通過HX創建wgt了,我們可以使用yarn build:app-plus命令先生成打包資源目錄,再將其壓縮為zip包,修改擴展名為wgt即可
注意:wgt包中,必須將manifest,json所在路徑當做根節點進行打包,
打完包后,我們可以將其上傳到OSS,
熱更新方案
熱更新方案:通過增加當前APP資源的版本號(versionCode),跟上一次打包時的APP資源版本號進行對比,如果比之前的資源版本號高,即進行熱更新,
熱更新原理:uniapp的熱更新,其實是將build后的APP資源,打包為一個zip壓縮包(擴展名改為wgt),
涉及到的版本資訊檔案:
- src/manifest.json
- app.json (自己創建,用于版本對比)
- platforms/android/app/build.gradle
注意事項:
保證以上檔案的versionName和versionCode均保持一致,
熱更新核心代碼
以下為熱更新的核心代碼:
// #ifdef APP-PLUS
let downloadPath = "https://xxx.cn/apk/app.wgt"
uni.downloadFile({
url: downloadPath,
success: (downloadResult) => {
if (downloadResult.statusCode === 200) {
plus.runtime.install(downloadResult.tempFilePath, {
force: true // 強制更新
}, function() {
console.log('install success...');
plus.runtime.restart();
}, function(e) {
console.error(e);
console.error('install fail...');
});
}
}
})
// #endif
這里是下載wgt包,并進行安裝的代碼,以上代碼無論如何都會下載wgt進行安裝,
更新介面
實際上,在這之前,我們還需要判斷是否需要更新,這就涉及到介面的部分,在此,只講講思路:
- 獲取安裝的版本名、版本號等資訊,將其當做引數呼叫對應的更新介面;
- 介面取到這些資訊,與最新版本進行對比,如果版本已經更新,回傳需要更新的資訊;
- 介面可以自行約定,怎么方便這么來,
我自己做的話,根本沒寫什么介面,只是創建了一個app.json檔案,用于存放最新版本資訊:
{
"versionCode": "100",
"versionName": "1.0.0"
}
將其上傳到OSS,然后在下載wgt包之前進行版本檢查即可:
// #ifdef APP-PLUS
plus.runtime.getProperty(plus.runtime.appid, function(widgetInfo) {
console.log(widgetInfo);
uni.request({
url: 'https://xxx.cn/apk/app.json',
success: (result) => {
let { versionCode, versionName } = result.data
console.log({ versionCode, versionName });
// 判斷版本名是否一致
if (versionName === widgetInfo.version) {
// 如果安裝的版本號小于最新發布的版本號,則進行更新
if (parseInt(widgetInfo.versionCode) < parseInt(versionCode)) {
// 下載wgt更新包
let downloadPath = "https://xxx.cn/apk/app.wgt"
uni.downloadFile({
url: downloadPath,
success: (downloadResult) => {
if (downloadResult.statusCode === 200) {
plus.runtime.install(downloadResult.tempFilePath, {
force: true // 強制更新
}, function() {
console.log('熱更新成功');
plus.runtime.restart();
}, function(e) {
console.error('熱更新失敗,錯誤原因:' + e);
});
}
}
})
} else {
console.log('你的版本為最新,不需要熱更新');
}
} else {
console.log('版本名不一致,請使用整包更新');
}
}
});
});
// #endif
OK,至此,熱更新就完成了,
Android整包更新
看到上面更新邏輯,如果版本名不一致,則需要下載最新的apk進行安裝,在下載之前,建議給用戶一個更新提示:
console.log('版本名不一致,請使用整包更新');
let url = "https://xxx.cn/apk/app.apk"
uni.showModal({ //提醒用戶更新
title: "更新提示",
content: "有新的更新可用,請升級",
success: (res) => {
if (res.confirm) {
plus.runtime.openURL(url);
}
}
})
以上代碼是官方提供的,其實也可以下載apk成功后,直接呼叫install進行安裝:
console.log('版本名不一致,請使用整包更新');
let downloadPath = "https://zys201811.boringkiller.cn/shianonline/apk/app.apk"
uni.showModal({ //提醒用戶更新
title: "更新提示",
content: "有新的更新可用,請升級",
success: (res) => {
if (res.confirm) {
// plus.runtime.openURL(downloadPath);
uni.downloadFile({
url: downloadPath,
success: (downloadResult) => {
if (downloadResult.statusCode === 200) {
console.log('正在更新...');
plus.runtime.install(downloadResult.tempFilePath, {
force: true // 強制更新
}, function() {
console.log('整包更新成功');
plus.runtime.restart();
}, function(e) {
console.error('整包更新失敗,錯誤原因:' + e);
});
}
}
})
}
}
})
熱更新的自動化處理
知道原理后,就好辦了,我們可以將其繁雜的作業自動化,以減少重復勞動,
修改package.json的相關打包腳本:
{
"name": "shianaonline",
"version": "0.1.224",
"private": true,
"scripts": {
"apk": "node deploy/scripts/build-apk.js",
"wgt": "node deploy/scripts/build-wgt.js",
"build:app-plus-android": "cross-env NODE_ENV=production UNI_PLATFORM=app-plus UNI_OUTPUT_DIR=./platforms/android/app/src/main/assets/apps/your appid/www vue-cli-service uni-build",
"build:app-plus-ios": "cross-env NODE_ENV=production UNI_PLATFORM=app-plus UNI_OUTPUT_DIR=./platforms/iOS/apps/your appid/www vue-cli-service uni-build",
}
}
其中,需要替換的地方是your appid,換為自己的uniapp appid
創建app.json,用于存盤當前app的版本資訊:
{
"versionName": "1.0.27",
"versionCode": 336,
"appPath": "https://xxx.oss.com/apk/app-release.apk",
"wgtPath": "https://xxx.oss.com/apk/www.wgt"
}
創建自動化打包腳本build-wgt.js:
const fs = require('fs')
const { execSync } = require('child_process')
const join = require('path').join
// 修改版本號
let app = require('../../app.json')
let manifest = require('../../src/manifest.json')
if (app.versionName !== manifest.versionName) {
console.info('manifest.json和app.json的versionName不一致,請檢查')
return
}
if (app.versionCode !== manifest.versionCode) {
console.info('manifest.json和app.json的versionCode不一致,請檢查')
return
}
// 獲取build.gradle的版本名
let gradleFilePath = '../../platforms/android/app/build.gradle'
let data = https://www.cnblogs.com/smileZAZ/archive/2022/10/27/fs.readFileSync(__dirname +'/' + gradleFilePath, {
encoding: 'utf-8'
})
let reg = new RegExp(`versionCode ${app.versionCode}`, "gm")
if (!reg.test(data)) {
console.log('platforms/android/app/build.gradle的versionCode不一致,請檢查')
return
}
app.versionCode += 1
manifest.versionCode += 1
console.log('====================');
console.log('newVersion:' + app.versionName + "." + app.versionCode);
console.log('====================');
let appJSON = JSON.stringify(app, null, 2)
let manifestJSON = JSON.stringify(manifest, null, 2)
let replaceFiles = [{
path: '../../app.json',
name: 'app.json',
content: appJSON
}, {
path: '../../src/manifest.json',
name: 'manifest.json',
content: manifestJSON
}]
replaceFiles.forEach(file => {
fs.writeFileSync(__dirname + '/' + file.path, file.content, {
encoding: 'utf-8'
})
console.log(file.name + ': 替換成功');
})
// 替換build.gradle的版本名
let result = data.replace(reg, `versionCode ${app.versionCode}`)
fs.writeFileSync(__dirname + '/' + gradleFilePath, result, {
encoding: 'utf-8'
})
console.log('platforms/android/build.gradle: 替換成功')
console.log('====================');
// 編譯
console.log(execSync('yarn build:app-plus-android', { encoding: 'utf-8'}))
// 打包
const compressing = require('compressing');
const tarStream = new compressing.zip.Stream();
const targetPath = './platforms/android/app/src/main/assets/apps/your appid/www'
const targetFile = './www.wgt'
let paths = fs.readdirSync(targetPath);
paths.forEach(function (item) {
let fPath = join(targetPath, item);
tarStream.addEntry(fPath);
});
tarStream
.pipe(fs.createWriteStream(targetFile))
.on('finish', upToOss)
// 上傳至OSS
let OSS = require('ali-oss');
function upToOss() {
let client = new OSS({
region: 'oss-cn-shenzhen',
accessKeyId: 'your accessKeyId',
accessKeySecret: 'your accessKeySecret'
});
client.useBucket('your bucketName');
let ossBasePath = `apk`
put(`${ossBasePath}/www.wgt`, 'www.wgt')
put(`${ossBasePath}/wgts/${app.versionCode}/www.wgt`, 'www.wgt')
put(`webview/vod.html`, 'src/hybrid/html/vod.html')
put(`${ossBasePath}/app.json`, 'app.json')
async function put (ossPath, localFile) {
try {
await client.put(ossPath, localFile);
console.log(`${localFile}上傳成功:${ossPath}`);
} catch (err) {
console.log(err);
}
}
}
console.log('====================');
console.log('更新完畢,newVersion:' + app.versionName + "." + app.versionCode);
console.log('====================');
以上打包腳本,做了以下作業:
- 驗證版本號和版本名是否正確,如果不正確,終止腳本
- 修改當前APP版本號
- 生成APP打包資源
- 將打包資源做成zip包(擴展名改為wgt)
- 上傳wgt資源包到OSS
一鍵式操作,打包為wgt只需要執行:
yarn wgt
Android整包更新的自動化處理
Android整包更新需要在AndroidManifest.xml中配置:
<uses-permission android:name="android.permission.INSTALL_PACKAGES"/> <uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES"/>
Android整包更新的業務代碼跟熱更新一樣,都可以呼叫plus.runtime.install來實作,
主要還是說一下打包apk的自動化腳本build-apk.js
const fs = require('fs')
const { execSync } = require('child_process')
let app = require('../../app.json')
let manifest = require('../../src/manifest.json')
if (app.versionName !== manifest.versionName) {
console.log('manifest.json和app.json的versionName不一致,請檢查')
return
}
if (app.versionCode !== manifest.versionCode) {
console.log('manifest.json和app.json的versionCode不一致,請檢查')
return
}
// 獲取build.gradle的版本名
let gradleFilePath = '../../platforms/android/app/build.gradle'
let data = https://www.cnblogs.com/smileZAZ/archive/2022/10/27/fs.readFileSync(__dirname +'/' + gradleFilePath, {
encoding: 'utf-8'
})
let reg = new RegExp(`versionName "${app.versionName}"`, "gm")
if (!reg.test(data)) {
console.info('platforms/android/app/build.gradle的versionName不一致,請檢查')
return
}
let regCode = new RegExp(`versionCode ${app.versionCode}`, "gm")
if (!regCode.test(data)) {
console.info('platforms/android/app/build.gradle的versionCode不一致,請檢查')
return
}
// 修改版本名
let appVersionName = app.versionName.split('.')
let manifestVersionName = manifest.versionName.split('.')
let appVersionLast = Number(appVersionName[2])
let manifestVersionLast = Number(manifestVersionName[2])
appVersionLast += 1
manifestVersionLast += 1
app.versionName = appVersionName[0] + '.' + appVersionName[1] + '.' + appVersionLast
manifest.versionName = manifestVersionName[0] + '.' + manifestVersionName[1] + '.' + manifestVersionLast
console.log('====================');
console.log('newVersion:' + app.versionName + "." + app.versionCode);
console.log('====================');
let appJSON = JSON.stringify(app, null, 2)
let manifestJSON = JSON.stringify(manifest, null, 2)
// 替換專案版本名
let replaceFiles = [{
path: '../../app.json',
name: 'app.json',
content: appJSON
}, {
path: '../../src/manifest.json',
name: 'manifest.json',
content: manifestJSON
}]
replaceFiles.forEach(file => {
fs.writeFileSync(__dirname + '/' + file.path, file.content, {
encoding: 'utf-8'
})
console.log(file.name + ': 替換成功');
})
// 替換build.gradle的版本名
let result = data.replace(reg, `versionName "${app.versionName}"`)
fs.writeFileSync(__dirname + '/' + gradleFilePath, result, {
encoding: 'utf-8'
})
console.log('platforms/android/build.gradle: 替換成功')
console.log('====================');
// 打包資源
console.log(execSync(`yarn build:app-plus-android`, { encoding: 'utf-8'}))
// 打包apk
console.log(execSync(`cd platforms/android && gradle assembleRelease`, { encoding: 'utf-8'}))
// 上傳至OSS
let OSS = require('ali-oss');
function upToOss() {
let client = new OSS({
region: 'oss-cn-shenzhen',
accessKeyId: 'your accessKeyId',
accessKeySecret: 'your accessKeySecret'
});
client.useBucket('your bucketName');
let ossBasePath = `apk`
put(`${ossBasePath}/app-release.apk`, 'platforms/android/app/build/outputs/apk/release/app-release.apk')
put(`${ossBasePath}/apks/${app.versionName}/app-release.apk`, 'platforms/android/app/build/outputs/apk/release/app-release.apk')
put(`${ossBasePath}/apks/${app.versionName}/output.json`, 'platforms/android/app/build/outputs/apk/release/output.json')
put(`webview/vod.html`, 'src/hybrid/html/vod.html')
put(`${ossBasePath}/app.json`, 'app.json')
async function put (ossPath, localFile) {
try {
await client.put(ossPath, localFile);
console.log(`${localFile}上傳成功:${ossPath}`);
} catch (err) {
console.log(err);
}
}
}
upToOss()
console.log('====================');
console.log('更新完畢,newVersion:' + app.versionName + "." + app.versionCode);
console.log('====================');
以上打包腳本,做了以下作業:
- 驗證版本號和版本名是否正確,如果不正確,終止腳本
- 修改當前APP版本名
- 生成APP打包資源
- 打包Android APP(擴展名apk)
- 上傳apk到OSS
一鍵式操作,打包為apk只需要執行:
yarn apk
安裝更新
我們看看plus.runtime.install的官方檔案:
void plus.runtime.install(filePath, options, installSuccessCB, installErrorCB);
支持以下型別安裝包:
- 應用資源安裝包(wgt),擴展名為'.wgt';
- 應用資源差量升級包(wgtu),擴展名為'.wgtu';
- 系統程式安裝包(apk),要求使用當前平臺支持的安裝包格式, 注意:僅支持本地地址,呼叫此方法前需把安裝包從網路地址或其他位置放置到運行時環境可以訪問的本地目錄,
知道了呼叫方式就好辦了,我們封裝一個檢測更新的方法:
class Utils {
...
// 獲取APP版本資訊
getVersion() {
let {versionName, versionCode} = manifest
return {
versionName,
versionCode,
version: `${versionName}.${versionCode}`
}
}
// 檢測更新
detectionUpdate(needRestartHotTip = false, needRestartFullTip = false) {
return new Promise(async (resolve, reject) => {
let appInfo = this.getVersion()
uni.request({
url: 'https://xxx.oss.com/apk/app.json',
success: async (result) => {
let { versionCode, versionName, appPath, wgtPath } = result.data
let versionInfo = {
appPath,
wgtPath,
newestVersion: `${versionName}.${versionCode}`,
newestVersionCode: versionCode,
newestVersionName: versionName,
currentVersion: appInfo.version,
currentVersionCode: appInfo.versionCode,
currentVersionName: appInfo.versionName
}
// 判斷版本名是否一致
try {
if (versionName === appInfo.versionName) {
// 如果安裝的版本號小于最新發布的版本號,則進行更新
if (appInfo.versionCode < versionCode) {
// 下載wgt更新包
if (needRestartHotTip) {
uni.showModal({
title: '提示',
content: `檢測到新版本 ${versionInfo.newestVersion} (當前版本:${versionInfo.currentVersion}),是否立即更新并重啟應用,以使更新生效?`,
success: async (res) => {
if (res.confirm) {
await this.downloadAndInstallPackage(wgtPath)
plus.runtime.restart();
resolve({code: 1, data: versionInfo})
} else if (res.cancel) {
await this.downloadAndInstallPackage(wgtPath)
resolve({code: 1, data: versionInfo})
}
}
})
} else {
await this.downloadAndInstallPackage(wgtPath)
resolve({code: 1, data: versionInfo})
}
} else {
resolve({code: 0, data: versionInfo})
console.log('你的版本為最新,不需要熱更新');
}
} else {
// 整包更新
console.log('版本名不一致,請使用整包更新');
if (needRestartFullTip) {
uni.showModal({
title: '提示',
content: `檢測到新版本 ${versionInfo.newestVersion} (當前版本:${versionInfo.currentVersion}),是否立即更新應用?`,
success: async (res) => {
if (res.confirm) {
// await this.downloadAndInstallPackage(appPath)
plus.runtime.openURL(appPath)
resolve({code: 2, data: versionInfo})
} else if (res.cancel) {}
}
})
} else {
// await this.downloadAndInstallPackage(appPath)
plus.runtime.openURL(appPath)
resolve({code: 2, data: versionInfo})
}
}
} catch (e) {
reject(e)
}
}
});
})
}
// 下載并安裝更新包
downloadAndInstallPackage(url) {
console.log('開始下載更新包:' + url)
return new Promise((resolve, reject) => {
uni.downloadFile({
url: url,
success: (downloadResult) => {
if (downloadResult.statusCode === 200) {
console.log('正在更新...');
plus.runtime.install(downloadResult.tempFilePath, {
force: true // 強制更新
}, function() {
console.log('更新成功');
resolve()
}, function(e) {
console.error('更新失敗,錯誤原因:' + JSON.stringify(e));
reject(e)
});
}
}
})
})
}
}
...
創建Utils的實體,并掛載到Vue的原型中,呼叫起來非常方便:
...
let res = await this.$utils.detectionUpdate(false, true)
if (res.code === 1) {
uni.showModal({
title: '提示',
content: `發現新的熱更新包,是否立即重啟APP以使更新生效?`,
success: async (res) => {
if (res.confirm) {
plus.runtime.restart()
} else if (res.cancel) {}
}
})
}
...
let res = await this.$utils.detectionUpdate(true, true)
if (res.code === 0) {
let {currentVersion} = res.data
uni.showModal({
title: '提示',
content: `你的APP為最新版本 ${currentVersion},不需要更新!`,
showCancel: false,
success: async (res) => {
if (res.confirm) {
} else if (res.cancel) {}
}
})
}
實戰案例代碼及程序
思路
服務器中存盤著最新版本號,前端進行查詢 可以在首次進入應用時進行請求版本號進行一個匹對 如果版本號一致則不提示,反之則提示進行更新執行更新操作
1.封裝一個對比版本號的函式
/**
* 對比版本號,如需要,請自行修改判斷規則
* 支持比對 ("3.0.0.0.0.1.0.1", "3.0.0.0.0.1") ("3.0.0.1", "3.0") ("3.1.1", "3.1.1.1") 之類的
* @param {Object} v1
* @param {Object} v2
* v1 > v2 return 1
* v1 < v2 return -1
* v1 == v2 return 0
*/
function compare(v1 = '0', v2 = '0') {
v1 = String(v1).split('.')
v2 = String(v2).split('.')
const minVersionLens = Math.min(v1.length, v2.length);
let result = 0;
for (let i = 0; i < minVersionLens; i++) {
const curV1 = Number(v1[i])
const curV2 = Number(v2[i])
if (curV1 > curV2) {
result = 1
break;
} else if (curV1 < curV2) {
result = -1
break;
}
}
if (result === 0 && (v1.length !== v2.length)) {
const v1BiggerThenv2 = v1.length > v2.length;
const maxLensVersion = v1BiggerThenv2 ? v1 : v2;
for (let i = minVersionLens; i < maxLensVersion.length; i++) {
const curVersion = Number(maxLensVersion[i])
if (curVersion > 0) {
v1BiggerThenv2 ? result = 1 : result = -1
break;
}
}
}
return result;
}
2.封裝更新函式
var updateUseModal = (packageInfo) => {
const {
title, // 標題
contents, // 升級內容
is_mandatory, // 是否強制更新
url, // 安裝包下載地址
platform, // 安裝包平臺
type // 安裝包型別
} = packageInfo;
let isWGT = type === 'wgt'
let isiOS = !isWGT ? platform.includes('iOS') : false;
let confirmText = isiOS ? '立即跳轉更新' : '立即下載更新'
return uni.showModal({
title,
content: contents,
showCancel: !is_mandatory,
confirmText,
success: res => {
if (res.cancel) return;
// 安裝包下載
if (isiOS) {
plus.runtime.openURL(url);
return;
}
let waiting = plus.nativeUI.showWaiting("正在下載 - 0%");
// uni.showLoading({
// title: '安裝包下載中'
// });
// wgt 和 安卓下載更新
const downloadTask = uni.downloadFile({
url,
success: res => {
if (res.statusCode !== 200) {
console.error('下載安裝包失敗', err);
return;
}
// 下載好直接安裝,下次啟動生效
plus.runtime.install(res.tempFilePath, {
force: false
}, () => {
uni.hideLoading()
if (is_mandatory) {
//更新完重啟app
plus.runtime.restart();
return;
}
uni.showModal({
title: '安裝成功是否重啟?',
success: res => {
if (res.confirm) {
//更新完重啟app
plus.runtime.restart();
}
}
});
}, err => {
uni.hideLoading()
uni.showModal({
title: '更新失敗',
content: err.message,
showCancel: false
});
});
},
//介面呼叫結束
complete: ()=>{
uni.hideLoading();
downloadTask.offProgressUpdate();//取消監聽加載進度
}
});
//監聽下載進度
downloadTask.onProgressUpdate(res => {
// state.percent = res.progress;
waiting.setTitle("正在下載 - "+res.progress+"%");
// console.log('下載進度百分比:' + res.progress); // 下載進度百分比
// console.log('已經下載的資料長度:' + res.totalBytesWritten); // 已經下載的資料長度,單位 Bytes
// console.log('預期需要下載的資料總長度:' + res.totalBytesExpectedToWrite); // 預期需要下載的資料總長度,單位 Bytes
});
}
});
}
3.用變數接收實作函式(在函式中使用上方封裝的函式)并匯出
fRequestWithToken為我封裝的請求方法,可自行進行使用axios進行請求也行!!!
var fCheckVersion = (cb) => {
// #ifdef APP-PLUS
plus.runtime.getProperty(plus.runtime.appid, function(widgetInfo) {
// console.log(widgetInfo.version)
// console.log(plus.runtime.version)
// console.log(widgetInfo.version)
var nVerSta = compare(plus.runtime.version, widgetInfo.version),
sLaststVer = plus.runtime.version;
if (widgetInfo.version) {
if (nVerSta == 1) {
console.log(plus.runtime.version)
sLaststVer = plus.runtime.version
} else if (nVerSta == -1) {
console.log(widgetInfo.version)
sLaststVer = widgetInfo.version
}
}
console.log(sLaststVer)
//發送請求進行匹對,我這里資料庫設定的是如果回傳null則版本號一致,反之需要更新!!!
fRequestWithToken({
ajaxOpts: {
url: URLS_COM.d_lastVer,
data: {
versionCode: sLaststVer
}
},
showloading: false,
silence:true
}).then(data =https://www.cnblogs.com/smileZAZ/archive/2022/10/27/> {
console.log(data)
// console.log('################')
if (data) {
var sUrl = '',
type = '';
if (data.wgtName) {
sUrl = data.wgtName;
type = "wgt"
} else {
sUrl = data.pkgName;
type = "pkg";
}
updateUseModal({
title: data.title||"",
contents: data.note||'',
is_mandatory: true,
url: sUrl,
platform: 'android',
type: type // 安裝包型別
})
}
}).catch((res)=>{
cb&&cb()
console.log(res)
})
})
// #endif
}
export {
fCheckVersion
}
使用
可在App.vue中進行使用,根據專案需求而定
1.引入封裝好的函式
路徑自己記得填寫自己封裝的位置
import{fCheckVersion} from '@/common/project/checkversion.js'
2.然后可以在onLoad函式中進行觸發
onLoad() {
fCheckVersion();//檢查更新
}
這樣就實作了熱更新
然后的話只需要進行打包個熱更新的包

后端進行上傳至服務器進行更新資料
本地再進行一個云打包,記得在mainifest.json檔案中進行版本號的修改,修改成低于熱更新包的版本號即可

本文部分內容轉載于:
https://blog.csdn.net/m_xiaozhilei/article/details/126485684
如果對您有所幫助,歡迎您點個關注,我會定時更新技術檔案,大家一起討論學習,一起進步,

轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/521921.html
標籤:其他
