Android 開發:apk文件的安裝6.0,7.0,8.0踩坑筆記

最近在作 APP 的升級功能,須要在 apk 文件下載下來以後安裝,我本覺得是個很簡單的功能,直接調用系統的接口就完事了,沒想到仍是有很多坑的。php

Android 6.0 版本的安裝

這個最常規,在6.0版本及以前版本都是通用的。java

/** * 安裝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);
}
複製代碼

Android 7.0 版本的安裝

上面的代碼在 Android 7.0 及以上版本安裝 apk 則會遇到 android.os.FileUriExposedException 問題。官方給出的解釋是:android

對於面向 Android 7.0 的應用,Android 框架執行的 StrictMode API 政策禁止在您的應用外部公開 file:// URI。若是一項包含文件 URI 的 intent 離開您的應用,則應用出現故障,並出現 FileUriExposedException 異常。bash

解決方案以下:app

1.在 AndroidManifest.xml 中添加以下代碼:框架

<provider android:name="android.support.v4.content.FileProvider" android:authorities="你的包名.fileProvider" android:grantUriPermissions="true" android:exported="false">
            <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths" />
        </provider>
複製代碼

注意ide

authorities:你app的包名.fileProvider
grantUriPermissions:必須是true,表示授予 URI 臨時訪問權限
exported:必須是false
resource:中的@xml/file_paths是咱們接下來要添加的文件
複製代碼

還有額外的坑☠️

我在使用過程當中添加以上 provider 代碼以後,遇到了 manifest 合併衝突問題:ui

Error:Execution failed for task ':app:processDebugManifest'.
> Manifest merger failed with multiple errors, see logs
複製代碼

解決方案:因爲多個lib庫中定義類相同因此衝突,集成FileProvider重寫個類便可。沒有遇到此問題則能夠略過。代碼以下:spa

public class InstallApkProvider extends FileProvider {
}
複製代碼

因此我在 Manifest 中添加的代碼以下:code

<provider android:name=".InstallApkProvider" android:authorities="個人包名.fileProvider" android:exported="false" android:grantUriPermissions="true">
    <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths" />
</provider>
複製代碼

2.在res/xml下新建file_paths.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>
複製代碼

注意

path:須要臨時受權訪問的路徑
name:就是你給這個訪問路徑起個名字
複製代碼

3.Android 7.0 的構建 Uri 在6.0時代,直接使用 Uri.fromFile(apkFile)構建出一個Uri,如今咱們使用

FileProvider.getUriForFile(context, BuildConfig.APPLICATION_ID + ".fileProvider", apkFile);
複製代碼

BuildConfig.APPLICATION_ID 直接是應用的包名。

到這裏,咱們就能夠愉快的在7.0上安裝 apk 了。代碼以下:

/** * 安裝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);
    }
複製代碼

Android 8.0 版本的安裝

若是你的系統版本是 8.0+,那你須要多加一個權限,不然仍是不行滴!🤣

<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES"/>
複製代碼

總結

就這樣,咱們徹底搞定了 apk 文件在不一樣 Android 版本系統上的安裝。撒花🎉

相關文章
相關標籤/搜索