簡體   English   中英

以編程方式安裝 APK (Android 12)

[英]Installing an APK Programmatically (Android 12)

我正在嘗試以編程方式在 Android 12 上安裝 APK,但此時似乎遇到了未知問題。 我發現的所有關於以編程方式安裝 APK 的建議似乎都已被棄用。

目前,我可以保存我的文件,但每當我嘗試使用 PackageManager.PackageInstaller 安裝它時,它都會靜默失敗,並且我無法在日志中找到任何提示可能出現故障的內容。

這是我的 package 安裝程序 object。

object PackageInstaller {
    @SuppressLint("WrongConstant")
    @Throws(IOException::class)
    fun installPackage(
        context: Context,
        installSessionId: String?,
        packageName: String?,
        apkStream: InputStream?
    ) {
        val packageManger = context.packageManager
        val packageInstaller = packageManger.packageInstaller
        val params = android.content.pm.PackageInstaller.SessionParams(
            android.content.pm.PackageInstaller.SessionParams.MODE_FULL_INSTALL
        )
        params.setAppPackageName(packageName)
        var session: android.content.pm.PackageInstaller.Session? = null
        try {
            val sessionId = packageInstaller.createSession(params)
            session = packageInstaller.openSession(sessionId)
            val out = session.openWrite(installSessionId!!, 0, -1)
            val buffer = ByteArray(1024)
            var length: Int
            var count = 0
            if (apkStream != null) {
                while (apkStream.read(buffer).also { length = it } != -1) {
                    out.write(buffer, 0, length)
                    count += length
                }
            }
            session.fsync(out)
            out.close()
            val intent = Intent
            intent.addFlags(Intent.ACTION_PACKAGE_ADDED)
            Log.v("installer", "Installing..?")
            session.commit(
                PendingIntent.getBroadcast(
                    context, sessionId,
                    intent, if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                        PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT
                    } else {
                        PendingIntent.FLAG_UPDATE_CURRENT
                    }

                ).intentSender
            )
        }finally {
            session?.close()
        }
    }
}

在這一點上,我很迷茫,不知道下一步該往哪里看。 有誰知道這是否仍然可行? 或者這個問題的解決方案?

您可以嘗試使用它與 android 12 一起使用

class DownloadApk(private var context: WeakReference<Context>) {

@JvmOverloads
fun startDownloadingApk(url: String, fileName: String = "App Update") {
    if (URLUtil.isValidUrl(url)) {
        DownloadNewVersion(context, url, fileName).execute()
    }
}

@Suppress("DEPRECATION")
private class DownloadNewVersion(
    private val context: WeakReference<Context>,
    val downloadUrl: String,
    val fileName: String
) : AsyncTask<String, Int, Boolean>() {

    private lateinit var bar: ProgressDialog

    override fun onPreExecute() {
        super.onPreExecute()
        bar = ProgressDialog(context.get()).apply {
            setCancelable(false)
            setMessage("Downloading...")
            isIndeterminate = true
            setCanceledOnTouchOutside(false)
            show()
        }
    }

    override fun onProgressUpdate(vararg values: Int?) {
        super.onProgressUpdate(*values)
        var msg = ""
        val progress = values[0]
        if (progress != null) {
            bar.progress = progress
            msg = if (progress > 99) "Finishing... " else "Downloading... $progress%"
        }

        bar.apply {
            isIndeterminate = false
            max = 100
            setMessage(msg)
        }
    }

    override fun onPostExecute(result: Boolean?) {
        super.onPostExecute(result)
        bar.dismiss()
        if (result != null && result) {
            context.get()?.let {
                Toast.makeText(it, "Update Done", Toast.LENGTH_SHORT).show()
            }

        } else {
            context.get()?.let {
                Toast.makeText(it, "Error: Try Again", Toast.LENGTH_SHORT).show()
            }

        }
    }

    override fun doInBackground(vararg p0: String?): Boolean {
        var flag = false

        try {
            val path =
                Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)
                    .toString() + "/"
            var outputFile = File("$path$fileName.apk")
            var repetition = 1
            while (outputFile.exists()) {
                outputFile = File("$path$fileName ($repetition).apk")
                repetition++
            }

            val directory = File(path)
            if (!directory.exists()) {
                directory.mkdirs()
            }

            val url = URL(downloadUrl)
            val c = url.openConnection() as HttpURLConnection
            c.requestMethod = "GET"
            c.connect()

            val fos = FileOutputStream(outputFile)
            val inputStream = c.inputStream
            val totalSize = c.contentLength.toFloat() //size of apk

            val buffer = ByteArray(1024)
            var len1: Int
            var per: Float
            var downloaded = 0f
            while (inputStream.read(buffer).also { len1 = it } != -1) {
                fos.write(buffer, 0, len1)
                downloaded += len1
                per = (downloaded * 100 / totalSize)
                publishProgress(per.toInt())
            }
            fos.close()
            inputStream.close()
            openNewVersion(outputFile.path)
            flag = true
        } catch (e: MalformedURLException) {
            Log.e("DownloadApk", "Update Error: " + e.message)
            flag = false
        } catch (e: IOException) {
            e.printStackTrace()
        }

        return flag
    }

    private fun openNewVersion(location: String) {
        val intent = Intent(Intent.ACTION_VIEW)
        intent.setDataAndType(
            getUriFromFile(location),
            "application/vnd.android.package-archive"
        )
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
        intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
        context.get()?.startActivity(intent)
    }

    private fun getUriFromFile(filePath: String): Uri? {
        return if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
            Uri.fromFile(File(filePath))
        } else {
            context.get()?.let {
                FileProvider.getUriForFile(
                    it,
                    it.packageName + ".provider",
                    File(filePath)
                )    
            }
        }
    }
}

}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM