適配Android N遇到的兩個問題

月光邊境發表於2018-01-18

####一:通過DownloadManager下載檔案 在API 24以前我們通過 String filePath=cursor.getString(cursor.getColumnIndex(DownloadManager.COLUMN_LOCAL_FILENAME));這種方式來獲取下載完成後的檔案路徑,但是在Android N上面使用這種方法會丟擲SecurityException解決方法: 方法1:將targetSdkVersion指定到24以下,targetSdkVersion 23; 方法2:修改DownloadManager.Request的下載路徑,例如: request.setDestinationInExternalFilesDir(this, "apk", "test.apk"); 先獲取下載的Uri,然後根據Uri獲取檔案的路徑

        String uri = cursor.getString(cursor.getColumnIndex(DownloadManager.COLUMN_LOCAL_URI));
        if (uri != null) {
            File file= new File(Uri.parse(uri).getPath());
            String filePath = file.getAbsolutePath();
            Log.d(TAG, "downloadFilePath->" + filePath);
        }
複製程式碼

####二: 應用間共享檔案 看官方說明

對於面向 Android 7.0 的應用,Android 框架執行的StrictModeAPI 政策禁止在您的應用外部公開file://URI。如果一項包含檔案 URI 的 intent 離開您的應用,則應用出現故障,並出現FileUriExposedException異常。 要在應用間共享檔案,您應傳送一項content://URI,並授予 URI 臨時訪問許可權。進行此授權的最簡單方式是使用FileProvider類。如需瞭解有關許可權和共享檔案的詳細資訊,請參閱共享檔案

大概每個應用都有這種使用場景,在應用升級更新的時候,我們會將下載完成的Apk檔案以一個Intent傳送出去,讓系統安裝應用。 在Android N以前,我們的做法:

        Intent intent = new Intent(Intent.ACTION_VIEW);
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        intent.setDataAndType(Uri.parse("file://" + filename), "application/vnd.android.package-archive");
        startActivity(intent);
複製程式碼

在Android N上面這種方式會丟擲FileUriExposedException異常。 適配Android N的方法:

  1. 在manifest中新增配置
        <provider
            android:name="android.support.v4.content.FileProvider"
            android:authorities="@string/fileProvider_authorities"
            android:grantUriPermissions="true"
            android:exported="false">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/file_paths" />
        </provider>
複製程式碼
  1. 在res目錄下建立xml/file_paths檔案,只有在file_paths中配置的目錄下的檔案才可以在應用間共享
<?xml version="1.0" encoding="utf-8"?>
<paths>
    <external-path
        name="external-path"
        path="." />
    <cache-path
        name="cache-path"
        path="." />
    <files-path
        name="files-path"
        path="." />
</paths>
複製程式碼

對應關係:

  • external-path 對應 Environment.getExternalStorageDirectory()
  • cache-path對應 getCacheDir()
  • files-path對應 getFilesDir() path指定對應目錄下的子目錄, path="." 表示該目錄下所有子目錄
  1. 共享檔案
        Intent intent = new Intent(Intent.ACTION_VIEW);
        intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
        Uri contentUri = FileProvider.getUriForFile(context, getString(R.string.fileProvider_authorities), new File(filePath));
        intent.setDataAndType(contentUri, "application/vnd.android.package-archive");
        startActivity(intent);
複製程式碼

相關文章