该问题请在专业群( uni-app 官方技术交流群 1 ) 咨询,群中有相关专业的管理员和群友。
问题本质
在 Android 11 及以上系统,/sdcard(外部存储)采用「分区存储」+「延迟挂载」策略。
开机后如果 App 被系统或第三方保活工具立即拉起,此时外部存储尚未挂载完成,
uni-app 热更新框架(wgt-loader)会退而求其次去 /data/data/包名/apps/manifest.json 读取版本信息;
而当外部存储可用后再启动,框架会优先读取 /data/data/包名/files/apps/manifest.json(指向 /sdcard 上的 wgt 包)。
两份 manifest.json 版本号不一致就会出现「版本回退」。
解决思路
- 让框架在 /sdcard 挂载完成以后再执行热更新检测。
- 或者把热更新包直接放到内部存储,彻底摆脱外部存储挂载时机。
推荐做法(uni-app 可落地)
-
延迟执行热更新
在 App.vue → onLaunch 里,先监听外部存储挂载事件,再调用 plus.runtime.install:
// #ifdef APP-ANDROID
function waitForExternalStorage() {
return new Promise((resolve) => {
const path = plus.io.convertLocalFileSystemURL('_doc/');
const timer = setInterval(() => {
plus.io.resolveLocalFileSystemURL(
path,
() => {
clearInterval(timer);
resolve(true);
},
() => {}
);
}, 200);
});
}
onLaunch: async function () {
await waitForExternalStorage(); // 等 /sdcard 就绪
// 再执行热更新逻辑
plus.runtime.getProperty(plus.runtime.appid, (info) => {
// 这里再读取 /sdcard 上的 manifest.json
});
}
// #endif
-
把 wgt 包放到内部存储
在 manifest.json → app-plus → distribute → android 里加
"android": {
"wgtPath": "/data/data/__PACKAGE_NAME__/files/apps"
}
然后在服务器端把 wgt 包下载到 plus.io.convertLocalFileSystemURL('_doc/apps/')(内部存储),
这样无论外部存储是否挂载,读取的都是同一份文件,不会出现版本差异。
-
使用系统广播(可选)
如果项目里已经接入了原生插件,可以在 AndroidManifest.xml 注册监听
<receiver android:name=".BootReceiver">
<intent-filter>
<action android:name="android.intent.action.MEDIA_MOUNTED" />
<data android:scheme="file" />
</intent-filter>
</receiver>
收到广播后再通过 UniJSCallback 通知 uni 层开始热更新。
-
关闭第三方保活/自启
某些保活框架会在系统启动 1-2 秒内强行拉起 App,导致 100% 复现。
在设置里关闭「自启动」或把热更新逻辑延后到 onShow 第一次进入前台时再执行,也能规避。
小结
最简方案:在 onLaunch 里加 2-3 秒延时或轮询 /sdcard 是否可用,再读取 manifest.json;
根治方案:把 wgt 包放到内部存储,彻底摆脱外部存储挂载时序问题。
1 个回复
Ask小助手 - Ask社区AI助手
问题本质
在 Android 11 及以上系统,/sdcard(外部存储)采用「分区存储」+「延迟挂载」策略。
开机后如果 App 被系统或第三方保活工具立即拉起,此时外部存储尚未挂载完成,
uni-app 热更新框架(wgt-loader)会退而求其次去 /data/data/包名/apps/manifest.json 读取版本信息;
而当外部存储可用后再启动,框架会优先读取 /data/data/包名/files/apps/manifest.json(指向 /sdcard 上的 wgt 包)。
两份 manifest.json 版本号不一致就会出现「版本回退」。
解决思路
推荐做法(uni-app 可落地)
延迟执行热更新
在 App.vue → onLaunch 里,先监听外部存储挂载事件,再调用 plus.runtime.install:
把 wgt 包放到内部存储
在 manifest.json → app-plus → distribute → android 里加
然后在服务器端把 wgt 包下载到 plus.io.convertLocalFileSystemURL('_doc/apps/')(内部存储),
这样无论外部存储是否挂载,读取的都是同一份文件,不会出现版本差异。
使用系统广播(可选)
如果项目里已经接入了原生插件,可以在 AndroidManifest.xml 注册监听
收到广播后再通过 UniJSCallback 通知 uni 层开始热更新。
关闭第三方保活/自启
某些保活框架会在系统启动 1-2 秒内强行拉起 App,导致 100% 复现。
在设置里关闭「自启动」或把热更新逻辑延后到 onShow 第一次进入前台时再执行,也能规避。
小结
最简方案:在 onLaunch 里加 2-3 秒延时或轮询 /sdcard 是否可用,再读取 manifest.json;
根治方案:把 wgt 包放到内部存储,彻底摆脱外部存储挂载时序问题。
要回复问题请先登录或注册
公告
更多>相关问题