Install Application programmatically on Android
Is possible to programmatically install a dynamically downloaded apk from a custom Android application.
Solution 1:
You can easily launch a market link or an install prompt:
Intent promptInstall = new Intent(Intent.ACTION_VIEW)
.setDataAndType(Uri.parse("file:///path/to/your.apk"),
"application/vnd.android.package-archive");
startActivity(promptInstall);
source
Intent goToMarket = new Intent(Intent.ACTION_VIEW)
.setData(Uri.parse("market://details?id=com.package.name"));
startActivity(goToMarket);
source
However, you cannot install .apks without user's explicit permission; not unless the device and your program is rooted.
Solution 2:
File file = new File(dir, "App.apk");
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.fromFile(file), "application/vnd.android.package-archive");
startActivity(intent);
I had the same problem and after several attempts, it worked out for me this way. I don't know why, but setting data and type separately screwed up my intent.
Solution 3:
The solutions provided to this question are all applicable to targetSdkVersion
s of 23 and below. For Android N, i.e. API level 24, and above, however, they do not work and crash with the following Exception:
android.os.FileUriExposedException: file:///storage/emulated/0/... exposed beyond app through Intent.getData()
This is due to the fact that starting from Android 24, the Uri
for addressing the downloaded file has changed. For instance, an installation file named appName.apk
stored on the primary external filesystem of the app with package name com.example.test
would be as
file:///storage/emulated/0/Android/data/com.example.test/files/appName.apk
for API 23
and below, whereas something like
content://com.example.test.authorityStr/pathName/Android/data/com.example.test/files/appName.apk
for API 24
and above.
More details on this can be found here and I am not going to go through it.
To answer the question for targetSdkVersion
of 24
and above, one has to follow these steps:
Add the following to the AndroidManifest.xml:
<application
android:allowBackup="true"
android:label="@string/app_name">
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="${applicationId}.authorityStr"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/paths"/>
</provider>
</application>
2. Add the following paths.xml
file to the xml
folder on res
in src, main:
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path
name="pathName"
path="pathValue"/>
</paths>
The pathName
is that shown in the exemplary content uri example above and pathValue
is the actual path on the system.
It would be a good idea to put a "." (without quotes) for pathValue in the above if you do not want to add any extra subdirectory.
-
Write the following code to install the apk with the name
appName.apk
on the primary external filesystem:File directory = context.getExternalFilesDir(null); File file = new File(directory, fileName); Uri fileUri = Uri.fromFile(file); if (Build.VERSION.SDK_INT >= 24) { fileUri = FileProvider.getUriForFile(context, context.getPackageName(), file); } Intent intent = new Intent(Intent.ACTION_VIEW, fileUri); intent.putExtra(Intent.EXTRA_NOT_UNKNOWN_SOURCE, true); intent.setDataAndType(fileUri, "application/vnd.android" + ".package-archive"); intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK); intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); context.startActivity(intent); activity.finish();
No permission is also necessary when writing to your own app's private directory on the external filesystem.
I have written an AutoUpdate library here in which I have used the above.
Solution 4:
Well, I dug deeper, and found sources of PackageInstaller application from Android Source.
https://github.com/android/platform_packages_apps_packageinstaller
From manifest I found that it require permission:
<uses-permission android:name="android.permission.INSTALL_PACKAGES" />
And the actual process of installation occurs after confirmation
Intent newIntent = new Intent();
newIntent.putExtra(PackageUtil.INTENT_ATTR_APPLICATION_INFO, mPkgInfo.applicationInfo);
newIntent.setData(mPackageURI);
newIntent.setClass(this, InstallAppProgress.class);
String installerPackageName = getIntent().getStringExtra(Intent.EXTRA_INSTALLER_PACKAGE_NAME);
if (installerPackageName != null) {
newIntent.putExtra(Intent.EXTRA_INSTALLER_PACKAGE_NAME, installerPackageName);
}
startActivity(newIntent);