Android N 通過Intent安裝APK

封面圖還是要有的

之前使用Intent 安裝APK文件,使用下面的代碼可以直接調起安裝界面。

public void installAPK(Context context, File apkFile){
    Intent intent = new Intent(Intent.ACTION_VIEW);
    intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    intent.setDataAndType(Uri.fromFile(apkFile),"application/vnd.android.package-archive");
    context.startActivity(intent);
}

最近把targetSdkVersion升級到了26才發現app在Android 8.0的手機上無法正常安裝,一查才知道從Android N(也就是Android API 24)開始直接執行上面的代碼會報android.os.FileUriExposedException異常,需要使用FileProvider來處理對Content URI讀取的臨時授權問題。直接上解決方案

首先,需要在AndroidManifest.xml文件中的<application>標籤中定義FileProvider

<application>
    ...
    <provider
        android:name="android.support.v4.content.FileProvider"
        android:exported="false"
        android:grantUriPermissions="true"
        android:authorities="com.mrtrying.installappdemo.fileprovider">
        ...
    </provider>
    ...
</application>

注意:這裏<provider>標籤中的android:authorities爲設置授權的URI,一般都是授權自己app包名下的fileprovider,也就是應用包名.fileprovider;而android:exported屬性爲false則表示該FileProvider不是需要是公共的。另外,android:grantUriPermissions屬性爲true表示允許給文件臨時訪問權限。

然後,在res/xml目錄下定義一個apk_path.xml文件,內容如下:

<?xml version="1.0" encoding="utf-8"?>
<paths>
    <external-path
        name="apk_path"
        path="."/>
</paths>

<paths>中必須有子元素,這裏使用<external-path>標籤對應的是使用Environment.getExternalStorageDirectory()路徑,name屬性則是名稱,path則是表示臨時授權的子目錄路徑(不是單個文件),使用.表示所有路徑,這個可以根據需求添加。

將定義好的apk_path.xml文件通過<meta-data>添加到之前在AndroidManifest.xml文件中定義的<provider>中,將<meta-data>標籤的android:resource屬性設置爲@xml/apk_path

<provider
    android:name="android.support.v4.content.FileProvider"
    android:exported="false"
    android:grantUriPermissions="true"
    android:authorities="com.mrtrying.installappdemo.fileprovider">
    <meta-data
        android:name="android.support.FILE_PROVIDER_PATHS"
        android:resource="@xml/apk_path"/>
</provider>

最後,只需要在代碼中使用FileProvider來獲取URI就大功告成了

public void installAPK(Context context, File apkFile){
    Intent intent = new Intent(Intent.ACTION_VIEW);
    Uri uri;
    if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.N){
        intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
        //第二個參數需要與<provider>標籤中的android:authorities屬性相同
        uri = FileProvider.getUriForFile(this,"com.mrtrying.installappdemo.fileProvider",apkFile);
    }else{
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        uri = Uri.fromFile(apkFile);
    }
    intent.setDataAndType(Uri.fromFile(apkFile),"application/vnd.android.package-archive");
    context.startActivity(intent);
}

FileProvider的使用可以參考官方文檔

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章