Android 7.0拍照/相册/截取图片FileProvider使用
来源:互联网 发布:冬未了 知乎 编辑:程序博客网 时间:2024/06/06 01:05
Android 7.0拍照/相册/截取图片FileProvider使用
- Android 70拍照相册截取图片FileProvider使用
- GitHub地址
- HIT THE PIT
- 需求
- 实现解析
- 一 创建需要保存原图和裁剪图的File
- 从原图File获取原图的Uri
- 1 注册Privider
- 2 使用FileProvider
- 从原图File获取原图的Uri
- 二 调用相机拍照并保存在SD中
- 三 打开系统相册
- 四 裁剪图像
- 一 创建需要保存原图和裁剪图的File
- 总结
- 后话
- 参考资料
GitHub地址
https://github.com/DanialFu/CameraDemo
HIT THE PIT
- 坑1:4.4+ 系统打开相册的不同Action
- 坑2 :6.0+ 动态权限适配
- 坑3:7.0+ FileProvider对设备内容Uri的处理
- 坑4:小米手机的FileProvider共享目录配置(也可以说根目录下的资源文件目录配置)
需求
实现解析
一. 创建需要保存原图和裁剪图的File
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
注意:Demo中将所有保存的图像均存放在app内部存储的路径中,当app卸载后存储的资源文件也会相应的删除。所以是存储路径的选择时根据项目需求来改变的。imgPathOri & imgPathCrop Demo中仅用于打印Log日志使用
1. 从原图File获取原图的Uri
- 1
- 2
- 3
- 4
- 5
- 1
- 2
- 3
- 4
- 5
为了提高应用私有目录的安全性,在7.0之后Google强制执行了“StrictMode API 政策”,用于限制访问私有文件目录的权限。如果在7.0之后调用包含file://Uri 类型的Intent离开了应用界面,会抛出onFileUriExposed的异常。所以我们用FileProvide来”格式化”Uri,用grantUriPermissions来授权Intent所持有的权限
1.1 注册Privider
FileProvider继承于ContentProvider,所以我们需要在manifest中注册Provider
manifest.xml
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- authorities:标识provider 一般由 [packageName/applicationId + 自定义名称] 命名
- exported:要求必须为false,具体信息不在本文讨论
- grantUriPermissions:是否授予Uri临时访问权限
- meta-data:定义FileProvider所授权的资源路径
res\ xml\ file_paths.xml
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 1
- 2
- 3
- 4
- 5
- 6
- 7
通过paths.xml来定义FileProvider需要转换为Content Uri的文件路径。第一第二个为Demo测试使用
标签是官方文档上没有说明的,在这里需要说明下为什么会用到root-path,顾名思义他就是代表设备根目录的。在打开相册的需求时,有的手机厂商会在系统根目录放入一些图像来供用户体验,所有当你选择了这些就会出现onFileUriExposed的异常,所以建议加上root-path标签
不同的标签对应不同的存储区域,path和name标签规定了file 转换成content 的匹配规则。如果想深入了解规则参考[filecontent转换规则][file-content转换规则]
// Context.getFilesDir().
// getCacheDir().
// Environment.getExternalStorageDirectory().
// Context.getExternalFilesDir().
// Context.getExternalCacheDir().
1.2 使用FileProvider
FileProvider.getUriForFile(this, getPackageName() + “.provider”, oriPhotoFile);
intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
第一个是根据File获取FileProvider管理的Uri,第二个是对Intent授予读写私有目录的权限。
注意:如果manifest.xml没有定义Android:grantUriPermissions=”true”或者定义为”false”,都需要在代码中动态定义
- 1
- 2
- 3
- 4
- 5
- 1
- 2
- 3
- 4
- 5
二. 调用相机拍照并保存在SD中
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
三. 打开系统相册
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
打开系统相册的Action有三种:ACTION_PICK,ACTION_GET_CONTENT,ACTION_OPEN_DOCUMENT。
setType(“image/*”)情况下:
ACTION_PICK :直接打开图库,优点是不会出现类型混乱的情况,缺点仅能打开图库而不能从其他路径中获取资源且界面较单一。
ACTION_GET_CONTENT:4.4以下的版本打开的是缩略图的图库,4.4以上是可选择的页面(图库/图像选择器)。
ACTION_OPEN_DOCUMENT:直接打开图像选择器,不可以在4.4以下使用。(官方建议4.4+使用此Action)。
从图库选择图像返回的Uri:
- <7.0 :content://media/external/images/media/…
- >7.0 :content://com.android.providers.media.documents/document/image…
从图像选择器选择图像返回的Uri:
<4.4 :不可打开图像选择器
4.4 - 7.0 :content://media/external/images/media/…
- >7.0 :content://com.android.providers.media.documents/document/image…
四. 裁剪图像
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
裁剪图像同样是调用系统程序,所以,对于7.0以上和以下的版本一样要分别处理。
- <7.0 Uri的类型不受限制,可传入Scheme为file和content类型的Uri
- >7.0 Uri的类型就要通过FileProvider和grantUriPermission处理后才可以传入,所以只可传入Scheme为content类型的Uri
总结
由于Google官方对于安全的强制要求,我们必须对于7.0以上的版本进行私有目录文件安全控制。而安全策略的主角就是FileProvider
FileProvider 定义了一套加密策略,而策略规则就是demo中的file-path.xml,加密的详细过程可以参考[file-content转换规则][file-content转换规则]。
grantUriPermissions 则是向其他应用授予私有目录的读取权限,换句话说就是告诉某一应用我的Uri的加密规则。接着Intent跳转的应用就可以根据FileProvider的加密规则解析出私有目录的真实位置来进行操作。
拍照/图像选择器/裁剪都是属于系统应用,所以我们需要对7.0以上的系统应用公开app私有目录的安全策略,否则系统会抛出FileUriExposedException的异常。
在本例中,相机拍照所保存图像的Uri是有app自己定义的加密策略,所以调用系统裁剪应用可以直接传入imgUriOri。而7.0以后采用图像选择器应用返回的图像Uri的来源不可控制,导致图像的安全策略我们app并不知道,所以我们需要从未知安全策略的Uri中解析出图像真正的路径,接而转换为由app自己定义安全策略的Uri,这样系统裁剪应用才可以解析出图像。
后话
本篇因为时间和精力,对于系统存储目录并没有太多的解释,空出时间会详细分析目录以及相关知识点
这个博客前后翻了不下于60篇博文,包括官网和Stack Overflow,在这里感谢各位的开源奉献的精神。由于“抄袭”博文太多就不一一感谢了,本博文纯手打,0复制粘贴,请转载的大大们注明文章来源,尊重开源精神。
另外,最重要的一点,如果各位大大发现博文用词不当或出现bug请在第一时间联系我更改,避免错误传播。Google邮箱:unableApe@gmail.com
本例测试机型:中兴(4.0)、HTC802w(4.4.2)、红米Note(6.0)、华为荣耀8(7.0)
参考资料
Android M、N适配踩坑
file-content转换规则
系统调用相册不同的Action区别
原文地址;http://blog.csdn.net/fuhao476200/article/details/71487432
- Android 7.0拍照/相册/截取图片FileProvider使用
- Android 7.0拍照/相册/截取图片FileProvider使用
- Android中拍照截取和相册获取图片截取
- 调用相册 拍照 截取图片
- android 拍照使用fileprovider遇到的坑
- Android使用WebView从相册/拍照中添加图片
- Android使用WebView从相册/拍照中添加图片
- Android使用WebView从相册/拍照中添加图片
- FileProvider的拍照和打开相册功能
- Android调用相机应用拍照及FileProvider使用
- android 使用相机拍照以及FileProvider源码浅析
- Android 7.0 FileProvider的使用
- Android 7.0 FileProvider的使用
- Android 7.0 FileProvider的使用
- Android 从相册和拍照选择图片
- android 选择图片 相册选择 马上拍照
- android 手机拍照。。相册 取图片
- Android 拍照/相册 获取图片裁剪显示
- activity跳转回退
- [ 学习 ] 8种方式帮助你如何从一名普通的程序员进阶成为一名伟大的程序员
- MVC5+LocalDb发布到IIS
- centos彻底删除文件夹、文件命令(centos 新建、删除、移动、复制等命令)
- 当个好的测试经理不容易,懂得这些很重要
- Android 7.0拍照/相册/截取图片FileProvider使用
- 题目:输入两个正整数m和n,求其最大公约数和最小公倍数。
- 301、404、200、304、500HTTP状态
- php 基于socket的基本通信
- 在Linux中编译jrtplib
- 给Ubuntu 16.04更换更新源
- 设计模式12-策略模式
- java读取properties文件
- MyBatis框架介绍