关于 Android 7.0 适配中 FileProvider 部分的总结

匿名 (未验证) 提交于 2019-12-03 00:27:02

file://

Android 7.0 权限变更

file://

备注:如果你对应用私有目录不太清楚的话,可以阅读我的这篇文章:了解 Android 应用的文件存储目录,掌握持久化数据的正确姿势

StrictModefile://file://

file://FileUriExposedException

FileProvider

file://content://

第一步,注册一个 FileProvider

作为系统四大组件之一的 ContentProvider,其子类FileProvider,也同样需要使用 元素在 Manifest 文件中添加注册信息,并按照要求设置相关属性值。

.........

1

2

3

4

5

6

7

8

9

10

11

applicationId

第二步,添加共享目录

在 res/xml 目录下新建一个 xml 文件,用于存放应用需要共享的目录文件。这个 xml 文件的内容类似这样:

...

1

2

3

4

5

元素必须包含一到多个子元素。这些子元素用于指定共享文件的目录路径,必须是这些元素之一:

:外部存储空间应用私有目录下的 cache/ 目录,等同于 Context.getExternalCacheDir();

namepath

其中,path 属性用于指定当前子元素所代表目录下需要共享的子目录名称。注意:path 属性值不能使用具体的独立文件名,只能是目录名。

content://

如果我们需要分享的文件位于同级别目录下不同的子目录中,就需要添加多个子元素逐一指定要分享的文件目录,或者共享他们通用的父目录也行。

1

2

3

4

5

6

7

8

9

第三步,生成 Content URI

1

2

需要传递三个参数。第二个参数便是 Manifest 文件中注册 FileProvider 时设置的 authorities 属性值,第三个参数为要共享的文件,并且这个文件一定位于第二步我们在 path 文件中添加的子目录里面。

举个例子:

1

2

3

4

5

6

7

生成的 Content URI 是这样的:

content://com.yifeng.samples.myprovider/my_images/1493715330339.jpg

1

第四步,授予 Content URI 访问权限

生成 Content URI 对象后,需要对其授权访问权限。授权方式有两种:

FLAG_GRANT_READ_URI_PERMISSION

FLAG_GRANT_WRITE_URI_PERMISSION

第五步,提供 Content URI 给其它应用

常见使用场景

开发者官方 FileProvider 部分

自动安装文件

版本更新完成时打开新版本 apk 文件实现自动安装的功能,应该是最常见的使用场景,也是每个应用必备功能之一。常见操作为,通知栏显示下载新版本完毕,用户点击或者监听下载过程自动打开新版本 apk 文件。适配 Android 7.0 版本之前,我们代码可能是这样:

File apkFile =newFile(getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS),"app_sample.apk");Intent installIntent =newIntent(Intent.ACTION_VIEW);installIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);installIntent.setDataAndType(Uri.fromFile(apkFile),"application/vnd.android.package-archive");startActivity(installIntent);

1

2

3

4

5

6

现在为了适配 7.0 及以上版本的系统,必须使用 Content URI 代替 File URI。

在 res/xml 目录下新建一个 file_provider_paths.xml 文件(文件名自由定义),并添加子目录路径信息:

1

2

3

4

5

6

然后在 Manifest 文件中注册 FileProvider 对象,并链接上面的 path 路径文件:

1

2

3

4

5

6

7

8

9

10

11

修改 java 代码,根据 File 对象生成 Content URI 对象,并授权访问:

1

2

3

4

5

6

7

8

9

如此这般,便完成了应用中调用系统功能打开 apk 文件的 7.0 适配工作。

调用系统拍照

调用系统拍照功能时也需要传递一个 Uri 对象,用于保存图片至指定目录,这里也需要适配 7.0 版本。其他步骤不再赘述,核心 java 代码如下(路径不同,注意添加 res/xml 中的 path 文件子目录):

1

2

3

4

5

6

7

8

9

10

11

调用系统裁剪

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

拿到正确的 Content URI 后,作为 inputUri,传递给 Intent 对象:

Intent intent =newIntent("com.android.camera.action.CROP");intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION);intent.setDataAndType(inputUri,"image/*");intent.putExtra("crop","true");intent.putExtra("aspectX",1);intent.putExtra("aspectY",1);intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(outputFile));startActivityForResult(intent, REQUEST_PICK);

1

2

3

4

5

6

7

8

注意:uCropcropper

历史版本问题

说了这么多,还有一个大家比较关心的问题就是:哪些已经上线的旧版本应用没有做 7.0 适配工作怎么办?关于这个问题,Google 已经提前帮我们想好解决方案啦。

还记得 6.0 运行时权限问题吗?如果你不想处理运行时权限事宜的话,只需要在 build.gradle 文件中将 targetSdkVersion 的值设为 23 以下即可。

同样的,只要 targetSdkVersion 值小于 24,File URI 的使用依旧可以出现在 7.0 及以上版本的设备中。不过需要注意的是,如前面所述,调用系统裁剪功能比较特殊,可能会出现一些问题。

虽然 Google 在每次发布新版 Android 系统时,都提供这种设置 targetSdkVersion 的方式兼容旧版本,但只是一种临时解决方案,并不推荐大家使用这种技巧绕开新版本的适配问题。要知道,新出现的 API 改变一定是在解决过去存在的系统问题,是一种进步的表现。遵循规范,是我们每个开发人员开发时都应铭记于心的格言。

摘自:https://blog.csdn.net/growing_tree/article/details/71190741

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!