很多開發(fā)者應(yīng)該都知道android7.0以上安裝apk的問題亚皂。但是看了一些文章束昵,并沒有很好的幫助我解決問題度气。而且還有的坑沒有被提到仿荆。
android7.0安裝apk會(huì)出現(xiàn)的問題和原因
google在android7.0以上,禁止直接通過file://形式的uri向另一個(gè)應(yīng)用傳遞文件uri鲤桥。所以導(dǎo)致安裝apk和相機(jī)拍照保存數(shù)據(jù)都會(huì)出現(xiàn)問題揍拆。google提供了FileProvider類來獲取文件uri。FileProvider的本質(zhì)也就是ContentProvider茶凳。
簡(jiǎn)單回顧下ContentProvider
ContentProvider做為android的四大組件之一嫂拴,它主要的作用就是夸進(jìn)程通信。從一個(gè)進(jìn)程讀取數(shù)據(jù)并提供給另一個(gè)進(jìn)程贮喧。ContentProvider的底層是Binder機(jī)制(和AIDL一樣)筒狠。
ContentProvider核心由三個(gè)部分組成
- uri: 統(tǒng)一資源標(biāo)識(shí)符 格式 content://com.aaa.bbb/user/1 。即:協(xié)議://授權(quán)(authority)/路徑/id箱沦。表明了訪問哪個(gè)進(jìn)程(com.aaa.bbb)的哪個(gè)文件(user)辩恼。相關(guān)的類有URIMather(根據(jù)uri匹配)和ContentUri(在uri后面添加和獲取id)。
- ContentResolver:用來幫助執(zhí)行ContentProvider中的增刪改查谓形,簡(jiǎn)化操作灶伊。
- ContentOberser:監(jiān)聽某個(gè)uri下面數(shù)據(jù)變化,使用觀察者模式寒跳。
創(chuàng)建一個(gè)ContentProvider步驟就是 清單文件注冊(cè)provider - 創(chuàng)建provider類聘萨,重寫增刪改查方法。訪問ContentProvider步驟就是 創(chuàng)建uri contentProvider ContentResolver - 調(diào)用api訪問童太。
為啥要回顧呢米辐?因?yàn)镕ileProvider就是ContentProvider。那么使用FileProvider好處是什么书释?當(dāng)然是增加開發(fā)者工作量翘贮,減少花錢時(shí)間。爆惧。 狸页。 好處大概是: 禁止過去的file://的方式向外部公開訪問(我猜測(cè)是setUri(file://xxx)這個(gè)xxx文件就會(huì)被賦予外部應(yīng)用的訪問權(quán)限。不然為啥要換FileProvider)检激,而通過FileProvider的方式給與臨時(shí)權(quán)限肴捉。官方解釋:
對(duì)于面向 Android 7.0 的應(yīng)用,Android 框架執(zhí)行的 StrictMode API 政策禁止在您的應(yīng)用外部公開 file:// URI叔收。如果一項(xiàng)包含文件 URI 的 intent 離開您的應(yīng)用,則應(yīng)用出現(xiàn)故障傲隶,并出現(xiàn) FileUriExposedException 異常饺律。
要在應(yīng)用間共享文件,您應(yīng)發(fā)送一項(xiàng) content:// URI跺株,并授予 URI 臨時(shí)訪問權(quán)限复濒。進(jìn)行此授權(quán)的最簡(jiǎn)單方式是使用 FileProvider 類脖卖。如需了解有關(guān)權(quán)限和共享文件的詳細(xì)信息,請(qǐng)參閱共享文件巧颈。
https://developer.android.com/about/versions/nougat/android-7.0-changes.html#accessibility
FileProvider如何使用
這是固定步驟畦木,不多贅述了。給個(gè)鴻洋的文章參考下:
https://blog.csdn.net/lmj623565791/article/details/72859156
但是我照著一模一樣的做了砸泛,剛打開安裝頁面就閃掉十籍。弄了大半天才發(fā)現(xiàn)問題。我使用的targetSdk為28唇礁,改成25就好了勾栗。為什么呢?原因是android8.0(ApiLevel26)以上需要添加權(quán)限盏筐,非正規(guī)來源apk的必須用戶手動(dòng)允許安裝围俘,才能進(jìn)行下面的安裝頁面操作。
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES"/>
/**
* 判斷是否是8.0系統(tǒng),是的話需要獲取此權(quán)限琢融,判斷開沒開界牡,沒開的話處理未知應(yīng)用來源權(quán)限問題,否則直接安裝
*/
private void checkIsAndroidO() {
if (Build.VERSION.SDK_INT >= 26) {
boolean b = getPackageManager().canRequestPackageInstalls();
if (b) {
publicApk();//安裝應(yīng)用的邏輯(寫自己的就可以)
} else {
//請(qǐng)求安裝未知應(yīng)用來源的權(quán)限
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.REQUEST_INSTALL_PACKAGES}, INSTALL_PACKAGES_REQUESTCODE);
}
} else {
installApk();
}
可以看看這篇文章
https://blog.csdn.net/kac930/article/details/79131671
到這里就結(jié)束了。這個(gè)權(quán)限的原因讓我找了大半天才找到漾抬。之前把時(shí)間都耗在查看代碼上宿亡,怎么都看不出來問題,同樣的代碼運(yùn)行demo就沒問題奋蔚,在我的app就有問題(target 28)她混。所以下次遇到問題要換個(gè)思路、方向不能死腦筋了泊碑。