静默热更新仅支持wgt包,apk/ipa无法真正静默;wgt需hbuilderx打包、签名一致、版本用数值比对、下载后必须立即调用plus.runtime.restart(),且无法覆盖原生层变更。

静默热更新只能用 wgt 包,不是 APK
uni-app App 端真正能“静默”生效的只有 wgt 包热更新——它不安装新应用,而是替换 WebView 内的 JS、Vue 页面、CSS 和静态资源。APK/IPA 整包更新在 iOS 完全不可静默;Android 8.0+ 即使有权限也必须弹系统安装页,用户点“继续”才算走完流程。
常见错误是把 uni.downloadFile + uni.openDocument 当成静默方案,结果 iOS 直接跳 App Store,Android 在部分机型上卡死或报 INSTALL_FAILED_USER_RESTRICTED。别走这条路。
-
wgt必须由 HBuilderX 打包生成:勾选「生成 wgt 包」,目标平台选「App」(不能选「通用」或「H5」) - 打包时
manifest.json中的appid必须与当前运行 App 的plus.runtime.appid完全一致,否则安装报install wgt fail: invalid wgt file - 签名必须和原安装包一致:云打包基座和自定义基座签名不同,wgt 不可混用
版本比对必须用数值,不能字符串直接比
本地 wgt 版本号来自 plus.runtime.getProperty 返回的 widgetInfo.versionCode(数字),服务端返回的 wgtVersion 也必须是整数。字符串比较 "1.0.10" > "1.0.2" 是 false(字典序),但语义上它是更高版本。
推荐统一用 semver.gt(newVer, curVer),比手写 split('.').map(Number) 更稳,尤其当版本含四位(如 "1.2.3.20260530")时不会出错。
- 前端取本地版本必须用
parseInt(widgetInfo.versionCode),不是widgetInfo.versionCode字符串 - 服务端接口字段建议为
{ update: true, wgtUrl: "https://xxx.com/app.wgt", isForce: false },wgtVersion字段传整数 - 千万别让后端返回
"v1.2.0"或"1.2.0-beta"这类非规范格式,semver.gt会解析失败
下载 + 安装 + 重启必须串行且同步执行
plus.runtime.install 只解压文件,不刷新页面;不调 plus.runtime.restart(),用户看到的仍是旧代码,甚至白屏或 404。这是静默更新失败最常见原因。
必须在 install 的 success 回调内**立即、同步**调用 plus.runtime.restart(),不能加 setTimeout,也不能写在回调外。
- 下载建议用
plus.downloader.createDownload(支持断点续传、进度监听),返回的d.filename是绝对路径,可直传给install - 不要在
onLaunch函数体里直接调用检查逻辑,H5+ 环境可能未就绪。改用plus.ready(() => { this.checkWgtUpdate() }) - 安卓低版本(如 5.x)上,漏掉
restart就表现为“控制台显示 success,但页面毫无反应”
强制更新要卡住路由,不能只靠弹窗
弹窗点了「取消」或用户按返回键,如果首页继续加载数据、发起 API、渲染 tabbar,那强制更新就形同虚设。关键不是弹不弹,而是“拦不住”。
正确做法是全局状态 + 路由守卫:检测到 isForce: true 且版本不满足时,立刻 uni.setStorageSync('pendingUpdate', true),所有页面 onLoad 开头加判断:
if (uni.getStorageSync('pendingUpdate')) {
uni.redirectTo({ url: '/pages/update/force' });
return;
}
/pages/update/force 页面只放一个全屏 <cover-view></cover-view> 弹窗(普通 <view></view> 会被 <map></map>、<video></video> 盖住)。Android 物理返回键需单独拦截:#ifdef APP-PLUS 下用 plus.key.addEventListener('backbutton', ...) 重定向为重新弹窗或提示。
真正容易被忽略的是:wgt 热更新无法覆盖原生层变更。你改了 manifest.json 的权限、加了新的 native 插件、调整了 features 配置,这些都必须走整包更新——否则用户打开就是白屏或崩溃,静默更新救不了。











