一、首先是uniapp 生成apk
用Hbuilder 进行打包,可以选择云打包。也可以使用自有证书,目测比直接使用云证书要快一些。
二、实现过程
1.准备update.json文件
准备update.json文件,供前端访问升级信息用。
{ "versionCode": 101, "versionName": "v1.0.1", "versionDesc": "功能优化", "appName": "android_myapp.apk", "downloadUrl": "http://111.xx.xx.xx:8000/static/release/" }
2. 客户端检查更新
在客户端,你可以使用uni.request方法来请求这个JSON文件,并对比当前版本和最新版本。如果发现新版本,提示用户更新。
export default { methods: { checkForUpdates() { const currentVersion = '1.1.0'; // 当前应用版本 uni.request({ url: 'https://your-update-server.com/update.json', success(res) { const latestVersion = res.data.version; const updateUrl = res.data.url; const updateDescription = res.data.description; if (latestVersion > currentVersion) { uni.showModal({ title: '发现新版本', content: updateDescription, confirmText: '立即更新', success(res) { if (res.confirm) { this.downloadAndInstallUpdate(updateUrl); } } }); } else { uni.showToast({ title: '已是最新版本', icon: 'none' }); } }, fail(err) { console.error('检查更新失败', err); } }); }, downloadAndInstallUpdate(updateUrl) { // 下载并安装更新包的逻辑 } }, onLoad() { this.checkForUpdates(); } }
3. 下载更新包
下载更新包可以使用uni.downloadFile方法。下载完成后,保存文件到本地。
downloadAndInstallUpdate(updateUrl) { const downloadTask = uni.downloadFile({ url: updateUrl, success(res) { if (res.statusCode === 200) { const filePath = res.tempFilePath; this.installUpdate(filePath); } else { console.error('下载更新包失败'); } }, fail(err) { console.error('下载更新包失败', err); } }); downloadTask.onProgressUpdate((res) => { console.log('下载进度', res.progress); console.log('已经下载的数据长度', res.totalBytesWritten); console.log('预期需要下载的数据总长度', res.totalBytesExpectedToWrite); }); }
4. 安装更新包
安装更新包的逻辑会根据不同的平台有所不同。以下是Android平台上的示例:
installUpdate(filePath) { plus.runtime.install(filePath, { force: false, success(res) { console.log('安装成功'); plus.runtime.restart(); }, fail(err) { console.error('安装失败', err); } }); }
三、详细实现
index.vue首页界面增加使用个popup弹出组件,用来展示升级进度。
<template> <view class="content"> <!-- 升级弹出框 --> <uni-popup ref="popup" type="center" :mask-click="false" catchTouchMove> <view class="popup-content"> <text>{{percentText}}</text> <progress :percent="progress" :stroke-width="10" /> </view> </uni-popup> </view> </template> <style scoped> .popup-content { text-align: center; max-width: 500rpx; /* 限定最大高度 */ overflow:hidden; background-color: #00aaff; border-radius: 10rpx; padding: 50px; } </style>
在checkVersion()方法里,调用接口checkUpdate去请求后台的update.json文件,获取升级信息。
// 检查更新 export const checkUpdate = async (verCode,verName) => { try { console.log('checkUpdate request'); const response = await uni.$http.get('/update.json',{verCode:verCode,verName:verName}); console.log(response); if (response.statusCode !== 200) { uni.showToast({ title: '数据请求失败! ', duration: 1500, icon: 'none', }); return []; } return response.data; } catch (error) { console.error('Network request failed:', error); uni.showToast({ title: '网络请求失败! ', duration: 1500, icon: 'none', }); return []; } };
比较版本号,判断是否应该升级。需要升级则使用uni.showModal弹出提示框。
if(verCode < result.versionCode){ // 更新提醒 uni.showModal({ title: '发现新版本,是否更新', content: '待更新版本:' + result.versionName +'\n更新说明:'+result.versionDesc, success: res => { // 点击确定 if (res.confirm) { // 打开手机自带浏览器下载 //plus.runtime.openURL(result.downloadUrl+result.appName) this.downloadUrl = result.downloadUrl+result.appName console.log('downloadUrl:'+this.downloadUrl) //显示升级进度 this.showPopup(); if (this.downloadUrl) { this.isStartDownload = true //开始下载App downloadApp(this.downloadUrl, current => { //下载进度 this.progress = current }).then(fileName => { //下载完成 this.isDownloadFinish = true this.fileName = fileName if (fileName) { //自动安装App this.handleInstallApp() } }).catch(e => { console.log(e, 'e') }) } else { uni.showToast({ title: '下载链接不存在', icon: 'none' }) } //this.startProgress(); } } }); }
完整实现
<script> import TodayBoxOffice from '@/components/TodayBoxOffice.vue'; import { downloadApp,installApp } from '@/utils/upgrade.js'; export default { components: { TodayBoxOffice }, data() { return { //升级相关 downloadUrl: '', //APP下载链接 isDownloadFinish: false, //是否下载完成 progress: 0, //升级进度条百分比 fileName: '', //下载后app本地路径名称 } }, async onLoad() { console.log("onLoad") //console.log(this.swiperList) }, computed: { //百分比文字 percentText() { let percent = this.progress; if (typeof percent !== 'number' || isNaN(percent)) return '正在升级中...' if (percent < 100) return `正在升级中... ${percent}%` return '下载完成' } }, methods: { checkVersion(){ console.log("checkVersion:") // 获取本地应用资源版本号 let version = "1.0.0" let verCode = 0 const systemInfo = uni.getSystemInfoSync(); // 应用程序版本号 // #ifdef APP version = plus.runtime.version; verCode = plus.runtime.versionCode; // #endif // #ifdef H5 version = systemInfo.appVersion; // #endif console.log(version) checkUpdate(verCode,version).then(result => { console.log("checkUpdate,result:"); console.log(result); if(verCode < result.versionCode){ // 更新提醒 uni.showModal({ title: '发现新版本,是否更新', content: '待更新版本:' + result.versionName +'\n更新说明:'+result.versionDesc, success: res => { // 点击确定 if (res.confirm) { // 打开手机自带浏览器下载 //plus.runtime.openURL(result.downloadUrl+result.appName) this.downloadUrl = result.downloadUrl+result.appName console.log('downloadUrl:'+this.downloadUrl) //显示升级进度 this.showPopup(); if (this.downloadUrl) { this.isStartDownload = true //开始下载App downloadApp(this.downloadUrl, current => { //下载进度 this.progress = current }).then(fileName => { //下载完成 this.isDownloadFinish = true this.fileName = fileName if (fileName) { //自动安装App this.handleInstallApp() } }).catch(e => { console.log(e, 'e') }) } else { uni.showToast({ title: '下载链接不存在', icon: 'none' }) } //this.startProgress(); } } }); } }) }, showPopup() { this.$refs.popup.open(); }, //安装app handleInstallApp() { //下载完成才能安装,防止下载过程中点击 if (this.isDownloadFinish && this.fileName) { installApp(this.fileName, () => { //安装成功,关闭升级弹窗 this.$refs.popup.close(); }) } } }, } </script>
/** * @description H5+下载App * @param downloadUrl:App下载链接 * @param progressCallBack:下载进度回调 */ export const downloadApp = (downloadUrl, progressCallBack = () => {}, ) => { return new Promise((resolve, reject) => { //创建下载任务 const downloadTask = plus.downloader.createDownload(downloadUrl, { method: "GET" }, (task, status) => { console.log(status,'status') if (status == 200) { //下载成功 resolve(task.filename) } else { reject('fail') uni.showToast({ title: '下载失败', duration: 1500, icon: "none" }); } }) //监听下载过程 downloadTask.addEventListener("statechanged", (task, status) => { switch (task.state) { case 1: // 开始 break; case 2: //已连接到服务器 break; case 3: // 已接收到数据 let hasProgress = task.totalSize && task.totalSize > 0 //是否能获取到App大小 if (hasProgress) { let current = parseInt(100 * task.downloadedSize / task.totalSize); //获取下载进度百分比 progressCallBack(current) } break; case 4: // 下载完成 break; } }); //开始执行下载 downloadTask.start(); }) }
/** * @description H5+安装APP * @param fileName:app文件名 * @param callBack:安装成功回调 */ export const installApp = (fileName, callBack = () => {}) => { //注册广播监听app安装情况 onInstallListening(callBack); //开始安装 plus.runtime.install(plus.io.convertLocalFileSystemURL(fileName), {}, () => { //成功跳转到安装界面 }, function(error) { uni.showToast({ title: '安装失败', duration: 1500, icon: "none" }); }) } /** * @description 注册广播监听APP是否安装成功 * @param callBack:安装成功回调函数 */ const onInstallListening = (callBack = () => {}) => { let mainActivity = plus.android.runtimeMainActivity(); //获取activity //生成广播接收器 let receiver = plus.android.implements('io.dcloud.android.content.BroadcastReceiver', { onReceive: (context, intent) => { //接收广播回调 plus.android.importClass(intent); mainActivity.unregisterReceiver(receiver); //取消监听 callBack() } }); let IntentFilter = plus.android.importClass('android.content.IntentFilter'); let Intent = plus.android.importClass('android.content.Intent'); let filter = new IntentFilter(); filter.addAction(Intent.ACTION_PACKAGE_ADDED); //监听APP安装 filter.addDataScheme("package"); mainActivity.registerReceiver(receiver, filter); //注册广播 }
|
---|