Install Apk 兼容性問題

問題描述

現(xiàn)象

代碼執(zhí)行安裝Apk刽酱,出現(xiàn)系統(tǒng)彈框解析錯誤喳逛,解析包時出現(xiàn)錯誤

場景

在華為P20 Android 8.0 手機(jī)上,下載Apk并使用通知欄進(jìn)度條顯示棵里,開啟應(yīng)用鎖屏通知權(quán)限润文,下載過程在鎖屏情況下進(jìn)行,下載完成后自動執(zhí)行安裝Apk殿怜,在解鎖后出現(xiàn)系統(tǒng)彈框典蝌,解析包出現(xiàn)錯誤。

解決之前安裝Apk的方法

首先在AndroidManifest中聲明fileProvider
  <provider
            android:name="android.support.v4.content.FileProvider"
            android:authorities="${applicationId}.fileprovider"
            android:exported="false"
            android:grantUriPermissions="true">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/file_path" />
        </provider>

provider屬性說明

屬性 說明
name android V4 包中的類FileProvider
authorities 你的文件的Uri的域名一般以包名.fileprovider的格式头谜,防止重名
exported 設(shè)置不允許導(dǎo)出骏掀,我們的FileProvider應(yīng)該是私有的
grantUriPermissions 允許獲取文件的臨時訪問權(quán)限
resourse 設(shè)置FileProvider訪問的文件路徑

res包下創(chuàng)建file_path.xml

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <external-path
        name="external_path"
        path="test" />

    <cache-path
        name="internal_path"
        path="test" />
        
        這里可以創(chuàng)建很多個paths,但是每個paths的name不能一樣
        

</paths>

path 說明

  <files-path name="*name*" path="*path*" />   對應(yīng)的是:Context.getFileDir()的路徑地址
   
     對應(yīng)路徑:Context.getFileDir()+"/${path}/"
     得到路徑:content://${applicationId}/&{name}/

     <cache-path name="*name*" path="*path*" />  
     對應(yīng)路徑:Context.getCacheFir()+"/${path}/"
     得到路徑:content://${applicationId}/&{name}/


     <external-path name="*name*" path="*path*" />  
     對應(yīng)路徑:Environment.getExternalStorageDirectory()+"/${path}/"
     得到路徑:content://${applicationId}/&{name}/

     <external-files-path name="*name*" path="*path*" />  
     對應(yīng)路徑:Context.getExternalStorageDirectory()+"/${path}/"
     得到路徑:content://${applicationId}/&{name}/

     <external-cache-path name="*name*" path="*path*" />   
     對應(yīng)路徑: Context.getExternalCacheDir()+"/${path}/"
     得到路徑:content://${applicationId}/&{name}/

舉個例子說明:

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

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

contentUri值為:content://com.mydomain.fileprovider/my_images/default_image.jpg
安裝apk的方法(7.0版本兼容問題)
 public static void installApk(Context context,File apkFile){
        try {
            Intent intent = new Intent(Intent.ACTION_VIEW);
            Uri apkUri = null;
            //判斷版本是否是 7.0 及 7.0 以上
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                apkUri = FileProvider.getUriForFile(context, BuildConfig.APPLICATION_ID + ".fileProvider", apkFile);
                //添加對目標(biāo)應(yīng)用臨時授權(quán)該Uri所代表的文件
                intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
                intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
            } else {
                apkUri = Uri.fromFile(apkFile);
            }
            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            intent.setDataAndType(apkUri,
                    "application/vnd.android.package-archive");
            context.startActivity(intent);
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

Android 8.0系統(tǒng)需要聲明權(quán)限
 <uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGE" />

OK,以上就是大家普遍解決7.0柱告,以及8.0版本兼容問題的方法截驮。

但是,在上文描述的場景中依然報出了錯誤:

java.lang.SecurityException: Permission Denial: 
opening provider android.support.v4.content.FileProvider from ProcessRecord{cc3ad2316425:
com.android.packageinstaller/u0a21} (pid=16425, uid=10021) that is not exported from uid 10340
懵逼.jpg

問題定位

經(jīng)過短暫的懵逼后际度,開始通過各種方式侧纯,探索問題的原因。

根據(jù)系統(tǒng)log分析甲脏,猜測在鎖屏?xí)r眶熬,用于安裝Apk的service處于休眠或者不可用的狀態(tài),導(dǎo)致通過intent.addflags方式賦予的臨時權(quán)限失效了块请。于是娜氏,再次仔細(xì)看了官方文檔后,發(fā)現(xiàn)還有一個方法墩新,可以生成權(quán)限且在主動調(diào)用方法或者手機(jī)重啟后才會失效贸弥。

改進(jìn)后的代碼

public static void installApk(Context context,File apkFile){
        try {
            Intent intent = new Intent(Intent.ACTION_VIEW);
            Uri apkUri = null;
            //判斷版本是否是 7.0 及 7.0 以上
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                apkUri = FileProvider.getUriForFile(context, BuildConfig.APPLICATION_ID + ".fileProvider", apkFile);
                //添加對目標(biāo)應(yīng)用臨時授權(quán)該Uri所代表的文件
                intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
                intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
            } else {
                apkUri = Uri.fromFile(apkFile);
            }
            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            intent.setDataAndType(apkUri,
                    "application/vnd.android.package-archive");
            //查詢所有符合 intent 跳轉(zhuǎn)目標(biāo)應(yīng)用類型的應(yīng)用,注意此方法必須放置setDataAndType的方法之后
                    List<ResolveInfo> resInfoList = context.getPackageManager().queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);
                    //然后全部授權(quán)
                    for (ResolveInfo resolveInfo : resInfoList) {
                        String packageName = resolveInfo.activityInfo.packageName;
                        context.grantUriPermission(packageName, apkUri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION);
                    }        
            context.startActivity(intent);
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

//對應(yīng)取消權(quán)限的方法是
context.revokeUriPermission(uri, modeFlags)

再次嘗試海渊,此問題再沒有出現(xiàn)绵疲。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市臣疑,隨后出現(xiàn)的幾起案子盔憨,更是在濱河造成了極大的恐慌,老刑警劉巖讯沈,帶你破解...
    沈念sama閱讀 218,122評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件郁岩,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)问慎,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,070評論 3 395
  • 文/潘曉璐 我一進(jìn)店門萍摊,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人如叼,你說我怎么就攤上這事冰木。” “怎么了笼恰?”我有些...
    開封第一講書人閱讀 164,491評論 0 354
  • 文/不壞的土叔 我叫張陵踊沸,是天一觀的道長。 經(jīng)常有香客問我挖腰,道長,這世上最難降的妖魔是什么练湿? 我笑而不...
    開封第一講書人閱讀 58,636評論 1 293
  • 正文 為了忘掉前任猴仑,我火速辦了婚禮,結(jié)果婚禮上肥哎,老公的妹妹穿的比我還像新娘辽俗。我一直安慰自己,他們只是感情好篡诽,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,676評論 6 392
  • 文/花漫 我一把揭開白布崖飘。 她就那樣靜靜地躺著,像睡著了一般杈女。 火紅的嫁衣襯著肌膚如雪朱浴。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,541評論 1 305
  • 那天达椰,我揣著相機(jī)與錄音翰蠢,去河邊找鬼。 笑死啰劲,一個胖子當(dāng)著我的面吹牛梁沧,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播蝇裤,決...
    沈念sama閱讀 40,292評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼廷支,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了栓辜?” 一聲冷哼從身側(cè)響起恋拍,我...
    開封第一講書人閱讀 39,211評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎藕甩,沒想到半個月后芝囤,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,655評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,846評論 3 336
  • 正文 我和宋清朗相戀三年悯姊,在試婚紗的時候發(fā)現(xiàn)自己被綠了羡藐。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,965評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡悯许,死狀恐怖仆嗦,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情先壕,我是刑警寧澤瘩扼,帶...
    沈念sama閱讀 35,684評論 5 347
  • 正文 年R本政府宣布,位于F島的核電站垃僚,受9級特大地震影響集绰,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜谆棺,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,295評論 3 329
  • 文/蒙蒙 一栽燕、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧改淑,春花似錦碍岔、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,894評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至仰猖,卻和暖如春捏肢,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背饥侵。 一陣腳步聲響...
    開封第一講書人閱讀 33,012評論 1 269
  • 我被黑心中介騙來泰國打工猛计, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人爆捞。 一個月前我還...
    沈念sama閱讀 48,126評論 3 370
  • 正文 我出身青樓奉瘤,卻偏偏與公主長得像,于是被迫代替她去往敵國和親煮甥。 傳聞我的和親對象是個殘疾皇子盗温,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,914評論 2 355

推薦閱讀更多精彩內(nèi)容