Skip to content

v10.53.0

Choose a tag to compare

@sunnylqm sunnylqm released this 20 Aug 04:24
· 24 commits to master since this release

English

Android full-package install moves to PackageInstaller

downloadAndInstallApk no longer hands the APK to the system through an ACTION_INSTALL_PACKAGE / ACTION_VIEW intent and a bundled FileProvider. It now stages the file into a PackageInstaller session and commits it, which changes three things that mattered in practice:

  • The promise reflects the real install outcome. Previously it resolved the moment the intent was fired — a rejected or failed install looked exactly like a successful one. The session now reports back through a status receiver: it resolves once the system installer takes over (confirmation screen shown, or the install succeeds outright) and rejects with the installer's own failure message when the session cannot be created, written, committed, or continued.
  • No storage permission, no public Downloads staging. The pre-API-24 path used to write pushy_update.apk into the shared Downloads directory and ask for WRITE_EXTERNAL_STORAGE from JS first. Both are gone — the APK is always downloaded to the app's private directory and read from there. You can drop WRITE_EXTERNAL_STORAGE from your manifest if it was only there for us.
  • The library's FileProvider is gone. PushyFileProvider, the ${applicationId}.pushy.fileprovider authority and pushy_file_paths.xml were removed from the library manifest; a non-exported PackageInstallerStatusReceiver replaces them. One less provider merged into your app, and one less source of authority collisions.

The session also declares an originating URI/UID and INSTALL_REASON_USER, and on Android 12+ explicitly requests USER_ACTION_REQUIRED, so the system prompt behaves consistently instead of depending on OEM intent handling. Failed sessions are abandoned rather than left dangling.

Action required if you use downloadAndInstallApk

Declare the install permission in your app's AndroidManifest.xml:

<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />

On Android 8.0+ the call now pre-flights before downloading anything:

  • permission not declared → rejects immediately with APK_INSTALL_PERMISSION_REQUIRED and a message telling you to declare it (no silent fallback — a misconfigured integration fails loudly instead of downloading an APK it can never install);
  • declared but not yet trusted by the user → opens the "install unknown apps" settings screen and rejects with the same code, so you can retry after the user grants it.

Hot updates (JS bundle) are unaffected — this path only runs when you ship a full new APK.

New error codes

APK_INSTALL_PERMISSION_REQUIRED and APK_INSTALL_FAILED are added to UpdateErrorCode (and to the Android / C++ code tables). STORAGE_PERMISSION_REJECTED / STORAGE_PERMISSION_ERROR remain in the type for compatibility but are no longer emitted.

Build floor

The library's Gradle defaults move up: minSdkVersion 16 → 21 (PackageInstaller requires API 21), compileSdkVersion 28 → 31, buildToolsVersion 31.0.0. These are safeExtGet defaults — if your root build.gradle sets ext.minSdkVersion / compileSdkVersion (every current RN template does), nothing changes for you.

No iOS or HarmonyOS changes in this release.

中文

Android 整包安装迁移到 PackageInstaller

downloadAndInstallApk 不再通过 ACTION_INSTALL_PACKAGE / ACTION_VIEW intent 加内置 FileProvider 把 APK 交给系统,而是把文件写入 PackageInstaller 会话并提交。三个实际差别:

  • Promise 真实反映安装结果。 以前 intent 一发出就 resolve——用户取消或安装失败,和成功完全无法区分。现在会话通过状态接收器回报:系统安装器接手(弹出确认页,或直接安装成功)时 resolve;会话创建、写入、提交或后续流程失败时,带上安装器自己的失败信息 reject。
  • 不再需要存储权限,也不再落公共 Downloads 目录。 旧的 API 24 以下路径会把 pushy_update.apk 写进共享 Downloads 目录,并先从 JS 申请 WRITE_EXTERNAL_STORAGE。两者都已移除——APK 一律下载到应用私有目录并从那里读取。如果你的清单里的 WRITE_EXTERNAL_STORAGE 只是为我们加的,现在可以删掉。
  • 库自带的 FileProvider 已移除。 PushyFileProvider${applicationId}.pushy.fileprovider authority 和 pushy_file_paths.xml 都从库清单中删除,取而代之的是一个不导出的 PackageInstallerStatusReceiver。合并进你 App 的 provider 少了一个,authority 冲突的来源也少了一个。

会话还会声明来源 URI/UID 与 INSTALL_REASON_USER,并在 Android 12+ 显式请求 USER_ACTION_REQUIRED,系统弹窗行为因此保持一致,不再取决于厂商对 intent 的处理。失败的会话会被 abandon,不会残留。

使用 downloadAndInstallApk 的必须改动

在 App 的 AndroidManifest.xml 中声明安装权限:

<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />

Android 8.0+ 上,该调用现在会在下载之前先做前置检查:

  • 未声明权限 → 立即以 APK_INSTALL_PERMISSION_REQUIRED reject,并提示补声明(不做静默降级——接入不完整就直接报错,而不是下载一个根本装不上的 APK);
  • 已声明但用户尚未授权 → 拉起"安装未知应用"设置页,并以同一错误码 reject,便于你在用户授权后重试。

热更新(JS bundle)不受影响——这条路径只在你要下发整包新 APK 时才走。

新增错误码

UpdateErrorCode(以及 Android / C++ 错误码表)新增 APK_INSTALL_PERMISSION_REQUIREDAPK_INSTALL_FAILEDSTORAGE_PERMISSION_REJECTED / STORAGE_PERMISSION_ERROR 为兼容保留在类型中,但已不再抛出。

构建下限

库的 Gradle 默认值上调:minSdkVersion 16 → 21(PackageInstaller 要求 API 21)、compileSdkVersion 28 → 31、buildToolsVersion 31.0.0。这些都是 safeExtGet 的默认值——只要你的根 build.gradle 设了 ext.minSdkVersion / compileSdkVersion(当前所有 RN 模板都设了),对你没有任何影响。

本版本无 iOS 与 HarmonyOS 变更。