Android 7.0系統代碼調用安裝apk時報錯FileUriExposedException完美解決

項目更新遇到問題

  Android項目開發中常常遇到下載更新的需求,之前調用系統安裝器執行安裝操做代碼以下:html

Intent intent = new Intent();
intent.setAction(android.content.Intent.ACTION_VIEW);
intent.setDataAndType(Uri.fromFile(new File(path)), "application/vnd.android.package-archive");
context.startActivity(intent);

  若是Android系統爲7.0及以上時則會報異常FileUriExposedException,這是因爲安卓官方爲了提升私有文件的安全性,面向 Android 7.0 或更高版本的應用私有目錄被限制訪問 (0700)。此設置可防止私有文件的元數據泄漏,如它們的大小或存在性。傳遞file:// URI 可能給接收器留下沒法訪問的路徑。所以,嘗試傳遞 file:// URI 會觸發 FileUriExposedException。所以須要使用 FileProvider。java

Android7.0系統使用FileProvider安裝apk安裝步驟:

1.manifest.xml文件配置:定義一個FileProvider

<application
        android:allowBackup="true"
        android:label="@string/app_name"
        android:icon="@mipmap/ic_launcher"
        android:theme="@style/AppTheme">

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

2.添加可用權限的文件目錄

  在項目res路徑下新建名爲xml的路徑,在xml路徑下新建名爲file_paths.xml的文件,在file_paths.xml文件中增長以下內容指定分享的路徑:android

<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
    <external-path path="Android/data/packageName/" name="files_root" />
</PreferenceScreen>

3.使用provider直接安裝apk:

Intent intent = new Intent();
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
Uri contentUri = FileProvider.getUriForFile(context, context.getPackageName() + ".fileprovider", new File(path));
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.setDataAndType(contentUri, context.getContentResolver().getType(contentUri));
//指定打開文件所調用的Activity,若不指定,則會彈出打開方式選擇框,
intent.setClassName("com.android.packageinstaller","com.android.packageinstaller.PackageInstallerActivity");
context.startActivity(intent);

完美適配全部系統版本進行apk安裝的方式

  如上代碼雖然能夠在Android7.0系統中正常安裝apk,可是在低於Android7.0的系統中則不起做用,因此對apk安裝調用方法進行封裝,完美適配全部系統版本進行apk的安裝調用。安全

/**
     * 安裝apk
     * 
     * @param context Application對象
     * @param path
     *            apk路徑
     */
    public static void InstallApk(Context context, String path) {

        Intent intent = new Intent();

        if (Build.VERSION.SDK_INT >= 24) {//Android 7.0以上
            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            Uri contentUri = FileProvider.getUriForFile(context, context.getPackageName() + ".fileprovider", new File(path));
            intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
            intent.setDataAndType(contentUri, context.getContentResolver().getType(contentUri));
            //指定打開文件所調用的Activity
            intent.setClassName("com.android.packageinstaller", "com.android.packageinstaller.PackageInstallerActivity");
        } else {
            intent.setAction(android.content.Intent.ACTION_VIEW);
            intent.setDataAndType(Uri.fromFile(new File(path)), "application/vnd.android.package-archive");
        }
        context.startActivity(intent);
    }

注意事項:

  清單文件配置的authorities的值必須與FileProvider.getUriForFile(context, context.getPackageName() + ".fileprovider", new File(path));方法中第二個參數一致。app

相關文章
相關標籤/搜索