使用PackageInstaller安装APK时无法获取状态更新求助
问题分析与解决方案
核心问题1:PendingIntent不可变性阻止系统注入额外数据
你创建PendingIntent时使用了PendingIntent.FLAG_IMMUTABLE,在Android 12(API 31)及以上版本,该标记会让Intent变为不可修改状态,而PackageInstaller需要向Intent中写入安装状态、包名等数据,因此无法完成注入。
修复代码:根据系统版本替换为FLAG_MUTABLE(低版本可保留原标记):
val pi = PendingIntent.getBroadcast( context, InstallReceiver::class.hashCode(), intent, if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_MUTABLE } else { PendingIntent.FLAG_UPDATE_CURRENT } )
核心问题2:未在SessionParams中指定目标包名
你的SessionParams未设置要安装APK的包名,PackageInstaller无法识别目标应用,因此无法传递EXTRA_PACKAGE_NAME等关键数据。
修复代码:解析APK包名并绑定到SessionParams:
// 在创建params后添加这段代码 val packageInfo = context.packageManager.getPackageArchiveInfo( apk.absolutePath, PackageManager.GET_META_DATA ) packageInfo?.packageName?.let { packageName -> params.setAppPackageName(packageName) }
其他潜在修复点
- 广播接收器XML配置错误:原配置标签未正确闭合,修正后:
<receiver android:name=".shared.updater.InstallReceiver" android:exported="false"> <intent-filter> <action android:name="xx.xx.installer.InstallReceiver.ACTION_INSTALL" /> </intent-filter> </receiver>
- Session资源优化:使用
use块自动管理Session生命周期,避免手动关闭的潜在问题:
// 替换原session.openSession后的代码块 context.packageManager.packageInstaller.openSession(sessionId).use { session -> apk.inputStream().use { apkStream -> session.openWrite(apk.nameWithoutExtension, 0, apk.length()).use { sessionStream -> apkStream.copyTo(sessionStream) session.fsync(sessionStream) } } // 此处执行commit操作 session.commit(pi.intentSender) }
修改后的完整安装方法示例
override suspend fun installUpdates(): Unit = withContext(Dispatchers.IO) { try { apkDirectory.listFiles()?.forEach { apk -> val params = PackageInstaller.SessionParams(PackageInstaller.SessionParams.MODE_FULL_INSTALL) // 解析APK包名并设置 val packageInfo = context.packageManager.getPackageArchiveInfo( apk.absolutePath, PackageManager.GET_META_DATA ) packageInfo?.packageName?.let { params.setAppPackageName(it) } val sessionId = context.packageManager.packageInstaller.createSession(params) context.packageManager.packageInstaller.openSession(sessionId).use { session -> apk.inputStream().use { apkStream -> session.openWrite(apk.nameWithoutExtension, 0, apk.length()).use { sessionStream -> apkStream.copyTo(sessionStream) session.fsync(sessionStream) } } val intent = Intent(context, InstallReceiver::class.java) intent.action = InstallReceiver.ACTION_INSTALL val piFlags = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_MUTABLE } else { PendingIntent.FLAG_UPDATE_CURRENT } val pi = PendingIntent.getBroadcast( context, InstallReceiver::class.hashCode(), intent, piFlags ) session.commit(pi.intentSender) } } } catch (e: Exception) { e.printStackTrace() } }
完成以上修改后,广播接收器即可接收到完整的安装状态、包名、会话ID等数据。
内容的提问来源于stack exchange,提问作者tyczj
相关产品推荐
相关产品推荐

