我正在为我的应用程序进行更新,其中有一节涉及下载和安装APK文件.

只要之前的版本是针对SDK30的,一切都运行得相当顺利.但是,当我增加目标并将SDK编译到32位时,它就开始出现奇怪的行为.

下面是处理包管理器和安装的代码:

private fun installOnClickListener() {
    binding.termuxInstallCard.showProgress()
    var session: PackageInstaller.Session? = null
    try {
        val packageInstaller: PackageInstaller =
            requireContext().packageManager.packageInstaller
        val params = PackageInstaller.SessionParams(
            PackageInstaller.SessionParams.MODE_FULL_INSTALL
        )
        val sessionId = packageInstaller.createSession(params)
        session = packageInstaller.openSession(sessionId)
        viewModel.addApkToSession(session)

        var installBroadcast: PendingIntent? = null
        val intent =
            Intent(PACKAGE_INSTALLED_ACTION).putExtra(
                "packageName",
                "com.termux"
            )

        installBroadcast = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
            PendingIntent.getBroadcast(
                context,
                0,
                intent,
                FLAG_MUTABLE
            )
        } else {
            PendingIntent.getBroadcast(context, 0, intent, FLAG_UPDATE_CURRENT)
        }
        session.commit(installBroadcast.intentSender)
        session.close()

    } catch (e: IOException) {
        throw RuntimeException("Couldn't install package", e)
    } catch (e: RuntimeException) {
        session?.abandon()
        throw e
    } finally {
        session?.close()
    }

}

以下是正在发生的事情:

因为我的目标是SDK 32,所以我需要指定Mutability of PendingIntent

           Targeting S+ (version 31 and above) requires that one of FLAG_IMMUTABLE or FLAG_MUTABLE be specified when creating a PendingIntent

当我使用时:

  1. FLAG_MUTABLE-安装失败,并在EXTRA_STATUS_MESSAGE中说明错误代码-STATUS_FAILURE_INVALID,没有额外的调试消息.问题是,当我试图通过ADBshell 安装相同的下载APK时,它只是正常安装,没有任何问题.
  2. FLAG_IMMARTABLE-安装成功,而不用安装对话框提示用户but nothing is actually installed.

更多的代码,以防你需要-

fun addApkToInstallSession(
        path: String,
        session: PackageInstaller.Session
    ) {
        val file = File("${context.filesDir.path}/$path")
        val packageInSession: OutputStream = session.openWrite("com.termux", 0, -1)
        val inputStream = FileInputStream(file)
        val byteStream = inputStream.read()
        try {
            var c: Int
            val buffer = ByteArray(16384)
            while (inputStream.read(buffer).also { c = it } >= 0) {
                packageInSession.write(buffer, 0, c)
            }
        } catch (e: IOException) {
            println("IOEX")
        } finally {
            try {
                packageInSession.close()
                inputStream.close()
            } catch (e: IOException) {
                println("IOEX in closing the stream")
            }
        }
    }

private val broadcastReceiverForInstallEvents = object : BroadcastReceiver() {
        override fun onReceive(context: Context, intent: Intent) {
            lifecycleScope.launch(Dispatchers.IO) {
                val extras = intent.extras
                val status = extras!!.getInt(PackageInstaller.EXTRA_STATUS)
                val packageName = extras.getString("packageName")!!
                if (PACKAGE_INSTALLED_ACTION == intent.action) {
                    println("STATUS $status")
                    when (status) {
                        PackageInstaller.STATUS_PENDING_USER_ACTION -> {
                            try {
                                val confirmIntent = extras[Intent.EXTRA_INTENT] as Intent
                                confirmIntent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
                                context.startActivity(confirmIntent)
                            } catch (e: Exception) {
                                lifecycleScope.launch(Dispatchers.Main) {
                                    Toast.makeText(
                                        requireContext(),
                                        "We could not find an application to handle the installation of apps. Please download a package installer.",
                                        Toast.LENGTH_SHORT
                                    ).show()
                                }
                            }
                        }
                        PackageInstaller.STATUS_SUCCESS -> {
                            lifecycleScope.launch(Dispatchers.Main) {
                                println("$packageName Install succeeded!")
                                // todo all done animation

                                binding.termuxInstallCard.markAsComplete()

                                Toast.makeText(requireContext(), "All Done!", Toast.LENGTH_SHORT)
                                    .show()

                                lifecycleScope.launch {
                                    // viewModel.setTermuxSetupDone()
                                }
                                /* redirecting... */
                                Handler(Looper.getMainLooper()).postDelayed({
                                    redirect()
                                }, 2000)

                            }
                        }
                        PackageInstaller.STATUS_FAILURE, PackageInstaller.STATUS_FAILURE_ABORTED, PackageInstaller.STATUS_FAILURE_BLOCKED, PackageInstaller.STATUS_FAILURE_CONFLICT, PackageInstaller.STATUS_FAILURE_INCOMPATIBLE, PackageInstaller.STATUS_FAILURE_INVALID, PackageInstaller.STATUS_FAILURE_STORAGE -> {
                            lifecycleScope.launch(Dispatchers.Main) {
                                println("Extra Status Message${extras.getString("EXTRA_STATUS_MESSAGE")}")
                                "There was an error installing Termux. Please retry.".showSnackbar(
                                    binding.root,
                                    true
                                )
                                binding.termuxInstallCard.hideProgress()
                            }
                        }
                        else -> {
                            lifecycleScope.launch(Dispatchers.Main) {
                                println("$packageName Install failed else!")
                                //  exitActivity("Package failed to install -> Unknown Error!") 
                                binding.termuxInstallCard.hideProgress()
                            }
                        }
                    }
                }
            }
        }
    }

如果能帮上忙,我会非常感激!

推荐答案

在计算我提交给PackageManager会话的文件的哈希后,我发现它没有正确地写入APK文件.

val inputStream: InputStream = session.openRead("com.termux")

        val file = File("${requireContext().filesDir.path}/test2.apk")
        if (!file.exists()) {
            file.createNewFile()
        }
        try {
            inputStream.use { input ->
                file.outputStream().use { output ->
                    input.copyTo(output)
                }
            }
        } catch (e: Exception) {
            println("Exception occured $e")
        }
        if (file.length() > 0) {
            val hash = file.getMD5Hash()
            println("HASH of session - $hash")
        }

修正了与可变待定意图的组合.该程序包现在安装得很好.

Android相关问答推荐

带有kSP而不是kapt的Hilt

Android,从C++调用的铁 rust 库缺少符号

属性可选的涟漪效果ItemBackEarth Borderless不适用于Android 13和更高版本

react 本机生成失败,出现异常.错误:无法确定';<;宏/>;的类型

DocumentFile.canWrite()、DocumentFile.Existes()-使用本地内置手机存储(而不是云)时性能较差(占用太多CPU时间)

更改选定的切换轨道 colored颜色

如何在Jetpack Compose中向SearchBar添加边框

将输出写入已发布的 Android 应用程序中的日志(log)文件?

Android kotlin 中闪屏 API 执行完成后如何根据身份验证将用户导航到特定屏幕

Android 不在后台更新位置

Spinner - onItemLongClick 从未执行

只能从同一个库组内调用成功(引用groupId=androidx.work from groupId=My Composable)

系统导航栏在某些场景下应用了深色效果

为什么集成React Native时compileSdkVersion错误?

如何在 Jetpack Compose 中向图像视图添加对角色带?

找不到(包名称).在以下位置搜索:

Compose Accompaniist Pager 中的 TabRow/Tab 重组问题

ionic - capacitor - Android 风味 - 无法在模拟器或真实设备中运行应用程序

Android Studio (Kotlin):无法启动活动

如何满足设备内框架的无效 Wear OS 屏幕截图Wear OS 表盘策略违规?