一、要解决的问题:
实现app内部静默更新。
二、要实现这个功能必须解决以下情况:
1、app内部如何检测更新了
2、检测到更新了之后如何获取新的资源下载链接
3、拿到资源后如何在内部安装
三、操作方式:
1、首次使用的打包方式uniapp+Android Studio(可以自行去uniapp的官网进行查阅)打包成apk文件,至于不用uniapp打包的原因就是排队太麻烦。
2、其后更新只需要打包为wgt文件即可在app内部安装
四、具体实现:
1、首先在后台管理系统定义一个版本、一个资源下载链接和版本更新的内容三个参数
2、在App.vue中调用接口进行一个版本的比对,如何版本不一致则跳转至更新页进行更新
/**
* 通过参数设置获取最新版本信息
*/
getVersion() {
const _this = this;
uni.$u.api
.getParameterApi({
key: 'parking.operation.version'
})
.then(res => {
if (res.code === 200) {
this.version = res.msg
if (res.msg !== config.version) {
uni.$u.route({
url: 'pages/appUpdate/appUpdate',
params: {
downloadUrl: this.downloadUrl, // 和版本一样通过参数获取下载链接
version: this.version
}
})
}
}
});
}
3、更新页处理
<template>
<view class="page-height">
<view class="page-content">
<view class="wrap" v-if="popup_show">
<view class="popup-bg">
<view class="popup-content" :class="{ 'popup-content-show': popup_show }">
<view class="update-wrap">
<image src="/static/images/img.png" class="top-img"></image>
<view class="content">
<text class="title">发现新版本V{{ updateInfo.version }}</text>
<!-- 升级描述 -->
<view class="title-sub" v-html="updateInfo.note"></view>
<!-- 操作按钮 -->
<view class="operation-btn" v-if="downstatus < 1">
<button class="btn cancel" @click="cancel()">暂不升级</button>
<button class="btn" @click="onUpdate()">立即升级</button>
</view>
<!-- 下载进度 -->
<view class="sche-wrap" v-else>
<!-- 更新包下载中 -->
<view class="sche-bg">
<view class="sche-bg-jindu" :style="lengthWidth"></view>
</view>
<text class="down-text">下载进度:{{ (downSize / 1024 / 1024).toFixed(2) }}M/{{ (fileSize / 1024 / 1024).toFixed(2) }}M</text>
</view>
</view>
</view>
<image src="/static/images/close.png" class="close-ioc" @click="closeUpdate()" v-if="downstatus < 1 && updateInfo.force == 0"></image>
</view>
</view>
</view>
</view>
</view>
</template>
<script>
import { config } from '@/common/config.js';
export default {
data() {
return {
popup_show: true,
updateInfo: {
note: '',
version: '',
downloadUrl: ''
}, //上一页面传过来的升级参数
note: [], //升级说明数组格式
fileSize: 0, //文件大小
downSize: 0, //已下载大小
downing: false, //是否下载中
downstatus: 0 //0未下载 1已开始 2已连接到资源 3已接收到数据 4下载完成
};
},
onLoad(option) {
this.updateInfo.version = option.version;
this.updateInfo.downloadUrl = option.downloadUrl;
},
onBackPress(e) {
if (e.from == 'backbutton') return true; //APP安卓物理返回键逻辑
},
computed: {
// 下载进度计算
lengthWidth: function () {
let w = (this.downSize / this.fileSize) * 100;
if (!w) {
w = 0;
} else {
w = w.toFixed(2);
}
return {
width: w + '%' //return 宽度半分比
};
},
getHeight: function () {
let bottom = 0;
if (this.tabbar) {
bottom = 50;
}
return {
bottom: bottom + 'px',
height: 'auto'
};
}
},
methods: {
// 当点击更新时
onUpdate() {
//判断是否为wifi模式
uni.getNetworkType({
success: (res) => {
if (res.networkType == 'wifi') {
this.startUpdate(); //开始更新
} else {
uni.showModal({
title: '提示',
content: '当前网络非WIFI,继续更新可能会产生流量,确认要更新吗?',
success: (modal_res) => {
if (modal_res.confirm) {
this.startUpdate(); //开始更新
}
}
});
}
}
});
},
/**
* 取消升级
*/
cancel() {
uni.$u.route({
type: 'back',
delta: 1
});
},
//开始更新
startUpdate() {
if (this.downing) return false; //如果正在下载就停止操作
this.downing = true; //状态改变 正在下载中
if (/\.wgt$/.test(this.updateInfo.downloadUrl)) {
// 如果是更新包
this.download_wgt(); // 安装包/升级包更新
} else {
plus.runtime.openURL(this.updateInfo.downloadUrl, function () {
//调用外部浏览器打开更新地址
plus.nativeUI.toast('打开错误');
});
}
},
// 下载升级资源包
download_wgt() {
plus.nativeUI.showWaiting('下载更新文件...'); //下载更新文件...
let options = {
method: 'get'
};
let dtask = plus.downloader.createDownload(this.updateInfo.downloadUrl, options);
dtask.addEventListener('statechanged', (task, status) => {
if (status === null) {
} else if (status == 200) {
//在这里打印会不停的执行,请注意,正式上线切记不要在这里打印东西!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
this.downstatus = task.state;
switch (task.state) {
case 3: // 已接收到数据
plus.nativeUI.closeWaiting();
this.downSize = task.downloadedSize;
if (task.totalSize) {
this.fileSize = task.totalSize; //服务器须返回正确的content-length才会有长度
}
break;
case 4:
this.installWgt(task.filename); // 安装
break;
}
} else {
plus.nativeUI.closeWaiting();
plus.nativeUI.toast('下载出错');
this.downing = false;
this.downstatus = 0;
}
});
dtask.start();
},
// 安装文件
installWgt(path) {
plus.nativeUI.showWaiting('安装更新文件...'); //安装更新文件...
plus.runtime.install(
path,
{
force: true
},
function () {
plus.nativeUI.closeWaiting();
// 应用资源下载完成!
plus.nativeUI.alert('更新完成,请重启APP!', function () {
plus.runtime.restart(); //重启APP
});
},
function (e) {
plus.nativeUI.closeWaiting();
// 安装更新文件失败
plus.nativeUI.alert('安装更新文件失败[' + e.code + ']:' + e.message);
}
);
}
}
};
</script>
<style lang="scss" scoped>
.page-height {
height: 100vh;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
background-color: rgba($color: #000000, $alpha: 0.7);
}
.popup-bg {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
width: 750rpx;
}
.popup-content {
display: flex;
flex-direction: column;
align-items: center;
}
.popup-content-show {
animation: mymove 300ms;
transform: scale(1);
}
@keyframes mymove {
0% {
transform: scale(0);
/*开始为原始大小*/
}
100% {
transform: scale(1);
}
}
.update-wrap {
width: 580rpx;
border-radius: 18rpx;
position: relative;
display: flex;
flex-direction: column;
background-color: #ffffff;
padding: 170rpx 30rpx 0;
.top-img {
position: absolute;
left: 0;
width: 100%;
height: 256rpx;
top: -128rpx;
}
.content {
display: flex;
flex-direction: column;
align-items: center;
padding-bottom: 40rpx;
.title {
font-size: 32rpx;
font-weight: bold;
color: #6526f3;
}
.title-sub {
text-align: center;
font-size: 24rpx;
color: #666666;
padding: 30rpx 0;
}
.operation-btn {
width: 100%;
display: flex;
justify-content: space-between;
align-items: center;
}
.btn {
width: 200rpx;
display: flex;
align-items: center;
justify-content: center;
color: #ffffff;
font-size: 30rpx;
height: 80rpx;
line-height: 80rpx;
border-radius: 100px;
background-color: #6526f3;
margin-top: 20rpx;
}
.cancel {
background-color: #cccccc;
color: #6526f3;
}
}
}
.close-ioc {
width: 70rpx;
height: 70rpx;
margin-top: 30rpx;
}
.sche-wrap {
display: flex;
flex-direction: column;
align-items: center;
justify-content: flex-end;
padding: 10rpx 50rpx 0;
.sche-wrap-text {
font-size: 24rpx;
color: #666;
margin-bottom: 20rpx;
}
.sche-bg {
position: relative;
background-color: #cccccc;
height: 30rpx;
border-radius: 100px;
width: 480rpx;
display: flex;
align-items: center;
.sche-bg-jindu {
position: absolute;
left: 0;
top: 0;
height: 30rpx;
min-width: 40rpx;
border-radius: 100px;
background: url(/static/images/round.png) #6526f3 center right 4rpx no-repeat;
background-size: 26rpx 26rpx;
}
}
.down-text {
font-size: 24rpx;
color: #6526f3;
margin-top: 16rpx;
}
}
</style>
4、在manifest.json配置应用安装权限(这两个权限是必须的,否则没有安装应用权限)
"<uses-permission android:name=\"android.permission.INSTALL_PACKAGES\"/>",
"<uses-permission android:name=\"android.permission.REQUEST_INSTALL_PACKAGES\"/>",
5、这样一个app应用的静默更新就完成了
希望大佬看到有不对的地方,提出博主予以改正!