uni-app App端版本更新需正确使用plus.runtime.version获取原生包版本、用分段数字比对函数比较版本号、Android注意下载路径与权限、iOS需跳转App Store,强制更新要持久化用户选择并设冷却期。

uni-app 的 App 内版本检测更新,核心不是“能不能做”,而是“别用错 API、别比错版本、别忽略平台差异”——只要避开这几个点,30 行代码就能跑通。
怎么安全获取当前 App 版本号(plus.runtime.version vs appWgtVersion)
很多更新失败,第一关就栽在“根本没拿到真实版本”。uni-app 在 App 端有两个常用字段,但用途和时机完全不同:
-
plus.runtime.version:返回的是原生包的versionName(manifest.json 里填的),打包后固化,重启也不变,适合做正式版比对 -
appWgtVersion(来自uni.getSystemInfoSync()):返回的是当前运行的 wgt 资源包版本,热更新后可能不同,**不能用于原生 APK/IOS 更新判断** - Android 和 iOS 对
plus.runtime.version的返回格式一致(如"2.8.5"),但 H5 端该 API 不存在,必须加#ifdef APP条件编译
实操建议:只用 plus.runtime.version 做原生更新比对,并包裹 try/catch 防止插件未就绪时报错:
const localVersion = uni.getSystemInfoSync().platform === 'ios' ? plus.runtime.version : plus.runtime.version;
版本号比较函数为什么总出错(compareVersions 的语义陷阱)
直接用 parseInt('1.10') < parseInt('1.2') 得到 true 是经典翻车现场。语义化版本号不是数字,是分段优先级序列。
- 不要用
parseFloat或字符串字典序('1.10' < '1.2'为 true,但实际 1.10 > 1.2) - 必须按段转
Number,逐位比对;位数不等时,长版本高('1.2.0'>'1.2') - 服务端返回的版本号如果带前缀(如
v1.2.3或1.2.3-beta),前端要先正则清洗:remoteVer.replace(/^v|[^0-9.]/g, '')
一个够用的比对函数示例(兼容 1.2 / 1.2.0 / 1.2.3.4):
function compareVersions(v1, v2) {<br> const a = v1.split('.').map(Number);<br> const b = v2.split('.').map(Number);<br> const len = Math.max(a.length, b.length);<br> for (let i = 0; i < len; i++) {<br> const aa = a[i] || 0;<br> const bb = b[i] || 0;<br> if (aa > bb) return 1;<br> if (aa < bb) return -1;<br> }<br> return 0;<br>}
下载安装流程卡在 silent(静默更新)失败?关键看 plus.downloader 和 plus.runtime.install 的权限与路径
Android 上静默安装失败,90% 是因为没处理好文件路径或权限,而不是逻辑问题。
-
plus.downloader.createDownload(url, {})下载的文件默认存到缓存目录,而plus.runtime.install()要求传入**绝对路径**且 Android 10+ 需是android.permission.REQUEST_INSTALL_PACKAGES授权后的可安装路径 - 推荐写法:用
plus.io.resolveLocalFileSystemURL('_www/download/')拿到私有目录,再拼接文件名,确保路径可读可写 - iOS 不支持静默安装,调用
plus.runtime.install会自动跳转 App Store;若你用的是企业签名或 TestFlight,得换用plus.runtime.openURL打开下载链接 - 务必监听
downloaderror事件,而不是只靠 status === 200 判断成功——网络中断、磁盘满、HTTPS 证书异常都会进 error 回调
强制更新怎么避免用户点“取消”后无限弹窗(isForceUpdate 的状态管理)
强制更新不是“弹完就完”,而是要持久化用户选择,否则下次启动又弹,体验极差。
- 服务端接口应返回
isForceUpdate: true/false和minSupportVersion(最低兼容版本),而非仅靠当前版本判断 - 前端收到
isForceUpdate: true后,应把本次版本号写入uni.setStorageSync('forceUpdateBlocked', '2.8.5'),下次启动先检查是否已屏蔽该版本 - 用户点“暂不更新”时,给个 24 小时冷却期(用时间戳记录),而不是永久记住——否则低版本用户永远卡死
- 特别注意:iOS 强制更新只能跳转 App Store 页面,无法拦截或重试,所以服务端最好同时返回 App Store 链接字段
appStoreUrl
真正麻烦的从来不是“怎么写”,而是“怎么让安卓不闪退、iOS 不白屏、用户不卸载”。版本更新链条上任何一个环节没兜住,整个升级就变成负优化。


















