Android 6.0 7.0 8.0三個版本Install Apk 採坑記錄

1.爲何會分爲6.0、7.0、8.0 三個版本呢?html

(1)6.0以及以前算是一個版本的問題,7.0版本添加了提升了私有文件的安全性FileProvider是一個坑,8.0版本對於Install Apk又增長了
權限管理又是一個坑

那麼算下來就有兩個坑了,咱們一一看看個人坑是怎麼樣的。
複製代碼

2.android 7.0的坑android

(1)這個坑是一個主要的坑,我相信不少的anroid開發者都應該知道Android 7.0 添加私有文件的安全性,那麼來看下個人代碼:
複製代碼
/**
     * 經過隱式意圖調用系統安裝程序安裝APK
     */
    public static void install(Context context) {
        Intent intent = new Intent(Intent.ACTION_VIEW);
        // 因爲沒有在Activity環境下啓動Activity,設置下面的標籤
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        intent.setDataAndType(Uri.fromFile(
                new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS), "myApp.apk")),
                "application/vnd.android.package-archive");
        context.startActivity(intent);
    }
複製代碼
相信這段代碼是咱們不少6.0及之前的經過Intent隱式安裝APK的方法,固然這個方法在6.0以及前是麼有任何問題的,可是在7.0這裏就會出現
問題了
複製代碼

這就表示咱們用絕對路徑去訪問文件的時候就會出現SecurityException的異常。
大神能夠直接移步官網介紹: https://developer.android.google.cn/training/secure-file-sharing/index.html

## (2)具體採坑的內容:

1、在AndroidManifest.xml裏聲明Provider
複製代碼
<provider
            android:name="android.support.v4.content.FileProvider"
            android:authorities="com.test.pr.fileprovider"
            android:exported="false"
            android:grantUriPermissions="true">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/file_paths"/>
</provider>
複製代碼
name: android V4 包中的類FileProvider
authorities:你的文件的Uri的域名  通常以包名.fileprovider的格式,防止重名
exported: 設置不容許導出,咱們的FileProvider應該是私有的
grantUriPermissions:容許獲取文件的臨時訪問權限
resourse: 設置FileProvider訪問的文件路徑

2、配置FileProvider的文件共享路徑

首先咱們在res文件下面建立一個xml文件夾,而後再xml中建立一個manifest中聲明的文件file_paths.xml。這個名字看你本身定義的,可是必須和AndroidManifest.xml中聲明的一致:
複製代碼
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <paths>
        <external-path
            name="Download"
            path="test"/>
    </paths>
    .
    .
    .
</resources>
複製代碼
這裏能夠建立不少個paths,可是每一個paths的name不能同樣。
name:FileProvider 提供的Uri中一個必要的,這裏的name=Download,那麼得到Uri的鏈接以下所示:
複製代碼
content://com.test.pr.fileprovider/Download
複製代碼
接下來external-path這個標籤是最坑的地方,我來慢慢解釋,我當時出問題就是在這個問題:

     <files-path name="*name*" path="*path*" />   對應的是:Context.getFileDir()的路徑地址
     以上面的配置的path="test"來講
     獲得路徑:Context.getFileDir()+"/test/"


     <cache-path name="*name*" path="*path*" />   對應路徑:Context.getCacheFir()
     以上面的配置的path="test"來講
     獲得路徑:Context.getCache()+"/test/"


     <external-path name="*name*" path="*path*" />   對應路徑:Environment.getExternalStorageDirectory()
     以上面的配置的path="test"來講
     獲得路徑:Environment.getExternalStorageDirectory()+"/test/"


     <external-files-path name="*name*" path="*path*" />   對應路徑:Context.getExternalStorageDirectory()
     以上面的配置的path="test"來講
     獲得路徑:Context.getExternalStorageDirectory()+"/test/"


     <external-cache-path name="*name*" path="*path*" />   對應路徑: Context.getExternalCacheDir()
     以上面的配置的path="test"來講
     獲得路徑:Context.getExternalCacheDir()+"/test/"
複製代碼

PS:我再囉嗦幾句:上面的這個path標籤必定要和你保存的文件的位置要對應起來,若是文件的路徑和你標籤對應的位置有錯的話,就會報這種錯誤:安全

錯誤: failed to find configured root that contains。。。
複製代碼

我再把個人Install APk的代碼以下:bash

public class InstallUtils {
    /**
     * 安裝apk
     *
     * @param downLoadId
     */
    public static void install(long downLoadId, Context mContext) {
        DownloadManager downloader = (DownloadManager) mContext.getSystemService(Context.DOWNLOAD_SERVICE);
        assert downloader != null;
        File file = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS), AppConstants.APP_NAME);
        if (!file.exists()) {
            ToastUtils.showToast(mContext, mContext.getString(R.string.install_fail));
            return;
        }
        Logger.e("" + file.length());
        //安裝
        Intent install = new Intent(Intent.ACTION_VIEW);
        //判斷是不是android 7.0及以上
        if (Build.VERSION.SDK_INT >= AppConstants.ANDROID_VERSION_7) {
            //7.0獲取存儲文件的uri
            Uri uri = FileProvider.getUriForFile(mContext, "com.zhiyunqiao.pr.fileprovider", file);
            install.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            //賦予臨時權限
            install.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
            //設置dataAndType
            install.setDataAndType(uri, "application/vnd.android.package-archive");
        } else {
            if (file.exists()) {
                install.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                install.setDataAndType(Uri.fromFile(file), "application/vnd.android.package-archive");
            } else {
                ToastUtils.showToast(mContext, mContext.getString(R.string.install_fail));
                //清除下載成功
                PreferenceHelp.remove(mContext, "Version", "update");
            }
        }
        mContext.startActivity(install);
    }

}
複製代碼

3.android 8.0 主要是一個權限問題app

Android 8.0更新主要是對Intent隱式安裝APK作了個安全管理:
須要在mainfist中添加一行權限:
<!--8.0安裝apk須要權限-->
複製代碼
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES"/>
複製代碼

而後在代碼中請求下權限便可。ide

相關文章
相關標籤/搜索