Android FileProvider之應(yīng)用安裝

應(yīng)用安裝(FileProvider)

應(yīng)用內(nèi)安裝apk時(shí)涉及到通過(guò)Intent在兩個(gè)應(yīng)用間共享資源,Android 從 N 開(kāi)始不允許以 file:// 的方式通過(guò) Intent 在兩個(gè) App 之間分享文件,取而代之的是通過(guò) FileProvider 生成 content://Uri,否則直接使用會(huì)拋出異常導(dǎo)致奔潰所以首先我們來(lái)了解一下FileProvider相關(guān)的知識(shí)。

首先給出FileProvider的官方介紹https://developer.android.google.cn/reference/androidx/core/content/FileProvider

FileProvider 是一個(gè)特殊的 ContentProvider 子類(lèi),通過(guò) content://Uri 代替 file://Uri 實(shí)現(xiàn)不同 App 間的文件安全共享。當(dāng)通過(guò)包含 Content URI 的 Intent 共享文件時(shí),需要申請(qǐng)臨時(shí)的讀寫(xiě)權(quán)限,可以通過(guò) Intent.setFlags() 方法實(shí)現(xiàn)。而 file://Uri 方式需要申請(qǐng)長(zhǎng)期有效的文件讀寫(xiě)權(quán)限,直到這個(gè)權(quán)限被手動(dòng)改變?yōu)橹梗@是極其不安全的做法。因此 Android 從 N 版本開(kāi)始禁止通過(guò) file://Uri 在不同 App 之間共享文件。

FileProvider的使用步驟:

1,定義一個(gè)FileProvider
2,指定可用的文件
3,生成文件的Content URI
4,給此URI授予臨時(shí)權(quán)限
5,將此Content URI通過(guò)Intent傳遞給另一個(gè)App

接下來(lái)詳細(xì)介紹
1,定義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/provider_paths" />
     </provider>
    
     android:authorities:applicationId+fileProvider

     applicationId:這里寫(xiě)成動(dòng)態(tài)獲取應(yīng)用包名,如果寫(xiě)死在項(xiàng)目包含多個(gè)moudle時(shí)出現(xiàn)不一致的情況

     android:exported="false":表示此provider是私有的不對(duì)其他應(yīng)用公開(kāi)

     android:grantUriPermissions="true":表示授予臨時(shí)權(quán)限

     provider_paths:指定用來(lái)配置文件目錄的xml文件,此處指定為provider_paths,名稱可以自定義

2,指定可用的文件provider_paths.xml

        <paths xmlns:android="http://schemas.android.com/apk/res/android">
            <!--相當(dāng)于Context.getFilesDir()-->
            <files-path name="name" path="path" />

            <!--相當(dāng)于Context. getCacheDir()-->
            <cache-path name="name" path="path" />

            <!--相當(dāng)于Environment.getExternalStorageDirectory()-->
            <external-path name="name" path="path" />

            
            <!--相當(dāng)于Context.getExternalFilesDir(String) Context.getExternalFilesDir(null).-->
            <external-files-path name="name" path="path" />
            
            <!--相當(dāng)于Context.getExternalCacheDir()-->
            <external-cache-path name="name" path="path" />

            <!--相當(dāng)于Context.getExternalMediaDirs()-->
            <external-media-path name="name" path="path" />
            ...
        </paths>

注意:這里只需配置自己文件所保存的path即可,name為別名影藏實(shí)際名稱,path為實(shí)際的文件路徑如果對(duì)Android文件存儲(chǔ)這塊知識(shí)不太了解可以看一下另一篇介紹:http://www.itdecent.cn/p/88dbdd8613db

3,生成文件的Content URI

完成了前兩步的配置,接下來(lái)通過(guò)官方提供的getUriForFile(File file) 方法生成能夠被其他應(yīng)用訪問(wèn)的Content URI加入有一個(gè)apk文件路徑為磁盤(pán)根目錄則相應(yīng)文件對(duì)象為

File file = new File("/sdcard/app.apk");

此文件對(duì)應(yīng)的可通過(guò)如下方式獲得uri

       Uri uri=FileProvider.getUriForFile(FaceTempratureActivity.this, BuildConfig.APPLICATION_ID + ".provider", file); 

獲取到Uri后我們將通過(guò)Intent將此Uri傳遞給另一個(gè)應(yīng)用,此處定義一個(gè)Intent

       Intent intent = new Intent(Intent.ACTION_VIEW);
       intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
       intent.setDataAndType(uri,"application/vnd.android.package-archive");

4,給此URI授予臨時(shí)權(quán)限
有了可訪問(wèn)的Uri路徑我們還得申請(qǐng)臨時(shí)讀寫(xiě)文件權(quán)限,這里可以直接通過(guò)Intent.setFlags()方法設(shè)置

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

5,將此Content URI通過(guò)Intent傳遞給另一個(gè)App

statActivity(intent);

最后給出一個(gè)應(yīng)用安裝的示例:

   private void installApp(Content content) {
       File fileS = new File("/sdcard/temp.apk");
       Uri data;
       Intent intent = new Intent(Intent.ACTION_VIEW);
       intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
       if (Build.VERSION.SDK_INT > Build.VERSION_CODES.M) {
           // 給目標(biāo)應(yīng)用一個(gè)臨時(shí)授權(quán)
           intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
           data = FileProvider.getUriForFile(content, BuildConfig.APPLICATION_ID + ".provider", fileS);
       } else {
           data = Uri.fromFile(fileS);
       }
       intent.setDataAndType(data, "application/vnd.android.package-archive");
       startActivity(intent);
   }
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容