uniapp熱更新和整包更新思路

来源:https://www.cnblogs.com/smileZAZ/archive/2022/10/27/16832534.html
-Advertisement-
Play Games

這裡給大家分享我在網上總結出來的一些知識,希望對大家有所幫助 我們知道,在打包Android App之前,我們需要先通過HX生成打包資源。如果是通過cli創建的項目,則通過以下命令生成打包資源: yarn build:app-plus 生成打包資源後的目錄長這樣: 然後將整個目錄中的所有文件拷貝到A ...


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

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

如果對您有所幫助,歡迎您點個關註,我會定時更新技術文檔,大家一起討論學習,一起進步。

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 作用: 藉助於防火牆標記來分類報文,而後基於標記定義集群服務;可將多個不同的應用使用同一個集群服務進行調度 實現方法: 添加防火牆標記 基於標記定義集群服務 在lvs主機上添加防火牆標記: 將lvs的多個埠號通過防火牆貼上同樣的標簽,多個埠號對應一個服務。 iptables -t mangle ...
  • 記CentOS7的httpd源碼包安裝的實驗過程 註:以下純屬本人(小白)見解,如有錯誤請求各位大佬幫忙指正。新人寫博有啥錯誤也麻煩各位大佬給個指點。 作者:lonely-sail 相關下載: httpd依賴包:apr、apr-util(官網下載:http://apr.apache.org/)、pc ...
  • 架構圖: 多網段: 客戶機位於192.168.10.x/24網段 RS位於:10.0.0.x/24網段 VIP:位於172.16.0.x/24網關 通信過程: 客戶機(CIP) >lvs(VIP) >lvs(DIP) >RS(RIP) >客戶機(CIP) 說明: DR模式要求每個RS都擁有和lvs一 ...
  • 架構圖: 環境: 一臺:客戶端 eth0:僅主機 192.168.10.6/24 GW:192.168.10.200 一臺:ROUTER eth0 :NAT 10.0.0.200/24 eth1: 僅主機 192.168.10.200/24 啟用 IP_FORWARD 一臺:LVS eth0:NAT ...
  • 一、前言 作為全鏈路數字化技術與服務提供商,袋鼠雲提供了從數據湖、大數據基礎平臺、離線開發、實時開發、數據服務、數據治理、指標管理、客戶數據洞察、數據孿生可視化等全產品體系的服務。 圍繞著“行業應用”及“通用應用”,袋鼠雲聚焦數智提供全維數字解決方案,幫助企業實現降本增效、快捷轉型,迄今為止袋鼠雲已 ...
  • 摘要:華為雲資料庫創新Lab在論文《MARINA: An MLP-Attention Model for Multivariate Time-Series Analysis》中提出了華為自研的自回歸時序神經網路模型,可用於時序數據的預測以及異常檢測。 本文分享自華為雲社區《CIKM'22 MARIN ...
  • openeuler安裝教程 1. 下載 鏡像版本:openEuler-20.03-LTS-x86_64-dvd.iso 下載地址:https://repo.openeuler.org/openEuler-20.03-LTS/ISO/x86_64/ 需要工具:vmware 2.安裝操作 完成 ...
  • 摘要:隨著offset的增加,查詢的時長也會越來越長。當offset達到百萬級別的時候查詢時長通常是業務所不能容忍的。 本文分享自華為雲社區《offset新探索:雙管齊下,加速大數據量查詢》,作者: GaussDB 資料庫 。 眾所周知,在各類業務中時常會用到LIMIT y offset x來做跳過 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...