目录
一.关于版本更新和热更新
版本更新也称为整包更新,是指下载并安装最新的apk文件,实现app的整包更新
热更新是指将包打为wgt文件,不进行整包安装并实现app更新
效果图
二.实现逻辑
1.打包
配置 manifest.json 文件,修改版本号和版本名称
2.上传最新的包文件
整包更新:最新的apk文件需要上传至web端并维护版本信息
热更新:生成的wgt文件需要上传至web端并维护版本信息
注:需前后端联调
3.uniapp内的实现逻辑
1.版本更新样式弹窗(可手写也可网上复制,我是手写的因为灵活性好一些)
2.调用接口检查是否需要更新(时机:登录后、我的页面手动点击检查更新)
3.若需要更新,弹出弹窗并展示更新内容,若无更新可弹出 ‘已是最新版本’ 弹窗也可无弹窗操作
4.需要更新的情况下,后端返回更新文件的路径,uni.downloadFile下载最新的包文件并重启或者安装最新的app
5.uploadTask.onProgressUpdate可监听下载进度,用于弹窗展示
4.代码部分
DOM部分(弹窗)
<!-- 版本信息弹窗 -->
<u-popup mode="center" round='15' :show="show">
<view v-if="versionsFlag === 1">
<view>
<image src="../../../static/update2.png" mode="aspectFill" style="width: 100%;height: 100%;">
</image>
</view>
<view>
{{updateType === 1?'最新资源包':'发现新版本'}} V{{version}}
</view>
<view>
<view>更新内容</view>
<view>
<u-textarea disabled v-model="apkUpdateContent" style="background-color: transparent;"
border="none"></u-textarea>
</view>
</view>
<view>
<view @click="updateNow">立即更新</view>
<view @click="show = false">暂不更新</view>
</view>
</view>
<view v-if="versionsFlag === 2">
<view>
<image src="../../../static/update2.png" mode="aspectFill" style="width: 100%;height: 100%;">
</image>
</view>
<view>已是最新版本</view>
<view>
<view>版本信息</view>
<view>{{latestVersionInfo}}</view>
</view>
<view>
<view @click="show = false">关闭</view>
</view>
</view>
<view v-if="versionsFlag === 3">
<view>
<image src="../../../static/update2.png" mode="aspectFill" style="width: 100%;height: 100%;">
</image>
</view>
<view>正在下载,请稍后 </view>
<view>
<u-line-progress height="50rpx" :percentage="updateProgress"
activeColor="#409eff"></u-line-progress>
</view>
<view v-if="restartFlag">重启APP,请稍后</view>
</view>
</u-popup>
data部分
// 版本更新相关
version: '', //版本名称
versionCode: '', //版本号
apkUpdateContent: '', //更新内容说明
updateType: '', //1资源包更新2版本更新
versionsFlag: 1, //1需要更新弹窗2已是最新版本弹窗3正在下载
latestVersionInfo: '', //已是最新版本弹窗内容
updateAPKPath: '', //下载文件路径
updateProgress: '', //下载进度
restartFlag: false,
show: false
js部分(需前后端联调)
update() {
let _this = this
let platform = uni.getSystemInfoSync().platform
let server = '***********************'
let signServer = '***********************'
// 当前版本信息
plus.runtime.getProperty(plus.runtime.appid, (info) => {
let version = info.version; //版本名称
let versionCode = info.versionCode; //版本号
uni.request({
url: signServer,
method: 'POST',
data: {
apkVersionName: version, //版本名称
apkVersion: versionCode, //版本号
},
success: (res) => {
let sign = res.data.result
uni.request({
url: server,
method: 'POST',
data: {
// appId: appid, // 应用AppID(唯一标识)
apkVersionName: version, //版本名称
apkVersion: versionCode, //版本号
sign: sign // 签名
},
success: (res) => {
if (res.statusCode == 200) {
if (res.data.code == 200) {
// 最新版本
_this.version = res.data.result.apkVersionName
// 版本更新内容
_this.apkUpdateContent = res.data.result.apkUpdateContent
let path = process.uniEnv.FILE_PREVIEW_URL +'/' + res.data.result.bucket + '/' + res.data.result.apkPath
// 更新文件路径
_this.updateAPKPath = path
// 资源包更新
if (res.data.result.hotUpdate === 1) {
// 打开更新弹框
_this.versionsFlag = 1
_this.updateType = 1
_this.show = true
// 整包更新
} else if (res.data.result.hotUpdate === 0 &&
res.data.result.apkPath) {
// 打开更新弹框
_this.versionsFlag = 1
_this.updateType = 2
_this.show = true
} else{
_this.versionsFlag = 2
_this.show = true
}
} else if (res.data.code == 500) {
// uni.showToast({
// title: res.data.message,
// icon: 'none'
// })
_this.latestVersionInfo = res.data.message
_this.versionsFlag = 2
// _this.show = true
// plus.nativeUI.toast(res.data.message)
}
} else {
uni.showToast({
title: '更新失败(获取签名失败)',
icon: 'none'
})
}
},
fail: (res) => {
console.log('fail', res);
}
})
},
fail: (res) => {
console.log('fail', res);
}
})
})
},
//弹窗点击确认更新以后
updateNow() {
let _this = this
_this.versionsFlag = 3
const uploadTask = uni.downloadFile({ // 下载apk/资源包
url: _this.updateAPKPath,
success: (downloadResult) => {
console.log(downloadResult);
if (downloadResult.statusCode === 200) {
uni.clearStorage()
plus.runtime.install(downloadResult.tempFilePath, {
force: true
},
function() {
plus.runtime.restart(); // 重启APP
},
function(e) {
_this.show = false
uni.showToast({
title: e.message,
icon: 'none'
})
});
} else {
_this.show = false
if (_this.updateType === 1) {
uni.showToast({
title: '资源包下载失败',
duration: 2000,
icon: 'error'
})
} else {
uni.showToast({
title: 'APK下载失败',
duration: 2000,
icon: 'error'
})
}
}
}
});
//监听下载进度
uploadTask.onProgressUpdate((res) => {
_this.updateProgress = res.progress
if (_this.updateType === 1) {
if (res.progress > 95) {
_this.restartFlag = true
}
}
});
},