uniapp 实现APP强更新,热更新
这里我封装了一个版本更新的组件

项目版本号在manifest.json---基础配置中查看

应用版本名称 2.1.07 这种三段式的就是大版本号,一般用于版本强制更新,比如重新安装apk包
应用版本号 2107 就是小版本号 ,一般用于热更新
下面是代码
首先在项目入口地址App.vue 界面获取设备信息,版本号信息,保存下来
onLaunch: function() {
// 获取手机设备信息
const res = uni.getSystemInfoSync();
uni.setStorageSync('platform', res.platform);
// #ifdef APP-PLUS
// 获取应用版本信息
plus.runtime.getProperty(plus.runtime.appid, function(inf) {
uni.setStorageSync('version', inf.version); // 大版本号
uni.setStorageSync('versionCode', inf.versionCode); // 小版本号
});
let uuid = plus.device.uuid;
// #endif
},
下面是强更新,热更新代码
这里是我写成了一个下载更新的组件 downloadUp.vue, 组件放在项目首页,如果版本需要更新,就会唤起组件弹窗,让用户手动强制更新,热更新的话,进入首页就自动触发了
created() {
// 获取设备是安卓还是ios
const appUpdate = uni.getStorageSync('platform');
// #ifdef APP-PLUS
this.type = appUpdate == 'android' ? 2 : 1;
this.checkUpdate(); // 判断是否需要更新
// #endif
},
checkUpdate() { const self = this, localAppVersonName = uni.getStorageSync('version'), localAppVerson = uni.getStorageSync('versionCode'); // #ifdef APP-PLUS plus.runtime.getProperty(plus.runtime.appid, function(widgetInfo) { getUpgrade({ appType: self.type }).then(res => { const { data } = res.data; if (res.data.code !== '200') return; // app大版本更新 if (data.apkVersion && comparisonVersionHandler(localAppVersonName, data.apkVersion.appVersonName)) { uni.hideTabBar() // 隐藏首页底部tabbar 按钮 self.updateApkObj = data.apkVersion; self.msg = data.apkVersion.versonLog; self.bannerShow = true; // 显示弹窗 return; // app热更新 } else if (data.wgtVersion && comparisonVersionHandler(localAppVerson, data.wgtVersion.appVerson)) { self.downloadWgt(data.wgtVersion.downloadUrl); return; } else { return; } }); }); // #endif },
comparisonVersionHandler 是判断版本号是否需要更新的方法
comparisonVersionHandler = (reqV, curV) => { /* 版本号名比较是否需要升级 curV string :当前最新 reqV string :之前 返回 true 表示需要升级 */ if (curV && reqV) { curV = String(curV); reqV = String(reqV); //将两个版本号拆成数字 let arr1 = curV.split('.'), //當前 arr2 = reqV.split('.'); let minLength = Math.min(arr1.length, arr2.length), position = 0, diff = 0; //依次比较版本号每一位大小,当对比得出结果后跳出循环 while (position < minLength && ((diff = parseInt(arr1[position]) - parseInt(arr2[position])) == 0)) { position++; } diff = (diff != 0) ? diff : (arr1.length - arr2.length); //若curV大于reqV,则返回true return diff > 0; } else { //输入为空 return false; } };
代码热更新
downloadWgt(updateWgtUrl) {
// 热更新
// 下载wgt方法
const that = this;
// 更新文件 wgt 文件地址
plus.nativeUI.showWaiting('正在更新...'); // 打开系统等待对话框
plus.downloader
.createDownload(
updateWgtUrl,
{
filename: '_doc/update/'
},
function(d, status) {
if (status == 200) {
that.installWgt(d.filename);
}
plus.nativeUI.closeWaiting(); // 关闭系统等待对话框
}
)
.start();
},
installWgt(path) {
// 安装wgt方法
plus.nativeUI.showWaiting('安装文件...');
plus.runtime.install(
path,
{ force: true },
function() {
plus.nativeUI.closeWaiting();
plus.nativeUI.alert('应用资源更新完成!', function() {
plus.runtime.restart(); // 重启APP
});
},
function(e) {
plus.nativeUI.closeWaiting();
}
);
},
強更新
goUpdate(updateApkObj) {
if (this.type == 2) { // 安卓端
// 弹出系统等待对话框
var dtask = plus.downloader.createDownload(updateApkObj.downloadUrl, {}, function(d, status) {
this.bannerShow = false;
// 下载完成
if (status == 200) {
plus.runtime.install(plus.io.convertLocalFileSystemURL(d.filename), {}, {}, function(error) {
uni.showToast({
title: '安装失败',
mask: false,
duration: 1500
});
});
} else {
uni.showToast({
title: '更新失败',
mask: false,
duration: 1500
});
}
});
try {
dtask.start(); // 开启下载的任务
let prg = 0;
const showLoading = plus.nativeUI.showWaiting('正在下载'); //创建一个showWaiting对象
dtask.addEventListener('statechanged', function(task, status) {
// 给下载任务设置一个监听 并根据状态 做操作
switch (task.state) {
case 1:
showLoading.setTitle('正在下载');
break;
case 2:
showLoading.setTitle('已连接到服务器');
break;
case 3:
prg = parseInt((parseFloat(task.downloadedSize) / parseFloat(task.totalSize)) * 100);
showLoading.setTitle(' 正在下载' + prg + '% ');
break;
case 4:
plus.nativeUI.closeWaiting();
//下载完成
break;
}
});
} catch (err) {
plus.nativeUI.closeWaiting();
uni.showToast({
title: '更新失败-03',
mask: false,
duration: 1500
});
}
} else if (this.type == 1) { // ios跳转到app store
plus.runtime.openURL(updateApkObj.downloadUrl);
}
}
下面是全部代碼
<template>
<view class="content" v-if="bannerShow">
<!-- 弹出层 -->
<view class="uni-banner">
<image src="/static/img/startUpHeader01.png" class="startUpHeaderLogo" />
<view class="banner_box">
<view class="startUpHeaderBox h6">发现新版本</view>
<view class="conter">{{ msg }}</view>
<view class="banner_foot"><button @click="goUpdate(updateApkObj)" class="banner_foot_button">前往升级</button></view>
</view>
</view>
<view class="uni-mask"></view>
</view>
</template>
<script>
import { comparisonVersionHandler } from '@/common/js/tools';
import { getUpgrade } from '@/common/js/apis';
export default {
data() {
return {
bannerShow: false, // 是否需要強制更新app
msg: '', // 更新描述
type: '', // 设备类型 android:2, ios:1
updateApkObj: null // 后台数据
};
},
created() {
const appUpdate = uni.getStorageSync('platform');
// #ifdef APP-PLUS
this.type = appUpdate == 'android' ? 2 : 1;
this.checkUpdate();
// #endif
},
methods: {
checkUpdate() {
const self = this,
localAppVersonName = uni.getStorageSync('version'),
localAppVerson = uni.getStorageSync('versionCode');
// #ifdef APP-PLUS
plus.runtime.getProperty(plus.runtime.appid, function(widgetInfo) {
getUpgrade({
appType: self.type
}).then(res => {
const { data } = res.data;
if (res.data.code !== '200') return;
// 大版本更新
if (data.apkVersion && comparisonVersionHandler(localAppVersonName, data.apkVersion.appVersonName)) {
uni.hideTabBar()
self.updateApkObj = data.apkVersion;
self.msg = data.apkVersion.versonLog;
self.bannerShow = true;
return;
// app热更新
} else if (data.wgtVersion && comparisonVersionHandler(localAppVerson, data.wgtVersion.appVerson)) {
self.downloadWgt(data.wgtVersion.downloadUrl);
return;
} else {
return;
}
});
});
// #endif
},
downloadWgt(updateWgtUrl) {
// 热更新
// 下载wgt方法
const that = this;
// 更新文件 wgt 文件地址
plus.nativeUI.showWaiting('正在更新...');
plus.downloader
.createDownload(
updateWgtUrl,
{
filename: '_doc/update/'
},
function(d, status) {
if (status == 200) {
that.installWgt(d.filename); // 安装wgt方法
}
plus.nativeUI.closeWaiting();
}
)
.start();
},
installWgt(path) {
// 安装wgt方法
plus.nativeUI.showWaiting('安装文件...');
plus.runtime.install(
path,
{ force: true },
function() {
plus.nativeUI.closeWaiting();
plus.nativeUI.alert('应用资源更新完成!', function() {
plus.runtime.restart();
});
},
function(e) {
plus.nativeUI.closeWaiting();
}
);
},
goUpdate(updateApkObj) {
if (this.type == 2) {
// 弹出系统等待对话框
var dtask = plus.downloader.createDownload(updateApkObj.downloadUrl, {}, function(d, status) {
this.bannerShow = false;
// 下载完成
if (status == 200) {
plus.runtime.install(plus.io.convertLocalFileSystemURL(d.filename), {}, {}, function(error) {
uni.showToast({
title: '安装失败',
mask: false,
duration: 1500
});
});
} else {
uni.showToast({
title: '更新失败',
mask: false,
duration: 1500
});
}
});
try {
dtask.start(); // 开启下载的任务
let prg = 0;
const showLoading = plus.nativeUI.showWaiting('正在下载'); //创建一个showWaiting对象
dtask.addEventListener('statechanged', function(task, status) {
// 给下载任务设置一个监听 并根据状态 做操作
switch (task.state) {
case 1:
showLoading.setTitle('正在下载');
break;
case 2:
showLoading.setTitle('已连接到服务器');
break;
case 3:
prg = parseInt((parseFloat(task.downloadedSize) / parseFloat(task.totalSize)) * 100);
showLoading.setTitle(' 正在下载' + prg + '% ');
break;
case 4:
plus.nativeUI.closeWaiting();
//下载完成
break;
}
});
} catch (err) {
plus.nativeUI.closeWaiting();
uni.showToast({
title: '更新失败-03',
mask: false,
duration: 1500
});
}
} else if (this.type == 1) { // ios跳转到app store
plus.runtime.openURL(updateApkObj.downloadUrl);
}
}
}
};
</script>
<style lang="scss" scoped>
.content,
#img {
width: 100%;
height: 100%;
}
.content .con {
font-size: 0;
display: flex;
align-items: center;
}
#info {
position: absolute;
top: 0;
left: 0;
width: 72rpx;
height: 72rpx;
line-height: 72rpx;
border-radius: 50%;
background-color: rgba(0, 0, 0, 0.3);
text-align: center;
color: #fff;
font-size: 24rpx;
}
.wrapper {
width: 36rpx;
height: 72rpx;
position: absolute;
top: 0;
overflow: hidden;
}
.right {
right: 0;
}
.left {
left: 0;
}
/* 弹出层形式的广告 */
.uni-banner {
display: flex;
align-items: center;
flex-direction: column;
position: fixed;
left: 50%;
top: 50%;
z-index: 1000;
transform: translate(-50%, -50%);
width: 80%;
.startUpHeaderLogo {
width: 256rpx;
height: 194rpx;
}
.banner_box {
width: 100%;
background: #fff;
border-radius: 20rpx;
}
.startUpHeaderBox {
width: 100%;
height: 96rpx;
background-image: url('/static/img/startUpHeader02.png');
background-position: left top;
background-repeat: no-repeat;
background-size: cover;
}
}
.banner_box .h6 {
text-align: center;
line-height: 96rpx;
font-size: 36rpx;
color: #fff;
font-weight: bold;
}
.banner_box .conter {
font-size: 28rpx;
color: #333;
margin: 48rpx;
}
.banner_foot {
width: 238rpx;
margin: 48rpx auto;
}
.banner_foot_button {
background-image: linear-gradient(to right, #3aaf7a, #41bf7f);
line-height: 72rpx;
height: 72rpx;
font-size: 30rpx;
color: #fff;
font-weight: bold;
border-radius: 40rpx;
border: none;
box-shadow: 0 8rpx 20rpx 0 rgba(46, 189, 88, 0.36);
}
.banner_foot_button:active {
background-image: linear-gradient(to right, #41bf7f, #3aaf7a);
}
.uni-mask {
background: rgba(0, 0, 0, 0.6);
position: fixed;
width: 100%;
height: 100%;
left: 0;
top: 0;
z-index: 2;
}
</style>

浙公网安备 33010602011771号