Recently, I am working on the APP upgrade function, which needs to be installed after the APK file is downloaded. I thought it was a very simple function, which can be completed by directly calling the interface of the system, but I did not expect that there are still many pits.
Android version 6.0 installation
This is the most common, and is common in version 6.0 and earlier.
/** * Install apK **@param* /
public static void install(Context mContext, File file) {
Intent install = new Intent(Intent.ACTION_VIEW);
install.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
install.setDataAndType(Uri.fromFile(file), "application/vnd.android.package-archive");
mContext.startActivity(install);
}
Copy the code
Android 7.0 installation
The above code in Android version 7.0 and above to install apk will meet Android. The OS. FileUriExposedException problem. The official explanation:
For Android 7.0 oriented applications, StrictMode API policies enforced by the Android framework prohibit exposing the file:// URI outside of your application. If an intent containing the URI of the file leaves your application, the application fails and a FileUriExposedException occurs.
Solutions are as follows:
1. Add the following code to androidmanifest.xml:
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="Your package name.fileProvider"
android:grantUriPermissions="true"
android:exported="false">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" />
</provider>
Copy the code
Pay attention to
Authorities: the package name of your app fileProvider grantUriPermissions: must betrueExported: Specifies that a URI is granted temporary access permissionfalse@xml/ File_paths in Resource: is the file we will add nextCopy the code
There are additional pits ☠️
I encountered manifest merge conflicts after adding the above provider code in the use process:
Error:Execution failed for task ':app:processDebugManifest'.
> Manifest merger failed with multiple errors, see logs
Copy the code
Solution: Because multiple lib libraries define the same class and therefore conflict, integrate FileProvider to rewrite the class. If this problem is not encountered, you can skip it. The code is as follows:
public class InstallApkProvider extends FileProvider {}Copy the code
So I added the following code to the Manifest:
<provider
android:name=".InstallApkProvider"
android:authorities="My package name.fileProvider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" />
</provider>
Copy the code
2. Create file_paths.xml under RES/XML
<?xml version="1.0" encoding="utf-8"? >
<resources>
<paths>
<root-path name="root" path="" />
<files-path name="files" path="" />
<cache-path name="cache" path="" />
<external-path name="external" path="" />
<external-files-path name="external_file_path" path="" />
<external-cache-path name="external_cache_path" path="" />
</paths>
</resources>
Copy the code
Pay attention to
Path: indicates the path that requires temporary authorization. Name: indicates that you give the access path a nameCopy the code
In 6.0, uri.fromfile (apkFile) was used directly to construct a Uri. Now we use uri.fromfile
FileProvider.getUriForFile(context, BuildConfig.APPLICATION_ID + ".fileProvider", apkFile);
Copy the code
Buildconfig. APPLICATION_ID is directly the package name of the application.
At this point, we are happy to install APK on 7.0. The code is as follows:
/** * Install apK **@param* /
public static void install(Context mContext, File file) {
Intent install = new Intent(Intent.ACTION_VIEW);
install.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
install.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
Uri contentUri = FileProvider.getUriForFile(mContext, "com.skycar.vehicleassistor.fileProvider", file);
install.setDataAndType(contentUri, "application/vnd.android.package-archive");
} else {
install.setDataAndType(Uri.fromFile(file), "application/vnd.android.package-archive");
}
mContext.startActivity(install);
}
Copy the code
Android 8.0 installation
If you are running 8.0+, you need to add an extra permission, otherwise it still won’t work! 🤣
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES"/>
Copy the code
conclusion
That’s it. We’re done installing apK files on different Versions of Android. Then spend 🎉