android7.0之后版本,FileProvider适配问题

发布于:2021-11-27 22:05:17

前言:这是我的第一篇博客,之前一直有写博客的想法,不知道从何下手而一直往后拖,*来因为一些原因越来越意识到自己的知识的不足,终于下定决心弥补,希望通过坚持写博客能给自己一些提高。本文是前两个月遇到的情况,更新APP的时候在一些系统7.0以上的手机会崩溃,所以花了一上午的时间研究,在此再做记录。

概述
android7.0中有一些新的变化,(官方文档),例如多窗口的支持,FileProvider等等,今天我们只对FileProvider做讲解,这也是我们在开发过程中必须要做的适配。



在7.0以上系统的手机上,Android框架执行的StrictMode API政策禁止在应用外部公开file//URI;传递file://URI会报出FileUriExposedException异常。如果要在应用间共享文件,应发送一项content//URI,最简单的方式就是使用FileProvider类。



使用方法
1,在ManiFest中的的节点中注册一个FileProvider,因为FileProvider是ContentProvider的子类;


name:配置当前FileProvider的实现类,一般为固定的。也可以写继承FileProvider的实现类authorities:配置一个FileProviderde 名字,必须是当前系统内的唯一值,一般为【包名+字符串】(例:com.example.demo.customName,如上图格式会自动引用gradle中的applicationId)exported:表示该FileProvider是否需要公开,一般不需要,本人测试:必须false否则抛异常grantUriPermissions:是否允许授权的文件临时访问权限,本人测试:必须true否则抛异常

2,配置可分享的文件的路径


name:是固定的,
resource:需要在res目录下新建xml文件夹,这里指向xml文件夹下的provider_paths文件,此文件的根节点为paths;
paths 标签内,必须配置最少一个 xxx-path 标签


//path=""---------表示为当前指定目录 如下:

//root-path:表示根目录,『/』。
//files-path:表示 content.getFileDir() 获取到的目录。
//files-path:表示 content.getFileDir() 获取到的目录。
//files-path:表示 content.getFileDir() 获取到的目录。
//files-path:表示 content.getFileDir() 获取到的目录。
//external-cache-path:表示 ContextCompat.getExternalCacheDirs() 获取到的目录


3,使用content:// 调用FileProvider.getUriForFile()


/** @param context 上下文对象
* @param authority 这里是前面在 AndroidManifest.xml 中 配置的 android:authorities 。
* @param file 要获取URI的file对象
*/

Fileprovider.getUriForFile(Context context,String authority,File file)
// 调用此方法,会自动得到一个 file:// 转换成 content:// 的 一个 Uri 对象,可以供我们直接使用。
生成的 Content URI 是这样的

content://com.example.demo.customName/*****

host 部分为 元素的 authorities 属性值(applicationId + customname),
path 片段为 res/xml 文件中指定的子目录别名


4,授予临时读写的权限


在配置 provider 标签的时候,有一个属性 android:grantUriPermissions=”true” ,它表示允许它授予 Uri 临时的权限。
当我们生成出一个 content:// 的 Uri 对象之后,其实也无法对其直接使用,还需要对这个 Uri 接收的 App 赋予对应的权限才可以。
授权类型的常量,被定义在 Intent 类中。


授权的方式分为两种:


使用Context.grantUriPermission() 为其他 App 授予 Uri 对象的访问权限。

/****
*
* @param toPackage 表示授予权限的 App 的包名。
* @param uri 授予权限的 content:// 的 Uri。
* @param modeFlags 读写权限。
*/
@Override
public void grantUriPermission(String toPackage, Uri uri, int modeFlags) {
super.grantUriPermission(toPackage, uri, modeFlags);
}
//这种情况下,授权的有效期限,从授权一刻开始,截止于设备*艋蛘呤侄饔 Context.revokeUriPermission() 方法,才会收回对此 Uri 的授权。

示例代码:(此处借鉴鸿洋大神的图片 博客?->)


配合 Intent.addFlags() 授权。 setFlags() == addflags()

intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
示例代码:


Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setAction("android.intent.action.VIEW");
intent.addCategory("android.intent.category.DEFAULT");
Uri data;
// 判*姹敬笥诘扔7.0
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
data = FileProvider.getUriForFile(context,"com.example.demo.fileprovider", file);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION |
Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
} else {
data = Uri.fromFile(file);
}

一旦授权,直到该 App 被完全退出,这段时间内,该 App 享有对此 Uri 指向的文件的对应权限,我们无法再主动收回此权限


常见使用场景


1,自动安装文件
2,调用系统相机拍照
3,调用系统裁剪


总结:终于完成了第一篇技术博客,发现真心不容易,在这里向各位坚持写博客的大佬致敬,本人也会坚持写下去,努力提升自己的水*,不拖android开发工程师的后腿。


由于本人水*有限,代码可能会出现超出本人认知范围的Bug,欢迎各位大佬批评指正。

相关推荐

最新更新

猜你喜欢