Android7.0系統使用Intent跳轉到APK安裝頁

轉載請注明出處:http://www.lxweimin.com/p/b566fa29a76e
本文出自Shawpoo的簡書
我的博客:CSDN博客

前言

昨天在開發的時候遇到這樣一個問題,在APP中更新版本下載完最新的apk之后沒有跳轉到應用安裝頁面。然后我換了個手機又進行測試了一下是可以的,這就怪了。我的代碼是這樣寫的:

    /**
     * @param file
     * @return
     * @Description 安裝apk
     */
    public void installApk(File file) {
        Intent intent = new Intent();
        intent.setAction(Intent.ACTION_VIEW);
        intent.setDataAndType(Uri.fromFile(file),
                "application/vnd.android.package-archive");
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        context.startActivity(intent);
    } 

打開安裝頁面不就是這樣嗎?難道還有其他的方法?正在趕項目的我遇到這個問題真是一臉懵逼,不知所措...


見鬼了?

查看了Studio的loacat才發現拋了一個異常:

FileUriExposedException

后來發現只有Android7.0的系統會報這個錯:

android.os.FileUriExposedException

為什么會這樣?難道是系統版本搞的鬼?沒錯,大胸弟,你的猜想一點沒錯,導致這個錯誤就是由于Android7.0系統引起的。

查詢Android開發官網可知:

了解:Android7.0 系統權限更改

為了提高私有文件的安全性,面向 Android 7.0 或更高版本的應用私有目錄被限制訪問 (0700)。此設置可防止私有文件的元數據泄漏,如它們的大小或存在性。此權限更改有多重副作用:

上面三條更改總之就是,對用戶私有的文件訪問更加嚴格,在訪問的時候需要使用特定的類和方法,而不像之前的系統那么容易,雖然這種限制不能完全得到控制,但是官方強烈反對放寬私有目錄的權限。

看到上面第二條,貌似和安裝APK所報的異常一樣,根據提示,看來需要使用FileProvider才能解決此異常的出現了。

進入正題:開始解決異常

1、定義FileProvider

在Androidmanifest.xml文件中聲明:

<manifest>
    ...
    <application>
        ...
        <provider
            android:name="android.support.v4.content.FileProvider"
            android:authorities="com.shawpoo.app.fileprovider" //自定義名字 為避免重復建議設為:包名.fileprovider
            android:exported="false"
            android:grantUriPermissions="true">
            ...
        </provider>
        ...
    </application>
</manifest>

2、指定可用的文件路徑

在項目的res目錄下,創建xml文件夾,并新建一個file_paths.xml文件。通過這個文件來指定文件路徑:

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

有多種指定路徑,在<paths>標簽內應至少包含一種,或者多種。

  • a、表示應用程序內部存儲區中的文件/子目錄中的文件
<files-path name="name" path="image" />

等同于Context.getFileDir() : /data/data/com.xxx.app/files/image

  • b、表示應用程序內部存儲區緩存子目錄中的文件
<cache-path name="name" path="image" />

等同于Context.getCacheDir() : /data/data/com.xxx.app/cache/image

  • c、表示外部存儲區根目錄中的文件
<external-path name="name" path="image" />

等同于Environment.getExternalStorageDirectory() : /storage/emulated/image

  • d、表示應用程序外部存儲區根目錄中的文件
<external-files-path name="name" path="image" />

等同于Context.getExternalFilesDir(String) / Context.getExternalFilesDir(null) : /storage/emulated/0/Android/data/com.xxx.app/files/image

  • e、表示應用程序外部緩存區根目錄中的文件
<external-cache-path name="name" path="image" />

等同于Context.getExternalCacheDir() : /storage/emulated/0/Android/data/com.xxx.app/cache/image

3、引用指定的路徑

在剛才Androidmanifest.xml中聲明的provider進行關聯:

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

4、生成文件的Uri

File imagePath = new File(Context.getFilesDir(), "images");
File newFile = new File(imagePath, "default_image.jpg");
Uri contentUri = getUriForFile(getContext(), "com.shawpoo.app.fileprovider", newFile);

5、給Uri授予臨時權限

intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);

所以最終安裝apk的方法可以這么寫了:

    /**
     * @param file
     * @return
     * @Description 安裝apk
     */
    protected void installApk(File file) {
        Intent intent = new Intent(Intent.ACTION_VIEW);
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { // 7.0+以上版本
            Uri apkUri = FileProvider.getUriForFile(context, "com.shawpoo.app.fileprovider", file); //與manifest中定義的provider中的authorities="com.shawpoo.app.fileprovider"保持一致 
            intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
            intent.setDataAndType(apkUri, "application/vnd.android.package-archive");
        } else {
            intent.setDataAndType(Uri.fromFile(file), "application/vnd.android.package-archive");
        }
        context.startActivity(intent);
    }

總結:好多東西還是得多查API吶~雖然英文是硬傷...

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容