'How to install any Android app programmatically in Android 10

In Android 9 & 10 I face issued in install app programmatically in Android Studio using filepath apk file. Below show what I tried..

Intent intent = new Intent("android.intent.action.VIEW");
intent.addCategory("android.intent.category.DEFAULT");
intent.setDataAndType(Uri.parse("content://"+Environment.getExternalStorageDirectory() + "/download/" + "app-release.apk"), "application/vnd.android.package-archive");
startActivity(intent);

I also added required permission in manifest file .

When I run this then it give me There was a problem parsing the package error.



Solution 1:[1]

If you want install application programmatically in Android 10, You need to give permission to install app for your application

Steps 1: Give permission in Manifest

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

Step 2: Write provider in Android Manifest

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

Step 4: Create file in XML folder named as provider_paths.xml and write

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <external-path
        name="files_root"
        path="Android/data/${applicationId}" />
    <external-path
        name="external_files"
        path="." />
</paths>

step 4: Give runtime permission for apk installation and storage permissions

    //installtion permission

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                if (!getPackageManager().canRequestPackageInstalls()) {
                    startActivityForResult(new Intent(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES).setData(Uri.parse(String.format("package:%s", getPackageName()))), 1234);
                } else {
                }
    }

    //Storage Permission

    if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
                ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE,Manifest.permission.READ_EXTERNAL_STORAGE}, 1);
            }

            if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
                ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1);
    }

Step 5: Call install apk function

 void installAPK(){

    String PATH = Environment.getExternalStorageDirectory() + "/" + "apkname.apk";
    File file = new File(PATH);
    if(file.exists()) {
        Intent intent = new Intent(Intent.ACTION_VIEW);
        intent.setDataAndType(uriFromFile(getApplicationContext(), new File(PATH)), "application/vnd.android.package-archive");
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
        try {
            getApplicationContext().startActivity(intent);
        } catch (ActivityNotFoundException e) {
            e.printStackTrace();
            Log.e("TAG", "Error in opening the file!");
        }
    }else{
        Toast.makeText(getApplicationContext(),"installing",Toast.LENGTH_LONG).show();
    }
}
Uri uriFromFile(Context context, File file) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
        return FileProvider.getUriForFile(context, BuildConfig.APPLICATION_ID + ".provider", file);
    } else {
        return Uri.fromFile(file);
    }
}

Solution 2:[2]

First, your Uri is invalid on every version of Android, outside of a few devices where the device manufacturer hacked in something for you.

Second, by default, neither you nor the package installer process have access to external storage on Android 10.

Third, installing apps via ACTION_VIEW or ACTION_INSTALL_PACKAGE is deprecated on Android 10.

The solution for Android 10 and higher — which also works on Android 5.0 and higher — is to use PackageInstaller.

This sample app demonstrates how to use it. The key pieces are in MainMotor:

/*
  Copyright (c) 2019 CommonsWare, LLC

  Licensed under the Apache License, Version 2.0 (the "License"); you may not
  use this file except in compliance with the License. You may obtain   a copy
  of the License at http://www.apache.org/licenses/LICENSE-2.0. Unless required
  by applicable law or agreed to in writing, software distributed under the
  License is distributed on an "AS IS" BASIS,   WITHOUT WARRANTIES OR CONDITIONS
  OF ANY KIND, either express or implied. See the License for the specific
  language governing permissions and limitations under the License.

  Covered in detail in the book _Elements of Android Q

  https://commonsware.com/AndroidQ
*/

package com.commonsware.q.appinstaller

import android.app.Application
import android.app.PendingIntent
import android.content.Intent
import android.content.pm.PackageInstaller
import android.net.Uri
import androidx.documentfile.provider.DocumentFile
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext

private const val NAME = "mostly-unused"
private const val PI_INSTALL = 3439

class MainMotor(app: Application) : AndroidViewModel(app) {
  private val installer = app.packageManager.packageInstaller
  private val resolver = app.contentResolver

  fun install(apkUri: Uri) {
    viewModelScope.launch(Dispatchers.Main) {
      installCoroutine(apkUri)
    }
  }

  private suspend fun installCoroutine(apkUri: Uri) =
    withContext(Dispatchers.IO) {
      resolver.openInputStream(apkUri)?.use { apkStream ->
        val length =
          DocumentFile.fromSingleUri(getApplication(), apkUri)?.length() ?: -1
        val params =
          PackageInstaller.SessionParams(PackageInstaller.SessionParams.MODE_FULL_INSTALL)
        val sessionId = installer.createSession(params)
        val session = installer.openSession(sessionId)

        session.openWrite(NAME, 0, length).use { sessionStream ->
          apkStream.copyTo(sessionStream)
          session.fsync(sessionStream)
        }

        val intent = Intent(getApplication(), InstallReceiver::class.java)
        val pi = PendingIntent.getBroadcast(
          getApplication(),
          PI_INSTALL,
          intent,
          PendingIntent.FLAG_UPDATE_CURRENT
        )

        session.commit(pi.intentSender)
        session.close()
      }
    }
}

Here, install() is given a Uri from ACTION_OPEN_DOCUMENT. Inside of a coroutine, I create a PackageInstaller session, open the session, copy the APK contents to a session-supplied stream, then commit and close the session.

Solution 3:[3]

Add the following permission in your manifest file.

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

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Vishwajeet Barve
Solution 2 CommonsWare
Solution 3 Richard Kamere