本來今天高高興興屈呕,想把之前封裝好的
DownloadManager
拿到新項目中使用微宝,但是一個個坑的我難受想哭棺亭。
原本的流程是,通過DownloadManager
下載Apk到本地蟋软,收到了下載完成廣播之后安裝镶摘。
第一坑
--
android.os.FileUriExposedException: file:///storage/emulated/0/xxx exposed beyond app through Intent.getData()
原來是我把targetSdk
設(shè)置到了24,以至于在將我的文件暴露給其他應(yīng)用時岳守,拋出了這個異常凄敢,下面是使用到的代碼。
Intent install = new Intent(Intent.ACTION_VIEW);
install.setDataAndType(apkUri, "application/vnd.android.package-archive");
install.setFlags(FLAG_ACTIVITY_NEW_TASK);
context.startActivity(install);
于是我就按這篇文章所說的湿痢,加入了FileProvider
涝缝,我下載好的文件存放在Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)
下,因此FileProvider
的xml是這樣設(shè)置的譬重。
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<!-- external-path 為 Environment.getExternalStorageDirectory() -->
<!-- Download 是Environment.DIRECTORY_DOWNLOADS 的目錄名稱 -->
<!-- downloads是uri中映射Download的名稱 -->
<external-path path="Download" name="downloads" />
</paths>
看下面這個圖就清楚了拒逮,圖片來源,侵刪臀规。通過FileProvider.getUriForFile(context, FILE_PROVIDER_NAME, file)
,獲得下載在公共存儲Download目錄下的apk文件的uri滩援,然后我將這個uri傳給安裝Intent
,應(yīng)該就沒問題了吧塔嬉。
圖樣玩徊,第二坑
java.lang.IllegalArgumentException: Failed to find configured root that contains /sdcard/storage/emulated/0/Download/apkFile.apk
在這個問答里,說是xml中的目錄寫錯了谨究,于是改來改去恩袱,不得其所。再看到這篇文章胶哲,原來是FileProvider
不支持sdcard
目錄下的文件共享畔塔。好吧,那我就把apk下載到我的私有目錄下,來修改DownloadManager
的參數(shù)俩檬。
public Request setDestinationUri(Uri uri) {
...
}
public Request setDestinationInExternalFilesDir(Context context, String dirType,String subPath) {
...
}
public Request setDestinationInExternalPublicDir(String dirType, String subPath) {
...
}
對萎胰,你沒看錯,指定地址的三個方法棚辽,都是存在sd卡上的技竟。咋搞。那我就在下載好了之后屈藐,把文件拷貝到我的私有目錄下榔组,這總行了吧。
注冊一個BroadcastReceiver
联逻,然后在onReceive()
中搓扯,將下載好的存放在sdcard中的apk拷貝到私有目錄files
文件夾內(nèi)的downloads
目錄,下面是BroadcastReceiver
的IntentFilter
和更改后的FileProvider
的xml包归。
IntentFilter filter = new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE);
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<!-- 注意锨推,這里改成了files-path -->
<files-path path="downloads" name="downloads" />
</paths>
測試通過
這里還有點要注意。
Intent install = new Intent(Intent.ACTION_VIEW);
install.setDataAndType(apkUri, "application/vnd.android.package-archive");
// 這里加上 FLAG_GRANT_READ_URI_PERMISSION 公壤,給目標程序讀改uri的權(quán)限换可。
install.setFlags(FLAG_GRANT_READ_URI_PERMISSION | FLAG_ACTIVITY_NEW_TASK);
context.startActivity(install);
總結(jié)
FileProvider
設(shè)置的本意是好的,避免直接暴露了應(yīng)用內(nèi)部的文件結(jié)構(gòu)厦幅。但是提供了external-path
獲取外部存儲空間卻不奏效沾鳄,很是疑惑,不知道是不是我哪里寫錯了确憨,如果有知道的讀者還請指點译荞。