FileProvider使用注意:
<manifest>
<application>
<provider
android:name="android.support.v4.content.FileProvider" //引用的FileProvider剿吻,if復寫注意路徑
android:authorities="applicationId .fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths"/>
</provider>
</application>
</manifest>
1.在java代碼中傳getUriForFile(Context context, String authority, File file)方法時渣蜗,authority與清單文件的authorities名字一致
2.exported="false",grantUriPermissions="true"
3.file_paths 文件:
<resources>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path name="external" path="" />
這里可以創(chuàng)建很多個paths,但是每個paths的name不能一樣
</resources>
適配:
安卓 8.0及以上: 需要聲明權(quán)限
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGE" />
安卓7.0以下: if (Build.VERSION.SDK_INT< Build.VERSION_CODES.N)
Uri.fromFile(File);
安卓7.0以上: if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
FileProvider.getUriForFile(context, applicationId + ".provider",File); //注意清單文件的authorities一樣
path 說明:
<files-path name="*name*" path="*path*" /> 對應的是:Context.getFileDir()的路徑地址
對應路徑:Context.getFileDir()+"/${path}/"
得到路徑:content://${applicationId}/&{name}/
<cache-path name="*name*" path="*path*" />
對應路徑:Context.getCacheFir()+"/${path}/"
得到路徑:content://${applicationId}/&{name}/
<external-path name="*name*" path="*path*" />
對應路徑:Environment.getExternalStorageDirectory()+"/${path}/"
得到路徑:content://${applicationId}/&{name}/
<external-files-path name="*name*" path="*path*" />
對應路徑:Context.getExternalStorageDirectory()+"/${path}/"
得到路徑:content://${applicationId}/&{name}/
<external-cache-path name="*name*" path="*path*" />
對應路徑: Context.getExternalCacheDir()+"/${path}/"
得到路徑:content://${applicationId}/&{name}/
eg:
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
分析:
ava.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
安裝Apk的service處于休眠或者不可用的狀態(tài)会涎,導致intent.addflags方式賦予的臨時權(quá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);
//添加對目標應用臨時授權(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)目標應用類型的應用舒帮,注意此方法必須放置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, uri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION);
}
context.startActivity(intent);
} catch (Exception e) {
e.printStackTrace();
}
}