在开发Android项目的时候,我们会用到相机,有些时候只是开发一个普通的扫码,仅仅赋予一下 权限 就好了,但是有些时候是需要拍照和从相册中获取照片的。

我们在Android 5.0以及5.0之前调用相机可以这样写

Intent intent = new Intent();
intent.setAction(MediaStore.ACTION_IMAGE_CAPTURE);
File savePhoto = new File(Environment.getExternalStorageDirectory().getAbsolutePath(),"/test/"+System.currentTimeMillis() + ".png");
intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(savePhoto));
startActivityForResult(intent,200);

这样写在6.0之前是完全没有问题的,拍照也可以按照指定的路径进行存储,一切的一切都是OK的,除非部分机型会有问题

到了6.0,在调用相机就得这样写
当我们开发者把sdk升级到了23后,这样写就会存在一点缺陷。那就是权限管理,需要动态进行获取了。OK,然后我们改成动态获取的,如下:

if(checkSelfPermission(Manifest.permission.CAMERA,Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED){
requestPermissions(new String[]{Manifest.permission.CAMERA,Manifest.permission.WRITE_EXTERNAL_STORAGE},200);
return;
}
Intent intent = new Intent();
intent.setAction(MediaStore.ACTION_IMAGE_CAPTURE);
File savePhoto = new File(Environment.getExternalStorageDirectory().getAbsolutePath(),"/test/"+System.currentTimeMillis() + ".png");
intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(savePhoto));
startActivityForResult(intent,200);

这样写和5.0几乎没有区别,只是在前边加了一个权限校验。因为6.0到了动态权限时代

然而到了7.0,一切的一切都不一样了,因为Android 7.0不允许intent带有file://的URI离开自身的应用了,要不然会抛出FileUriExposedException

想要在自己应用和其他应用之间共享File数据,只能使用content://的方式
所以我们在想按照5.0和6.0的方式去调用相机是不可行的了,我们需要在7.0的时候。把所有应用与应用之间的文件传递改成content://的方式,并且还需要把该URI赋予临时的访问权限,使用如下:

1.现在清单文件里配置一个provider

<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="应用包名"
android:exported="false"
android:grantUriPermissions="true">
</provider>

2.在xml目录下创建file_paths文件

<paths xmlns:android="http://schemas.android.com/apk/res/android">
<files-path name="my_images" path="images/"/>
</paths>

在file_paths文件夹内声明的都是需要对外共享的目录,比如上面的配置等于 new File(Context.getFilesDir(),"images") 路径

paths内还可以声明很多种类型的标签,每一种标签都代表了一个路径,如下:

<files-path /> = getFilesDir()
<cache-path /> = getCacheDir()
<external-path /> = Environment.getExternalStorageDirectory()
<external-files-path /> = Context#getExternalFilesDir(String) 或 Context.getExternalFilesDir(null)
<external-cache-path /> = Context.getExternalCacheDir()
<external-media-path /> = Context.getExternalMediaDirs()

我们在配置的时候。name的作用就是为了隐藏后边的真实路径,为了安全考虑
而后边的path则是需要共享的路径,用标签所代表的路径加上path上的值,就是完整的路径。

写好path文件后,我们在回到清单文件内继续更新 android.support.v4.content.FileProvider 这个Provider的配置,需要把刚刚的file_paths文件和这个provider关联起来,如下

<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="应用包名"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" />
</provider>

3.写完这些配置信息后,我们就可以在应用内直接获取需要共享文件的content://URI了,如下

File imagePath = new File(Context.getFilesDir(), "images");
File newFile = new File(imagePath, "test.jpg");
Uri contentUri = FileProvider.getUriForFile(getContext(), "应用包名", newFile);

getUriForFile的第二个参数内也可以不是应用包名,只要和清单文件内的authorities一致即可

这个contentUri的最后结果就是 content://应用包名/my_images/test.jpg

之所以会生成这个uri,相信很多同学看到这里就明白了,因为这个uri是要对其他应用共享的,所以不能直接共享真实路径,便衍生了FileProvider这种东西来专门生成这个Uri,他的生成规则便是 content:// 应用包名(或者是其他字符串)/ 伪名 (path文件内配置的name属性) / 文件名

4.然后赋予临时访问权限

我们可以调用 Context.grantUriPermission 方法来给Uri赋予权限,调用 revokeUriPermission() 函数来撤销权限,也可以通过 Intent.setFlags() 的方式来赋予临时访问权限

最终在7.0上调用相机就成了这个样子,前提是file_paths文件已经配置OK

if(checkSelfPermission(Manifest.permission.CAMERA,Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED){
requestPermissions(new String[]{Manifest.permission.CAMERA,Manifest.permission.WRITE_EXTERNAL_STORAGE},200);
return;
}
Intent intent = new Intent();
intent.setAction(MediaStore.ACTION_IMAGE_CAPTURE);
File imagePath = new File(Context.getFilesDir(), "images");
File newFile = new File(imagePath, "test.jpg");
Uri contentUri = FileProvider.getUriForFile(getContext(), "应用包名", newFile);
intent.putExtra(MediaStore.EXTRA_OUTPUT, contentUri);
intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
startActivityForResult(intent,200);

到这里就结束了,我也是刚刚踩完相机的坑,所以来一篇博客来记录这个经历,由于该内容全部都是用记事本手敲的,所以或多或少可能会有一些拼写错误之类的,欢迎在评论区指出错误,谢谢!

关于Android 7.0(API24)相机的问题汇总的更多相关文章

  1. Android 7.0 之后相机/文件读写等权限获取方式改变,导致开启相机闪退

    在 Android 7.0 之前 Google 提供的动态申请权限的 API,可以调用相机拍照,访问SDcard等操作都只需要申请对应的权限,如下: <uses-permission andro ...

  2. android 7.0+ FileProvider 访问隐私文件 相册、相机、安装应用的适配

    从 Android 7.0 开始,Android SDK 中的 StrictMode 策略禁止开发人员在应用外部公开 file:// URI.具体表现为,当我们在应用中使用包含 file:// URI ...

  3. Android 7.0+相机、相册、裁剪适配问题

    Android 7.0+相机.相册.裁剪适配问题 在manifest中: <provider android:name="android.support.v4.content.File ...

  4. 关于Android 7.0更新后调用系统相机及电筒问题

    android升级到7.0后对权限又做了一个更新即不允许出现以file://的形式调用隐式APP,需要用共享文件的形式:content:// URI 因为系统相机是提供的共享 Provider , C ...

  5. Android 6.0 运行时权限处理完全解析

    一.概述 随着Android 6.0发布以及普及,我们开发者所要应对的主要就是新版本SDK带来的一些变化,首先关注的就是权限机制的变化.对于6.0的几个主要的变化,查看查看官网的这篇文章http:// ...

  6. 【译】Android 6.0 Changes (机翻加轻微人工校对)

    Android 6.0 Changes In this document Runtime Permissions Doze and App Standby Apache HTTP Client Rem ...

  7. Android 6.0 运行时权限处理

    在运行时请求权限 从Android 6.0(API级别23)开始,用户权限授予应用程序在应用程序运行时,当他们安装程序.这种方法简化了应用程序的安装过程,因为用户不需要安装或更新应用程序时授予权限.这 ...

  8. Google Android 6.0 权限完全解析

    注:本文只针对Google原生Android系统有效, 小米魅族等手机有自己的权限机制, 可能不适用 一.运行时权限的变化及特点 新的权限机制更好的保护了用户的隐私,Google将权限分为两类,一类是 ...

  9. Android 6.0的运行时权限

    原文  http://droidyue.com/blog/2016/01/17/understanding-marshmallow-runtime-permission/ 主题 安卓开发   Andr ...

随机推荐

  1. C++标准库bitset类型(简单使用方法)

    转自此人博客 ```cpp #include<bister> using std::bitset; ``` 一句话定义:可自定义位数,用作记录二进制的数据类型. 一,定义和初始化 ```c ...

  2. NOIP提高组 2013货车运输

    觉得题目水的离开 不屑的大佬请离开 不会图论的请离开 ……. 感谢您贡献的访问量 ————————————华丽的分割线———————————— 题面: 题目描述 A 国有 n 座城市,编号从 1 到 ...

  3. 46个Linux面试常见问题送给你

    问题一: 绝对路径用什么符号表示?当前目录.上层目录用什么表示?主目录用什么表示? 切换目录用什么命令? 答案:绝对路径: 如/etc/init.d当前目录和上层目录: ./  ../主目录: ~/切 ...

  4. 精解Mat类(一):基本数据类型-固定大小的 矩阵类(Matx) 向量类(Vector)

    一.基础数据类型 1.(基础)固定大小矩阵类 matx 说明: ①    基础矩阵是我个人增加的描述,相对于Mat矩阵类(存储图像信息的大矩阵)而言. ②    固定大小矩阵类必须在编译期间就知晓其维 ...

  5. MSIL实用指南-创建字段

    本篇讲解怎么创建字段,主要是在修饰符的创建上. 创建字段的方法是TypeBuilder.DefineField,传入字段名称.字段类型.字段修饰符等参数,返回一个FieldBuilder对象.先看这一 ...

  6. jQuery 3.0最终版发布,十大新特性眼前一亮

    jQuery 3.0在日前发布了最终的全新版本.从2014年10月,jQuery团队对这个主要大版本进行维护开始,web开发者社区便一直在期待着这一刻的到来,终于在2016年6月他们迎来了这一个最终板 ...

  7. 笔记:Maven 项目报告插件

    Maven 项目报告插件,都是对于前面生成的项目站点的内容丰富,因此都是基于项目站点的,生成的命令和生成项目站点一致(mvn site),项目报告插件的配置和一般插件不同,是在 project-> ...

  8. 研华ADAM 6000系列型号枚举值

    public enum Adam6000Type    {        Non = 0,        Adam6015 = 6015,        Adam6017 = 6017,        ...

  9. 关于html表单的disabled属性的设置问题

    首先,我的看法是无论disable的值是否有值,只要设置了disabled属性的表单,无论是否有值,无论值为什么,都会被禁用.   来看下面例子: 在一个群里有人说因为直接写在表单属性上是字符串,因为 ...

  10. 机器学习(1) - TensorflowSharp 简单使用与KNN识别MNIST流程

    机器学习是时下非常流行的话题,而Tensorflow是机器学习中最有名的工具包.TensorflowSharp是Tensorflow的C#语言表述.本文会对TensorflowSharp的使用进行一个 ...