- 发布日期:2025-08-07 10:44 点击次数:177
概要
需求分析
技术实现梳理
1.是否更新判断:
2.升级弹窗的展示
3.根据升级类型限制操作
4.下载APP监听下载进度
5.下载完自动安装
核心API讲解
1.plus.downloader.createDownload(url,options,completedCallback)(下载)
2.plus.runtime.install(安装APP)
代码实现
效果演示
注意事项
概要
本文主要讲述uniapp APP在线升级功能实现,并用代码演示包括强制升级、可选升级、下载进度显示、下载自动安装等功能,示例代码已经过测试可结合实际开发场景做调整直接引入使用
需求分析
要求:
1.打开APP自动检测是否有最新版本,如有弹窗提示下载更新
2.升级类型分为可选更新,强制更新,可选更新用户可以选择关闭不更新情况下继续使用APP,强制更新用户无法关闭更新窗口,无法使用任何功能,必须在线升级后才能使用
3.下载过程进度条显示下载进度
4.下载完成自动跳转安装界面,用户取消安装还能继续手动点击安装
技术实现梳理
1.是否更新判断:
通过接口获取线上最新版本号(默认规定版本号为正整数)与本地APP版本号进行比较大小,当线上最新版本号大于本地版本号就需要更新。本地App版本可在每次发版时候在manifest.json-基础配置-应用版本号进行设置
2.升级弹窗的展示
升级弹窗实现有2种方案,一种直接在首页里嵌套弹窗组件,另一种是把弹窗放置在独立的页面,并把页面窗口设置透明,当需要升级的时候直接从首页进入,从视觉效果上看就相当于在首页上的悬浮窗口。考虑到后续有强制更新页面不能返回等操作,便于维护本案例将采用第二种方案
3.根据升级类型限制操作
当升级类型为强制升级意味着页面不能做除了升级的任何操作,包括返回功能,关闭弹窗功能,禁止返回可通过onBackPress生命周期函数处理,弹窗关闭入口动态控制,包括关闭按钮,遮罩层点击关闭功能等
4.下载APP监听下载进度
通过H5+方式下载 :plus.downloader.createDownload,生成下载任务对象(downloadTask),通过downloadTask.addEventListener("statechanged",(task,status)=>{})监听下载进度
5.下载完自动安装
通过H5+ plus.runtime.install实现自动安装,该api只能监听是否打开安装页面,无法监测到apk是否安装成功,还需要调用安卓原生注册广播事件,监听apk安装成功回调
核心API讲解
1.plus.downloader.createDownload(url,options,completedCallback)(下载)
说明:
请求下载管理创建新的下载任务,创建成功则返回Download对象,用于管理下载任务
参数:
url: ( String ) 必选 要下载文件资源地址
要下载文件的url地址,仅支持网络资源地址,支持http或https协议。 允许创建多个相同url地址的下载任务。 注意:如果url地址中包含中文或空格等,需要进行urlencode转换。
options: ( DownloadOptions ) 可选 下载任务的参数
可通过此参数设置下载任务属性,如保存文件路径、下载优先级等。
completedCallback: ( DownloadCompletedCallback ) 可选 下载任务完成回调函数
当下载任务下载完成时触发,成功或失败都会触发。
返回值:
Download:新建的下载任务对象
2.plus.runtime.install(filePath,options,installSuccessCB,installErrorCB)(安装APP)
说明:
支持以下类型安装包: 1. 应用资源安装包(wgt),扩展名为'.wgt'; 2. 应用资源差量升级包(wgtu),扩展名为'.wgtu'; 3. 系统程序安装包(apk),要求使用当前平台支持的安装包格式。 注意:仅支持本地地址,调用此方法前需把安装包从网络地址或其他位置放置到运行时环境可以访问的本地目录。
参数:
filePath: ( String ) 必选 要安装的文件路径
支持应用资源安装包(wgt)、应用资源差量升级包(wgtu)、系统程序包(apk)。
options: ( WidgetOptions ) 可选
应用安装设置的参数
installSuccessCB: ( InstallSuccessCallback ) 可选
正确安装后的回调
installErrorCB: ( InstallErrorCallback ) 可选
安装失败的回调
返回值:
void : 无
代码实现
项目目录:
pages.json:
新增升级弹窗页面路由,设置窗口透明
{
"pages": [ //pages数组中第一项表示应用启动页,参考:https://uniapp.dcloud.io/collocation/pages
{
"path": "pages/index/index",//首页
"style": {
"navigationBarTitleText": ""
}
},
{
"path": "pages/index/upgrade",//升级窗口页面
"style": {
"navigationBarTitleText": "",
"navigationStyle": "custom",//导航栏自定义
"app-plus": {
"bounce": "none",
"animationType":"none",//取消窗口动画
"background": "transparent" // 设置背景透明
}
}
}
],
"globalStyle": {
"navigationBarTextStyle": "black",
"navigationBarTitleText": "uni-app",
"navigationBarBackgroundColor": "#F8F8F8",
"backgroundColor": "#F8F8F8"
},
"uniIdRouter": {}
}
index.vue:(首页)
从接口获取最新版本号,跟本地对比,判断是否进入升级弹窗页
<script>
export default {
data() {
return {}
},
onLoad() {
this.init()
},
methods: {
//初始化
init() {
// #ifdef APP-PLUS
this.checkVersion()
// #endif
},
//检查版本更新情况
checkVersion() {
//模拟接口获取最新版本号,版本号固定为整数
setTimeout(() => {
const newVersionName = "V1.2.0" //线上最新版本名
const newVersionCode = 20; //线上最新版本号
const selfVersionCode = Number(uni.getSystemInfoSync().appVersionCode) //当前App版本号
//线上版本号高于当前,进行在线升级
if (selfVersionCode < newVersionCode) {
let platform = uni.getSystemInfoSync().platform //手机平台
//安卓手机弹窗升级
if (platform === 'android') {
uni.navigateTo({
url: './upgrade'
})
}
//IOS无法在线升级提示到商店下载
else {
uni.showModal({
title: '发现新版本 ' + newVersionName,
content: '请到App store进行升级',
showCancel: false
})
}
}
}, 200)
}
}
}
</script>
upgrade.vue(升级弹窗页):
布局样式可根据实际调整,顶部背景图upgrade_bg.png自行放入static
<template>
<view class="upgrade-popup">
<image class="header-bg" src="https://www.360doc.cn/article/../../static/upgrade_bg.png" mode="widthFix"></image>
<view class="main">
<view class="version">发现新版本{{versionName}}</view>
<view class="content">
<text class="title">更新内容</text>
<view class="desc" v-html="versionDesc"></view>
</view>
<!--下载状态-进度条显示 -->
<view class="footer" v-if="isStartDownload">
<view class="progress-view" :class="{'active':!hasProgress}" @click="handleInstallApp">
<!-- 进度条 -->
<view v-if="hasProgress" style="height: 100%;">
<view class="txt">{{percentText}}</view>
<view class="progress" :style="setProStyle"></view>
</view>
<view v-else>
<view class="btn upgrade force">{{ isDownloadFinish ? '立即安装' :'下载中...'}}</view>
</view>
</view>
</view>
<!-- 强制更新 -->
<view class="footer" v-else-if="isForceUpdate">
<view class="btn upgrade force" @click="handleUpgrade">立即更新</view>
</view>
<!-- 可选择更新 -->
<view class="footer" v-else>
<view class="btn close" @click="handleClose">以后再说</view>
<view class="btn upgrade" @click="handleUpgrade">立即更新</view>
</view>
</view>
</view>
</template>
<script>
import {
downloadApp,
installApp
} from './upgrade.js'
export default {
data() {
return {
isForceUpdate: false, //是否强制更新
versionName: '', //版本名称
versionDesc: '', //更新说明
downloadUrl: '', //APP下载链接
isDownloadFinish: false, //是否下载完成
hasProgress: false, //是否能显示进度条
currentPercent: 0, //当前下载百分比
isStartDownload: false, //是否开始下载
fileName: '', //下载后app本地路径名称
}
},
computed: {
//设置进度条样式,实时更新进度位置
setProStyle() {
return {
width: (510 * this.currentPercent / 100) + 'rpx' //510:按钮进度条宽度
}
},
//百分比文字
percentText() {
let percent = this.currentPercent;
if (typeof percent !== 'number'