必须用 plus.downloader.createdownload 而非 uni.downloadfile 实现增量更新进度,因其支持 statechanged 事件获取 downloadedsize 和 totalsize;需在 start 前绑定监听,android 在 state===1 后读 totalsize,ios 需后端返回 filesize;下载与安装进度须分离,install 阶段不可模拟进度;cover-view 弹窗需 settimeout 延迟挂载;强制更新需拦截交互并分平台验证。

增量更新进度不能用 uni.downloadFile
它不暴露下载过程中的字节级进度,只在完成时回调,根本没法算百分比。必须用 H5+ 原生下载器 plus.downloader.createDownload,它提供 statechanged 事件,能实时拿到 downloadedSize 和 totalSize。
常见错误是直接传 URL 字符串进去就 start,但没绑定监听——结果下载完成了却没触发任何进度更新。必须在 createDownload 后立即调用 addEventListener('statechanged', ...),且监听逻辑要写在任务创建之后、start() 之前。
- Android 端:
totalSize在state === 1(已开始)时才可读,早期状态可能为 0,别一上来就除零 - iOS 端:
totalSize始终为 0(苹果限制),只能靠服务端预估或返回fileSize字段,否则进度条永远卡在 0% - 进度值建议四舍五入取整:
Math.round((downloadedSize / totalSize) * 100),避免小数频繁触发 Vue 响应式更新导致卡顿
怎么把差分包进度和安装进度分开显示
增量更新本质是两阶段:先下差分包(.wgt 或 .zip),再用原生能力打补丁。但用户看到的“进度条”往往混为一谈,实际应分层处理:
- 第一阶段(下载差分包):用
plus.downloader监听,state === 2表示正在下载,此时更新 UI 进度 - 第二阶段(应用差分包):调用
plus.runtime.install后,iOS 无回调,Android 返回 success/fail 但不带进度;此时进度条应固定在 100%,文案改为“正在热更新…”而非继续动效 - 别试图在
install阶段模拟进度——没有底层 API 支持,强行 setTimeout 模拟只会误导用户
为什么 iOS 上增量更新进度总是不准
不是代码写错,是平台限制:iOS 的 plus.downloader 拿不到真实 totalSize,所有基于除法的百分比计算都失效。解决方案只有两个:
- 后端必须在版本接口里额外返回
fileSize字段(单位 byte),前端存下来,在下载开始后硬编码赋值给本地变量用于计算 - 改用“分段提示”代替精确百分比:比如“正在准备更新 → 下载中(约 30 秒)→ 应用补丁 → 重启完成”,用文案过渡替代数字跳变
- 千万别信
uni.getSystemInfoSync().windowWidth之类无关字段去“凑”进度——纯属误导
cover-view 进度弹窗必须延迟挂载
cover-view 是唯一能盖过 map/video/camera 的容器,但它渲染依赖原生层就绪。如果在 onLaunch 里同步 v-if="showProgress",iOS 常出现闪一下消失,安卓则可能遮不住原生组件。
- 正确做法:用
setTimeout(() => { this.showProgress = true }, 150)延迟挂载,确保 DOM 和原生视图树都 ready - 进度条组件别用第三方库的复杂动画,推荐原生
view+progress标签或简单u-line-progress,减少重绘压力 - 遮罩层必须设
z-index高于所有业务页面,且禁止透传点击事件:pointer-events: none加cover-view内部显式bindtap控制关闭逻辑
强制更新不是弹个框就完事——进度条背后得卡死路由、拦截返回键、禁用所有交互入口。而增量更新更麻烦:差分包校验失败、热更中途崩溃、iOS 安装跳转丢失上下文……这些都不会报错,只会静默失败。真正落地时,每个平台都要单独验证,不能共用一套逻辑。











