Android7.0以后对系统文件访问权限校验更加严格。
以前使用的file://模式会抛出错误 FileUriExposedException错误,7.0以后需要配置fileprovider来进行文件访问。
当前项目中的使用场景:
1.相机拍照
2.调用系统安装APK
使用
1.因为Android主工程跟依赖工程都使用provider的时候可能会产生冲突,一般需要自定义一个provider继承系统FileProvider,在AndroidMainest.xml中属性的name使用自定义的provider
2.主工程与依赖库的xml/file_paths.xml文件路径不能相同,里面的属性name也不能相同否则会覆盖掉依赖工程的路径。
public class MyFileProvider extends FileProvider {
}
在res文件下添加file_paths配置文件
<?xml version="1.0" encoding="utf-8"?>
<resources>
<paths>
<!--对应DEVICE_ROOT,也就是File DEVICE_ROOT = new File("/"),即根目录,一般不需要配置。-->
<root-path name="root" path="" />
<!--代表文件位于手机内部存储空间,访问效果如同 getFilesDir();-->
<files-path name="apk_download" path="test/apk" />
<!--代表文件位于手机内部缓存空间,访问效果如同 getCacheDir()-->
<cache-path name="cache" path="" />
<!--external-path 代表文件位于手机外部存储空间,访问效果如同 Environment.getExternalStorageDirectory() Android11不能访问 -->
<!--getExternalFilesDir(null); 得到的路径/storage/emulated/0/Android/data/yourPackageName/files-->
<external-path name="download" path="test/apk" />
<!--代表与Context#getExternalFilesDir(String) 和Context.getExternalFilesDir(null)相同的文件路径-->
<external-files-path name="name" path="path" />
<!--代表与Context.getExternalCacheDir()相同的文件路径-->
<external-cache-path name="name" path="path" />
</paths>
</resources>
在AndroidMainfest.xml中进行配置
<provider
android:name="com.test.test.MyFileProvider"
android:authorities="包名.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" />
</provider>
authorities:标识,在当前系统内的唯一值,一般使用包名。
exported:表示该FileProvider是否需要公开出去
grantUriPerMisssions = true :允许授权文件的临时访问权限。
使用
String sdpath = getExternalFilesDir(null)+File.separator+"test/apk";
test/apk是自己在file_paths中配置的路径
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
Uri contentUri = FileProvider.getUriForFile(context, context.getPackageName()+".fileprovider", apkfile);
安装APK的时候需要临时授权。
遇见的问题:
1.在小米Android 11上面Environment.getExternalStorageDirectory()获取的路径报FileNotFoundException。
解决办法:
用getExternalFilesDir(null)代替