Android Install APK with Intent.View_Action Not Working with File Provider

Android install apk with Intent.VIEW_ACTION not working with File provider

After a lot of trying I have been able to solve this by creating different Intents for anything lower than Nougat as using the FileProvider to create an install intent with Android Versions before Nougat causes the error:

ActivityNotFoundException: No Activity found to handle Intent { act=android.intent.action.INSTALL_PACKAGE dat=content://XXX.apk flg=0x1 }

While using a normal Uri on Android Nougat creates the following error:

FileUriExposedException: file:///XXX.apk exposed beyond app through Intent.getData()

My solution which is working for me with Android N on the emulator and a phone running Android M.

File toInstall = new File(appDirectory, appName + ".apk");
Intent intent;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
Uri apkUri = FileProvider.getUriForFile(activity, BuildConfig.APPLICATION_ID + ".fileprovider", toInstall);
intent = new Intent(Intent.ACTION_INSTALL_PACKAGE);
intent.setData(apkUri);
intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
} else {
Uri apkUri = Uri.fromFile(toInstall);
intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(apkUri, "application/vnd.android.package-archive");
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
}
activity.startActivity(intent);

UPDATE FOR Android Nougat 7.1:

You also need to add the permission REQUEST_INSTALL_PACKAGES in your manifest. Its available from Api Level 23 (Android 6.0 Marshmallow) and required from Level 25 (Android 7.1 Nougat).

UPDATE:

Remember to request the permissions for read and write to external storage if the file you try to install is on the external storage. And also to set up a correct FileProvider for Android Nougat and above.

First check if you have write permission by calling canReadWriteExternal() below, if not call requestPermission() before:

private static final int REQUEST_WRITE_PERMISSION = 786;

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
if (requestCode == REQUEST_WRITE_PERMISSION && grantResults[0] == PackageManager.PERMISSION_GRANTED)
Toast.makeText(this, "Permission granted", Toast.LENGTH_LONG).show();
}

private void requestPermission() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
requestPermissions(new String[]{ Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_WRITE_PERMISSION);
}

private boolean canReadWriteExternal() {
return Build.VERSION.SDK_INT < Build.VERSION_CODES.M ||
ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED;
}

Here is an example of a file provider for the Download folder on the external storage. AndroidManifest.xml:

<application ... >
...

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

resources/xml/filepaths.xml:

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path name="external_download" path="Download"/>
</paths>

If you get an error while installing the .apk saying something like "There is a problem parsing the package." it could be that you haven't asked for the read/write permission or the file you try to install doesn't exist or is corrupt.

UPDATE FOR Android Oreo 8.0:

You have to check if current application is allowed to install the APK on Android Oreo 8.0 or above.

You can check if your app is allowed to install APK by using canRequestPackageInstalls method of PackageManager class. If it returns false, then you can launch intent with ACTION_MANAGE_UNKNOWN_APP_SOURCES action to launch settings dialog where user can allow the app to install APKs.

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

unknownAppSourceDialog.launch(unknownAppSourceIntent);
} else {
// App already have the permission to install so launch the APK installation.
startActivity(intent);
}

Make sure you add the following code to your activity to receive the result of intent.

ActivityResultLauncher<Intent> unknownAppSourceDialog = registerForActivityResult(
new ActivityResultContracts.StartActivityForResult(),
result -> {
if (result.getResultCode() == Activity.RESULT_OK) {
// User has allowed app to install APKs
// so we can now launch APK installation.
startActivity(intent);
}
});

Trying to install apk with intent fails without error

Nevermind I made a typo in my AndroidManifest.xml.

How it was:

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

How it should be:

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

Notice that one space at the end?

Took me 3 days to find it...

intent to install apk on android N

I had many problems with it finally I found the answer. here is the answer hope its useful for you.

    File toInstall = new File(url);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
File newFile = new File(new File(Environment.getExternalStorageDirectory(), "apps"), getImageNameByUrl(appUrl));
Uri apkUri = getUriForFile(context, BuildConfig.APPLICATION_ID+".provider", newFile);
Intent intent = new Intent(Intent.ACTION_INSTALL_PACKAGE);
intent.setData(apkUri);
intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
context.startActivity(intent);
} else {
Uri apkUri = Uri.fromFile(toInstall);
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(apkUri, "application/vnd.android.package-archive");
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
}

manifest:

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

and file_paths:

<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path name="." path="." />
</paths>

and permission for API>25

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

No Activity found to handle Intent when using FileProvider

The package installer only supports content schemes starting on Android 7.0. Prior to that — and despite documentation to the contrary — the package installer only supports file schemes.

You will need to set the Uri on your Intent differently based on whether you are running on Android 7.0+ or not, such as by branching on Build.VERSION.SDK_INT.

FileProvider: Installing APK. There was an error parsing the package.

For anyone who has the same problem.
I had to specify the exactly folder with getExternalFilesDir();

MainActivity

public class MainActivity extends AppCompatActivity {

Button btnStartIntentFileProvider;
String strRootPathInternalStorage = Environment.getExternalStorageDirectory().toString();
String strApkToInstall = "app-debug.apk";

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

btnStartIntentFileProvider = (Button)findViewById(R.id.btnFileProvider);
btnStartIntentFileProvider.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {

File fileApkToInstall = new File(getExternalFilesDir("Download"), strApkToInstall);

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
Uri apkUri = FileProvider.getUriForFile(MainActivity.this, BuildConfig.APPLICATION_ID + ".provider", fileApkToInstall);
Intent intent = new Intent(Intent.ACTION_INSTALL_PACKAGE);
intent.setData(apkUri);
intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
MainActivity.this.startActivity(intent);
} else {
Uri apkUri = Uri.fromFile(fileApkToInstall);
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(apkUri, "application/vnd.android.package-archive");
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
MainActivity.this.startActivity(intent);
}
}
});
}
}

Manifest

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.spicysoftware.test">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="com.spicysoftware.test.provider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/provider_paths"/>
</provider>

<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>

provider_paths (in XML Folder)

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-files-path name="Download" path="Download/" />
</paths>


Related Topics



Leave a reply



Submit