必须在下载完成后校验md5,因plus.downloader不支持流式校验,仅success回调中tempfilepath就绪才可安全读取;服务端须返回规范小写32位file_md5字段,客户端用spark-md5校验完整wgt二进制,失败则清临时文件并提示“安装包损坏”。

必须在下载完成后再校验MD5,不能边下边校验;服务端必须返回file_md5字段,否则客户端无法比对。
为什么MD5校验不能放在下载过程中
uni-app的plus.downloader.createDownload不支持流式校验,回调里拿不到中间数据块。强行在statechanged中读取临时文件会失败——因为文件尚未写完,plus.io.resolveLocalFileSystemURL可能报错FileError.NOT_FOUND_ERR。校验动作只能发生在downloadResult.tempFilePath确认就绪之后。
- 下载完成回调(
success)是唯一安全触发点 - 不要用
uni.getFileSystemManager().readFileSync去读临时路径,iOS下该路径不可访问 - 安卓需确保
tempFilePath指向_doc/目录(如_doc/update.wgt),避免被系统拦截
服务端必须提供file_md5且格式规范
客户端拿到的file_md5必须是小写32位纯十六进制字符串(如"a1b2c3d4e5f67890..."),不能带0x前缀、空格或大小写混用。若服务端返回"MD5: a1B2..."这类带描述的值,compare必然失败。
- 服务端生成MD5时用
md5sum -b或Node.js的crypto.createHash('md5').update(buf).digest('hex') - API响应结构示例:
{ "version": "2.1.0", "wgtUrl": "https://cdn.example.com/app_2.1.0.wgt", "file_md5": "e8b1a9c7d2f3e4a5b6c7d8e9f0a1b2c3" } - 客户端必须严格校验字段存在:
if (!res.data.file_md5) { console.error('missing file_md5'); return; }
安卓8+和iOS对校验后安装的限制
MD5通过只是第一步,安装环节仍有硬性门槛:安卓8+要求REQUEST_INSTALL_PACKAGES权限已授予,iOS则根本无法静默安装.wgt或.ipa。
- 安卓:调用
plus.runtime.install前,先用plus.android.hasPermission('android.permission.REQUEST_INSTALL_PACKAGES')检查,未授权则跳转设置页 - iOS:
plus.runtime.install对.wgt无效,只能走plus.runtime.restart()热更;若要整包升级,必须用itms-services://协议+企业签名.plist,且域名必须HTTPS - 校验失败时,别直接删除临时文件——保留它用于人工排查,比如用
adb shell md5sum /data/data/io.dcloud.HBuilder/apps/_www/_doc/update.wgt复核
如何在wgt热更中嵌入MD5校验逻辑
wgt包本质是zip,校验对象是整个压缩包二进制内容,不是解压后的文件。因此校验必须在install前,且路径指向tempFilePath原始文件。
- 使用
plus.io.readAsArrayBuffer读取完整文件(避免readAsText破坏二进制) - MD5计算推荐用
spark-md5(轻量、无GC、支持ArrayBuffer):SparkMD5.ArrayBuffer.hash(arrayBuffer) - 校验失败后,应清除
tempFilePath并提示“安装包损坏,请重试”,而非继续install——否则可能覆盖旧资源导致白屏 - 注意wgt热更不触发App重启,
plus.runtime.restart()才是生效关键,但需确保所有JS模块已重新加载
真正容易被忽略的是:wgt包MD5校验通过后,plus.runtime.install仍可能因签名不匹配失败(尤其调试时用测试证书打包),此时错误日志里不会提MD5,只会报INSTALL_PARSE_FAILED_NO_CERTIFICATES——得回头查构建时的签名配置。











