Issue with in-app update implementation on Android 13 Go without Google Play Services

76 views Asked by At

I'm working on an IoT smart module that runs on Android 13 Go, and it doesn't have Google Play Services. I am trying to implement an in-app update functionality where the app can be updated on a button click. Currently, I am able to download the APK from a URL successfully, but I'm facing issues with the installation process using the PackageInstaller. After downloading, I don't receive any response from the installApk function, and the app doesn't seem to be updated.

Code

    private fun downloadAndInstallApk(apkUrl: String) {
    val request = DownloadManager.Request(Uri.parse(apkUrl))
        .setTitle("Sensor")
        .setDescription("Downloading")
        .setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED)
        .setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, "sensor.apk")

    val downloadManager = getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager
    downloadId = downloadManager.enqueue(request)

    // Register a BroadcastReceiver to listen for the download completion
    val filter = IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE)
    registerReceiver(downloadReceiver, filter)
}

private val downloadReceiver = object : BroadcastReceiver() {
    @SuppressLint("Range")
    override fun onReceive(context: Context?, intent: Intent?) {
        if (intent?.action == DownloadManager.ACTION_DOWNLOAD_COMPLETE) {
            val downloadManager = getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager

            val query = DownloadManager.Query().setFilterById(downloadId)
            val cursor = downloadManager.query(query)

            if (cursor.moveToFirst()) {
                val columnIndex = cursor.getColumnIndex(DownloadManager.COLUMN_STATUS)

                if (DownloadManager.STATUS_SUCCESSFUL == cursor.getInt(columnIndex)) {
                    val uri =
                        Uri.parse(cursor.getString(cursor.getColumnIndex(DownloadManager.COLUMN_LOCAL_URI)))

                    Log.i(TAG, "onReceive: $uri")
                    // Install the APK directly without copying to cache
                    installApk(uri)
                } else {
                    Toast.makeText(this@LandingActivity, "Download failed", Toast.LENGTH_SHORT)
                        .show()
                }
            }

            cursor.close()
        }
    }
}

private fun installApk(uri: Uri) {
    Log.i(TAG, "installApk: $uri")
    val packageInstaller = packageManager.packageInstaller
    val params = PackageInstaller.SessionParams(PackageInstaller.SessionParams.MODE_FULL_INSTALL)

    val sessionId = packageInstaller.createSession(params)
    val session = packageInstaller.openSession(sessionId)

    try {
        val inputStream = contentResolver.openInputStream(uri)
        val outputStream = session.openWrite("package", 0, -1)

        inputStream.use { input ->
            outputStream.use { output ->
                input!!.copyTo(output)
            }
        }

        val intent = Intent(this, javaClass)
        val pendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_IMMUTABLE)
        session.commit(pendingIntent.intentSender)
    } finally {
        session.close()
    }
}

Manifest

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

    <provider
        android:name="androidx.core.content.FileProvider"
        android:authorities="${applicationId}.fileprovider"
        android:exported="false"
        android:grantUriPermissions="true">
        <meta-data
            android:name="android.support.FILE_PROVIDER_PATHS"
            android:resource="@xml/file_paths" />
    </provider>

I've implemented a downloadAndInstallApk function that successfully downloads the APK and triggers the installApk function. However, after the download, the installation doesn't seem to proceed as expected. I've used a BroadcastReceiver to listen for the download completion and initiate the installation process.

Specific Concerns:

Is there an issue with how I'm using the PackageInstaller? Am I missing any critical steps in the installation process? I've included the necessary permissions and a FileProvider in the manifest. Is there anything else needed for proper file access? Additional Information:

I'm targeting Android 13 Go without Google Play Services. I'm using a FileProvider for file access. Any insights or suggestions on how to resolve this issue would be greatly appreciated. Thank you!

0

There are 0 answers