uni-app App整包更新必须通过原生层实现,H5和小程序不支持uni.installApp;Android需处理权限、路径及targetSdkVersion适配,iOS仅支持企业签名或TestFlight跳转安装。

uni-app App整包更新必须走原生层,H5和小程序不适用
uni-app 的 uni.downloadFile 和 uni.installDoucment(注意:实际是 uni.installApp)无法在纯 WebView 环境完成安装,iOS 完全禁止、Android 也受限于 targetSdkVersion 和权限模型。所谓“应用内更新”,本质是调用原生能力下载 APK/IOS 安装包并触发安装流程,H5 页面或小程序根本没这个权限。
常见错误现象:installApp:fail not supported 或静默失败;Android 上点了没反应,或提示“未知来源应用被禁止”;iOS 直接报错 installApp:fail system error。
- 只有使用
uni-app编译为 App(即通过 HBuilderX 打正式包,运行在5+ Runtime或uni-app 原生渲染引擎)时,uni.installApp才有效 - 必须确保 manifest.json 中 Android 配置了
"android": { "targetSdkVersion": 30 }及以下(31+ 需声明REQUEST_INSTALL_PACKAGES权限并动态申请) - iOS 需配合企业签名或 TestFlight,
uni.installApp对 App Store 版本无效
Android 下载 + 安装全流程要手动处理权限和路径
从下载到安装不是一条命令能搞定的事。Android 10+ 限制外部存储写入,uni.downloadFile 默认保存到缓存目录,但 uni.installApp 要求文件路径可被系统识别为“已知安装源”。
使用场景:用户点击“立即更新”,前端需判断版本号、下载新包、校验完整性、申请权限、再安装。
- 下载必须指定
success回调里的tempFilePath,不能直接传 URL 给uni.installApp - Android 8.0+ 必须在
AndroidManifest.xml中声明android.permission.REQUEST_INSTALL_PACKAGES - Android 11+ 若目标路径在
ExternalStorage,需改用getExternalFilesDir或getCacheDir,否则installApp会因路径不可读失败 - 推荐保存路径:
uni.env.USER_DATA_PATH + '/update/app-release.apk'(该路径始终可读写)
uni.installApp 在 iOS 上只起跳转作用,不能自动安装
iOS 没有“静默安装”概念。uni.installApp 在 iOS 上实际行为是:尝试用 itms-services://?action=download-manifest&url=... 协议打开,或 fallback 到 Safari 打开 plist 地址。它不下载、不校验、不提示,一切交由系统处理。
容易踩的坑:uni.installApp({ apkPath: 'https://xxx.plist' }) 看似合理,但若 plist 文件未部署在 HTTPS 域名下、或没有正确配置 CFBundleIdentifier 和签名,Safari 会直接报错“无法下载”。
- plist 文件必须通过 HTTPS 提供,且域名需支持 Apple 的 ATS 要求(TLS 1.2+,证书有效)
- plist 中
bundle-identifier必须与当前 App 的 Bundle ID 完全一致,否则安装失败且无明确提示 - 企业签名包每次更新需重新生成 plist,并确保新包的
url字段指向新的 IPA 下载地址(不能复用旧地址) - 真机调试时,
uni.installApp在 Xcode 模拟器中必然失败,仅限真机 + 企业证书环境
版本比对别只看字符串,得解析 build number
用户看到的“v2.3.0”只是显示用的 versionName,真正决定是否需要更新的是 Android 的 versionCode 或 iOS 的 CFBundleVersion(即 build number)。两者都是递增整数,字符串比较会出错,比如 “2.10.0”
uni-app 提供的 uni.getSystemInfoSync().platform 和 uni.getSystemInfoSync().version 返回的是运行时环境版本,不是当前 App 的构建版本。
- 获取当前 App 版本号应使用
uni.getSystemInfoSync().appVersion(对应 Android versionName / iOS CFBundleShortVersionString) - 获取构建号必须通过原生插件或条件编译:Android 读
android.app.ApplicationInfo.metaData,iOS 读[[NSBundle mainBundle] infoDictionary][@"CFBundleVersion"] - 服务端返回的更新信息里,务必同时带
versionName和buildCode字段,前端只用buildCode做数值比对 - 测试时最容易忽略:debug 包和 release 包的 buildCode 可能相同,导致“明明发了新版却提示已是最新”
整包更新真正的复杂点不在 JS 写几行代码,而在于每个平台对文件路径、权限、签名、协议的隐性约束。少一个 plist 配置项、漏一次 Android 权限申请、buildCode 比对逻辑写错——都会让更新流程卡在某个无声无息的环节。

















