主頁 > 移動端開發 > uniapp熱更新和整包更新思路

uniapp熱更新和整包更新思路

2022-10-28 07:53:00 移動端開發

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

我們知道,在打包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

注意事項:

保證以上檔案的versionNameversionCode均保持一致,

熱更新核心代碼

以下為熱更新的核心代碼:

// #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進行安裝,

更新介面

實際上,在這之前,我們還需要判斷是否需要更新,這就涉及到介面的部分,在此,只講講思路:

  1. 獲取安裝的版本名、版本號等資訊,將其當做引數呼叫對應的更新介面;
  2. 介面取到這些資訊,與最新版本進行對比,如果版本已經更新,回傳需要更新的資訊;
  3. 介面可以自行約定,怎么方便這么來,

我自己做的話,根本沒寫什么介面,只是創建了一個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('====================');

以上打包腳本,做了以下作業:

  1. 驗證版本號和版本名是否正確,如果不正確,終止腳本
  2. 修改當前APP版本號
  3. 生成APP打包資源
  4. 將打包資源做成zip包(擴展名改為wgt)
  5. 上傳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('====================');

以上打包腳本,做了以下作業:

  1. 驗證版本號和版本名是否正確,如果不正確,終止腳本
  2. 修改當前APP版本名
  3. 生成APP打包資源
  4. 打包Android APP(擴展名apk)
  5. 上傳apk到OSS

一鍵式操作,打包為apk只需要執行:

yarn apk

安裝更新

我們看看plus.runtime.install的官方檔案:

void plus.runtime.install(filePath, options, installSuccessCB, installErrorCB);

支持以下型別安裝包:

  1. 應用資源安裝包(wgt),擴展名為'.wgt';
  2. 應用資源差量升級包(wgtu),擴展名為'.wgtu';
  3. 系統程式安裝包(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

標籤:其他

上一篇:廣告內容定向分級,保護未成年人身心健康

下一篇:如何寫輸出PowerShell行程物件的ExitCode?[復制]

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 【從零開始擼一個App】Dagger2

    Dagger2是一個IOC框架,一般用于Android平臺,第一次接觸的朋友,一定會被搞得暈頭轉向。它延續了Java平臺Spring框架代碼碎片化,注解滿天飛的傳統。嘗試將各處代碼片段串聯起來,理清思緒,真不是件容易的事。更不用說還有各版本細微的差別。 與Spring不同的是,Spring是通過反射 ......

    uj5u.com 2020-09-10 06:57:59 more
  • Flutter Weekly Issue 66

    新聞 Flutter 季度調研結果分享 教程 Flutter+FaaS一體化任務編排的思考與設計 詳解Dart中如何通過注解生成代碼 GitHub 用對了嗎?Flutter 團隊分享如何管理大型開源專案 插件 flutter-bubble-tab-indicator A Flutter librar ......

    uj5u.com 2020-09-10 06:58:52 more
  • Proguard 常用規則

    介紹 Proguard 入口,如何查看輸出,如何使用 keep 設定入口以及使用實體,如何配置壓縮,混淆,校驗等規則。

    ......

    uj5u.com 2020-09-10 06:59:00 more
  • Android 開發技術周報 Issue#292

    新聞 Android即將獲得類AirDrop功能:可向附近設備快速分享檔案 谷歌為安卓檔案管理應用引入可安全隱藏資料的Safe Folder功能 Android TV新主界面將顯示電影、電視節目和應用推薦內容 泄露的Android檔案暗示了傳說中的谷歌Pixel 5a與折疊屏新機 谷歌發布Andro ......

    uj5u.com 2020-09-10 07:00:37 more
  • AutoFitTextureView Error inflating class

    報錯: Binary XML file line #0: Binary XML file line #0: Error inflating class xxx.AutoFitTextureView 解決: <com.example.testy2.AutoFitTextureView android: ......

    uj5u.com 2020-09-10 07:00:41 more
  • 根據Uri,Cursor沒有獲取到對應的屬性

    Android: 背景:呼叫攝像頭,拍攝視頻,指定保存的地址,但是回傳的Cursor檔案,只有名稱和大小的屬性,沒有其他諸如時長,連ID屬性都沒有 使用 cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DURATIO ......

    uj5u.com 2020-09-10 07:00:44 more
  • Android連載29-持久化技術

    一、持久化技術 我們平時所使用的APP產生的資料,在記憶體中都是瞬時的,會隨著斷電、關機等丟失資料,因此android系統采用了持久化技術,用于存盤這些“瞬時”資料 持久化技術包括:檔案存盤、SharedPreference存盤以及資料庫存盤,還有更復雜的SD卡記憶體儲。 二、檔案存盤 最基本存盤方式, ......

    uj5u.com 2020-09-10 07:00:47 more
  • Android Camera2Video整合到自己專案里

    背景: Android專案里呼叫攝像頭拍攝視頻,原本使用的 MediaStore.ACTION_VIDEO_CAPTURE, 后來因專案需要,改成了camera2 1.Camera2Video 官方demo有點問題,下載后,不能直接整合到專案 問題1.多次拍攝視頻崩潰 問題2.雙擊record按鈕, ......

    uj5u.com 2020-09-10 07:00:50 more
  • Android 開發技術周報 Issue#293

    新聞 谷歌為Android TV開發者提供多種新功能 Android 11將自動填表功能整合到鍵盤輸入建議中 谷歌宣布Android Auto即將支持更多的導航和數字停車應用 谷歌Pixel 5只有XL版本 搭載驍龍765G且將比Pixel 4更便宜 [圖]Wear OS將迎來重磅更新:應用啟動時間 ......

    uj5u.com 2020-09-10 07:01:38 more
  • 海豚星空掃碼投屏 Android 接收端 SDK 集成 六步驟

    掃碼投屏,開放網路,獨占設備,不需要額外下載軟體,微信掃碼,發現設備。支持標準DLNA協議,支持倍速播放。視頻,音頻,圖片投屏。好點意思。還支持自定義基于 DLNA 擴展的操作動作。好像要收費,沒體驗。 這里簡單記錄一下集成程序。 一 跟目錄的build.gradle添加私有mevan倉庫 mave ......

    uj5u.com 2020-09-10 07:01:43 more
最新发布
  • 歡迎頁輪播影片

    如圖,引導開始,球從上落下,同時淡入文字,然后文字開始輪播,最后一頁時停止,點擊進入首頁。 在來看看效果圖。 重力球先不講,主要歡迎輪播簡單實作 首先新建一個類 TextTranslationXGuideView,用于影片展示 文本是類似的,最后會有個圖片箭頭影片,布局很簡單,就是一個 TextVi ......

    uj5u.com 2023-04-20 08:40:31 more
  • 【FAQ】關于華為推送服務因營銷訊息頻次管控導致服務通訊類訊息

    一. 問題描述 使用華為推送服務下發IM訊息時,下發訊息請求成功且code碼為80000000,但是手機總是收不到訊息; 在華為推送自助分析(Beta)平臺查看發現,訊息發送觸發了頻控。 二. 問題原因及背景 2023年1月05日起,華為推送服務對咨詢營銷類訊息做了單個設備每日推送數量上限管理,具體 ......

    uj5u.com 2023-04-20 08:40:11 more
  • 歡迎頁輪播影片

    如圖,引導開始,球從上落下,同時淡入文字,然后文字開始輪播,最后一頁時停止,點擊進入首頁。 在來看看效果圖。 重力球先不講,主要歡迎輪播簡單實作 首先新建一個類 TextTranslationXGuideView,用于影片展示 文本是類似的,最后會有個圖片箭頭影片,布局很簡單,就是一個 TextVi ......

    uj5u.com 2023-04-20 08:39:36 more
  • 【FAQ】關于華為推送服務因營銷訊息頻次管控導致服務通訊類訊息

    一. 問題描述 使用華為推送服務下發IM訊息時,下發訊息請求成功且code碼為80000000,但是手機總是收不到訊息; 在華為推送自助分析(Beta)平臺查看發現,訊息發送觸發了頻控。 二. 問題原因及背景 2023年1月05日起,華為推送服務對咨詢營銷類訊息做了單個設備每日推送數量上限管理,具體 ......

    uj5u.com 2023-04-20 08:39:13 more
  • iOS從UI記憶體地址到讀取成員變數(oc/swift)

    開發除錯時,我們發現bug時常首先是從UI顯示發現例外,下一步才會去定位UI相關連的資料的。XCode有給我們提供一系列debug工具,但是很多人可能還沒有形成一套穩定的除錯流程,因此本文嘗試解決這個問題,順便提出一個暴論:UI顯示例外問題只需要兩個步驟就能完成定位作業的80%: 定位例外 UI 組 ......

    uj5u.com 2023-04-19 09:16:23 more
  • FIDE重磅更新!性能飛躍!體驗有禮!

    FIDE 開發者工具重構升級啦!實作500%性能提升,誠邀體驗! 一直以來不少開發者朋友在社區反饋,在使用 FIDE 工具的程序中,時常會遇到諸如加載不及時、代碼預覽/渲染性能不如意的情況,十分影響開發體驗。 作為技術團隊,我們深知一件趁手的開發工具對開發者的重要性,因此,在2023年開年,FinC ......

    uj5u.com 2023-04-19 09:16:15 more
  • 游戲內嵌社區服務開放,助力開發者提升玩家互動與留存

    華為 HMS Core 游戲內嵌社區服務提供快速訪問華為游戲中心論壇能力,支持玩家直接在游戲內瀏覽帖子和交流互動,助力開發者擴展內容生產和觸達的場景。 一、為什么要游戲內嵌社區? 二、游戲內嵌社區的典型使用場景 1、游戲內打開論壇 您可以在游戲內繪制論壇入口,為玩家提供沉浸式發帖、瀏覽、點贊、回帖、 ......

    uj5u.com 2023-04-19 09:15:46 more
  • iOS從UI記憶體地址到讀取成員變數(oc/swift)

    開發除錯時,我們發現bug時常首先是從UI顯示發現例外,下一步才會去定位UI相關連的資料的。XCode有給我們提供一系列debug工具,但是很多人可能還沒有形成一套穩定的除錯流程,因此本文嘗試解決這個問題,順便提出一個暴論:UI顯示例外問題只需要兩個步驟就能完成定位作業的80%: 定位例外 UI 組 ......

    uj5u.com 2023-04-19 09:14:53 more
  • FIDE重磅更新!性能飛躍!體驗有禮!

    FIDE 開發者工具重構升級啦!實作500%性能提升,誠邀體驗! 一直以來不少開發者朋友在社區反饋,在使用 FIDE 工具的程序中,時常會遇到諸如加載不及時、代碼預覽/渲染性能不如意的情況,十分影響開發體驗。 作為技術團隊,我們深知一件趁手的開發工具對開發者的重要性,因此,在2023年開年,FinC ......

    uj5u.com 2023-04-19 09:14:08 more
  • 游戲內嵌社區服務開放,助力開發者提升玩家互動與留存

    華為 HMS Core 游戲內嵌社區服務提供快速訪問華為游戲中心論壇能力,支持玩家直接在游戲內瀏覽帖子和交流互動,助力開發者擴展內容生產和觸達的場景。 一、為什么要游戲內嵌社區? 二、游戲內嵌社區的典型使用場景 1、游戲內打開論壇 您可以在游戲內繪制論壇入口,為玩家提供沉浸式發帖、瀏覽、點贊、回帖、 ......

    uj5u.com 2023-04-19 09:08:34 more