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