27

  • 相机
  • 严格模式解决办法
  • 摄像
  • 官方推荐 - FileProvider
    • 1. 缘由[(转载)](https://blog.csdn.net/wxz1179503422/article/details/84874171)
    • 2. 配置 FileProvider
      • 2.1 AndroidManifest内配置FileProvider
      • 2.2 可访问路径配置
        • 分析路径什么用途?
        • 其他路径
        • 配置的标签参照FileProvider里面的TAG配置
    • 3. 访问 FileProvider
    • 4. 拓展:获取图片方式
      • 4.1 通过绝对路径获取图片
      • 4.2 通过Uri获取资源流
      • 4.3 通过cursor获取图片

相机

以下,调用相机的代码出自开源项目 SelectImgAsWechath 。

添加权限:

    <!--拍照--><uses-permission android:name="android.permission.CAMERA" /><!--写入SD卡的权限:如果你希望保存相机拍照后的照片--><uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /><!--读取SD卡的权限:打开相册选取图片所必须的权限--><uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /><!--网络--><uses-permission android:name="android.permission.INTERNET"/><!-- 在SDCard中创建与删除文件权限 --><uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/><uses-permission android:name="android.permission.RECORD_AUDIO" />

调用:

    public void takePicture(Activity activity, int requestCode) {Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);if (intent.resolveActivity(activity.getPackageManager()) != null) {if (existSDCard()) {takeImageFile = new File(Environment.getExternalStorageDirectory(), "/DCIM/camera/");} else {takeImageFile = Environment.getDataDirectory();}Log.i(TAG, "takeImageFile ===" + takeImageFile);takeImageFile = createFile(takeImageFile, "IMG_", ".jpg");Log.i(TAG, "createFile ===" + takeImageFile);if (takeImageFile != null) {Uri uri = Uri.parse("file://" + takeImageFile.getAbsolutePath());Log.i(TAG, "uri ===" + uri);intent.putExtra(MediaStore.EXTRA_OUTPUT, uri);}}activity.startActivityForResult(intent, requestCode);}

发生异常:
在使用照相机或者摄像机的时候出现异常(targetSdkVersion 27):

    io.reactivex.exceptions.OnErrorNotImplementedException: file:///storage/emulated/0/DCIM/camera/IMG_20200526_110146.jpg exposed beyond app through ClipData.Item.getUri()at io.reactivex.internal.functions.Functions$OnErrorMissingConsumer.accept(Functions.java:704)at io.reactivex.internal.functions.Functions$OnErrorMissingConsumer.accept(Functions.java:701)at io.reactivex.internal.observers.LambdaObserver.onError(LambdaObserver.java:77)at io.reactivex.internal.observers.LambdaObserver.onNext(LambdaObserver.java:67)

经百度:
参考地址:解决exposed beyond app through ClipData.Item.getUri() 错误

7.0后的版本:
不再允许在app之间,使用file://的方式传递File,否则会抛出FileUriExposedException异常

FileUriExposedException:
应用程序将file://Uri 暴露给另一个应用程序时引发的异常。不鼓励这种曝光,因为接收应用可能无法访问共享路径。

严格模式解决办法

项目中的解决办法是
在onCreate的时候,添加如下代码:

        // android 7.0系统解决拍照的问题StrictMode.VmPolicy.Builder builder = new StrictMode.VmPolicy.Builder();StrictMode.setVmPolicy(builder.build());builder.detectFileUriExposure();

StrictMode 严格模式应用:https://www.jianshu.com/p/b80c58677892

Android 2.3提供一个称为严苛模式(StrictMode)的调试特性,Google称该特性已经使数百个Android上的Google应用程序受益。那它都做什么呢?它将报告与线程及虚拟机相关的策略违例。一旦检测到策略违例(policy violation),你将获得警告,其包含了一个栈trace显示你的应用在何处发生违例。你可以强制用警告代替崩溃(crash),也可以仅将警告计入日志,让你的应用继续执行。

虽然官方官方不是这么推荐滴,但是存在即合理?

摄像

通过这段代码,摄像机也可以这么搞:

    private void takenVedio() {// 表示跳转至相机的录视频界面Intent intent = new Intent(MediaStore.ACTION_VIDEO_CAPTURE);// MediaStore.EXTRA_VIDEO_QUALITY 表示录制视频的质量,从 0-1,越大表示质量越好,同时视频也越大intent.putExtra(MediaStore.EXTRA_VIDEO_QUALITY, 0);intent.putExtra(MediaStore.EXTRA_DURATION_LIMIT, 30);// 调用前置摄像头intent.putExtra("android.intent.extras.CAMERA_FACING", 1);intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);if (intent.resolveActivity(getPackageManager()) != null) {File file;if (existSDCard()) {file = new File(Environment.getExternalStorageDirectory(), "/DCIM/audio/");} else {file = Environment.getDataDirectory();}Log.i(TAG, "file ===" + file);file = createFile(file, "VIDEO_", ".mp4");Log.i(TAG, "file ===" + file);if (file != null) {Uri uri = Uri.parse("file://" + file.getAbsolutePath());Log.i(TAG, "uri ===" + uri);intent.putExtra(MediaStore.EXTRA_OUTPUT, uri);}}startActivityForResult(intent, REQUEST_CODE_RECORD_VIDEO);}

官方推荐 - FileProvider

1. 缘由(转载)

Android7.0 (N) 开始,将严格执行 StrictMode 模式,也就是说,将对安全做更严格的校验。而从 Android N 开始,将不允许在 App 间,使用 file:// 的方式,传递一个 File ,否者会抛出 FileUriExposedException的错误,会直接引发 Crash。

但是,既然官方对文件的分享做了一个这么强硬的修改(直接抛出异常),实际上也提供了解决方案,那就是 FileProvider,通过 content://的模式替换掉 file://,同时,需要开发者主动升级 targetSdkVersion 到 24 才会执行此策略。

FileProvider是android support v4包提供的,是ContentProvider的子类,便于将自己app的数据提供给其他app访问。
在app开发过程中需要用到FileProvider的主要有

  1. 相机拍照以及图片裁剪
  2. 调用系统应用安装器安装apk(应用升级)

2. 配置 FileProvider

2.1 AndroidManifest内配置FileProvider

注意:provider是4大组件,需要放置application中哦

        <providerandroid:name="android.support.v4.content.FileProvider"android:authorities="${applicationId}.fileprovider"android:exported="false"android:grantUriPermissions="true"><meta-dataandroid:name="android.support.FILE_PROVIDER_PATHS"android:resource="@xml/install" /></provider>

2.2 可访问路径配置

位置:

install.mxl :

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android"><external-pathname="DCIM"path="DCIM/camerademo" /><!--代表外部存储区域的根目录下的文件 Environment.getExternalStorageDirectory()/目录--><external-pathname="external_storage_root"path="." /><external-pathname="Pictures"path="Pictures/camerademo" /><!--代表app 私有的存储区域 Context.getFilesDir()目录下的images目录 /data/user/0/com.hm.camerademo/files/images--><files-pathname="private_files"path="images" /><!--代表app 私有的存储区域 Context.getCacheDir()目录下的images目录 /data/user/0/com.hm.camerademo/cache/images--><cache-pathname="private_cache"path="images" /><!--代表app 外部存储区域根目录下的文件 Context.getExternalFilesDir(Environment.DIRECTORY_PICTURES)目录下的Pictures目录--><!--/storage/emulated/0/Android/data/com.xx.xxxxxx/files/Pictures--><external-files-pathname="external_files"path="Pictures" /><!--代表app 外部存储区域根目录下的文件 Context.getExternalCacheDir目录下的images目录--><!--/storage/emulated/0/Android/data/com.xx.xxxxxx/cache/images--><external-cache-pathname="external_cache"path="." /></paths>

分析路径什么用途?

当调用Environment.getExternalStorageDirectory()获取,外部存储根目录时,获取的路径是:

/storage/emulated/0

打印2.3中

        photoUri = FileProvider.getUriForFile(this,getPackageName() + ".fileprovider",takeImageFile);

photoUri 的值:

content://com.yoshin.company.blogdemo.fileprovider/external_storage_root/DCIM/camera/IMG_20200526_203123.jpg

此时外部存储根目录在Uri中显示为 “external_storage_root”

所以:

    <external-pathname="external_storage_root"path="." />

中,name代表uri中显示名称,path是绝对路径。

其他路径

    <external-pathname="DCIM"path="DCIM/camerademo" />

我们知道获取DCIM的路径代码是:

Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM).getAbsoluteFile()

打印出的路径是:

/storage/emulated/0/DCIM

所以,我们可以知道替换

            takeImageFile = new File(Environment.getExternalStorageDirectory(), "/DCIM/camera/");

takeImageFile = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM).getAbsoluteFile(), "/DCIM/camera/");

时,会打印出:

content://com.yoshin.company.blogdemo.fileprovider/external_storage_root/DCIM/DCIM/camera/IMG_20200526_203123.jpg

通过:

    <external-pathname="DCIM"path="DCIM/camerademo" />

我们知道,Uri中要显示"DCIM",绝对路径必须是 path=“DCIM/camerademo”,修改代码:

takeImageFile = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM).getAbsoluteFile(), "/camerademo/");

此时,打印出来的Uri即是:

content://com.yoshin.company.blogdemo.fileprovider/DCIM/IMG_20200526_204125.jpg

懂了吗?

当我们代码中使用的绝对路径,(如 “DCIM/camerademo”)匹配到了install.mxl中设置到的path字段的内容(path=“DCIM/camerademo”),Uri中显示路径就会被对应的name字段内容替代了。

配置的标签参照FileProvider里面的TAG配置

3. 访问 FileProvider

    public void takePicture(Activity activity, int requestCode) {Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION| Intent.FLAG_GRANT_WRITE_URI_PERMISSION| Intent.FLAG_ACTIVITY_CLEAR_TOP);if (existSDCard()) {takeImageFile = new File(Environment.getExternalStorageDirectory(), "/DCIM/camera/");} else {takeImageFile = Environment.getDataDirectory();}takeImageFile = createFile(takeImageFile, "IMG_", ".jpg");photoUri = FileProvider.getUriForFile(this,getPackageName() + ".fileprovider",takeImageFile);intent.putExtra(MediaStore.EXTRA_OUTPUT, photoUri);activity.startActivityForResult(intent, requestCode);}

4. 拓展:获取图片方式

4.1 通过绝对路径获取图片

image.setImageBitmap(BitmapFactory.decodeFile(takeImageFile.getAbsolutePath()));

4.2 通过Uri获取资源流

            Bitmap bitmap = null;try {bitmap = BitmapFactory.decodeStream(getContentResolver().openInputStream(photoUri));} catch (FileNotFoundException e) {e.printStackTrace();}image2.setImageBitmap(bitmap);

4.3 通过cursor获取图片

嘿嘿嘿,这是错误示范,引以为戒

            Cursor cursor = getContentResolver().query(photoUri, new String[]{MediaStore.Images.Media.DATA}, null, null, null);if (cursor != null) {if (cursor.getColumnCount() > 0) {if (cursor.moveToFirst()) {int index = cursor.getColumnIndex(MediaStore.Images.Media.DATA);if (index > -1) {path = cursor.getString(index);} else {LogUtils.e(TAG, "cursor index -1");}}}cursor.close();}

通过Uri和selection来获取真实路径
Android系统提供了MediaScanner,MediaProvider,MediaStore等接口,并且提供了一套数据库表格,通过Content Provider的方式提供给用户。当手机开机或者有SD卡插拔等事件发生时,系统将会自动扫描SD卡和手机内存上的媒体文件,如audio,video,图片等,将相应的信息放到定义好的数据库表格中。
在这个程序中,我们不需要关心如何去扫描手机中的文件,只要了解如何查询和使用这些信息就可以了。

MediaStore中定义了一系列的数据表格,通过ContentResolver提供的查询接口,我们可以得到各种需要的信息。

EXTERNAL_CONTENT_URI 为查询外置内存卡的,INTERNAL_CONTENT_URI为内置内存卡。
MediaStore.Audio获取音频信息的类
MediaStore.Images获取图片信息
MediaStore.Video获取视频信息

为什么是错误示范呢?

因为 getContentResolver().query(photoUri, new String[]{MediaStore.Images.Media.DATA}, null, null, null); 查询不到任何图片信息,这和Uri有关系,因为我们的Uri不是目标文件的绝对路径,所以查询不到任何东西。

至于Uri怎么设置成绝对路径(试了试,都没有成功),

我自己拼了个Uri

            Uri uri = new Uri.Builder().scheme("content").authority(BuildConfig.APPLICATION_ID+".fileprovider").path("/DCIM/camerademo/IMG_20200527_093044.jpg").build();

打印:

uri ===content://com.yoshin.company.blogdemo.fileprovider/DCIM/camerademo/IMG_20200527_093044.jpg

替换photoUri去查询,并不好用,查询出0条信息。

再试下,还是不行~~~~

            Uri uri = new Uri.Builder().scheme("content").authority(BuildConfig.APPLICATION_ID+".fileprovider").path("/storage/emulated/0/DCIM/camerademo/IMG_20200527_093044.jpg").build();

崩溃了。

通过cursor获取图片,不太懂怎么弄的,记录一下。欢迎大神留言。感谢。

推荐Github开源项目 SelectImgAsWechath :https://github.com/SCCXYS/SelectImgAsWechat
参考地址:Android FileProvider详细解析和踩坑指南

targetSdk27 FileProvider 摄像和照相相关推荐

  1. 安卓个人中心头像模块(从相册选择和照相功能,适配7.0)

    ** 开篇: ** 1.讲解Intent中的四个重要属性--Action.Data.Category.Extras 2.关于 Android 7.0 适配中 FileProvider 部分的总结 3. ...

  2. 什么是婚礼一条龙服务及一站式服务

    现代的婚礼市场是一个琳琅满目及鱼龙混杂的市场,面对庆典公司.礼仪服务公司.花坊.花店各种服务的店面,新人如何去选择,可以说是一个很大的难题.面对 不了解的行业,新人往往是茫目的选择,或者是单面的选择, ...

  3. switch手柄可以连电脑吗_电脑可以拍照吗

    电脑可以拍照吗?如果可以该怎么设置,相信对于很多想通过电脑进行拍照的朋友来说,这个问题相当重要,下面就给大家科普一下吧. 电脑可以拍照吗? 电脑可以拍照.电脑拍照的方法很多,随着如今摄像头的像素的提升 ...

  4. android 按钮事件添加事件吗,android为按钮添加事件的三种方法

    Android中为按钮添加事件一般有三种方法,这里总结一下,当然其实这完全是java基础内容. 1.内部类: ? 代码片段,双击复制 btn.setOnClickListener(new OnClic ...

  5. 云影数码工作室-创业计划书

    云 影 数 码 工 作 室 创业计划书 团队名称:     云飞工作室 负 责 人:       张建波 成员名单: 黄隆徽 李扬 黄健 刘磊 网   址:   WWW.YUNFLY.COM 联系电话 ...

  6. 中职计算机老师的一天,信息技术教师的一天

    信息技术教师在学校中的地位似乎是可有可无,特别是在评优评先过程中更是这样.但在实际工作中,信息技术教师常常忙得晕头转向,然而,在有些人眼里,信息技术老师就是应该这样,信息技术教师就应该是个修理工,是打 ...

  7. 2014年湛江新教育交流会总结

    转载自sina博主"爱和榜样"的博文"2014年湛江新教育交流会总结",转载请直接引用原链接. 2014年湛江新教育交流会总结 为期半天的2014年湛江新教育交 ...

  8. 基于WinCE6.O操作系统的在线流媒体播放软件设计

    http://www.hqew.com/tech/sheji/526049.html 摘要:互联网的迅猛发展和普及为流媒体业务发展提供了强大的市场动力,流媒体业务正变得日益流行.基于此设计了一个基于W ...

  9. 计算机信息技术专业毕业鉴定,信息技术毕业鉴定自我鉴定.doc

    第一篇.信息技术专业人员工作情况自我鉴定 信息技术毕业鉴定自我鉴定 信息技术专业人员工作情况自我鉴定 这一学期,各位老师们立足岗位,团结协作,求真求实,教书育人,顺利而圆满地完成了各项教育教学任务,并 ...

最新文章

  1. 倒排索引的一些算法调研
  2. java操作大文件复制
  3. SPOJ SUMPRO(数学)
  4. CSS——规避脱标流和vertical-align
  5. ArrayList类contains方法实现原理
  6. azure云数据库_从Azure Databricks将数据加载到Azure SQL数据库
  7. 华为智慧屏云会议怎么操作_会议室预定系统有哪些?怎么操作
  8. 中国银行外币汇率查询
  9. Python制作局域网双人聊天软件(一)
  10. Spring框架学习总结(上)
  11. 记录一次C#爬虫记录,获取必应图片
  12. win7系统同步服务器,win7自动同步服务器
  13. 1021.Deepest Root
  14. 今日新闻快讯摘要十条
  15. XBOX GAMEPASS取消自动续费
  16. 篆刻小站之设计与开发
  17. Netty使用FileUpload报错Not represented by a file
  18. 行人重识别基础(一)
  19. 吉林华微电子: 自主研发砥砺行 助力打造“中国芯”
  20. 【转】前端——实用UI组件库

热门文章

  1. 卡巴斯基2017年第二季度IT威胁及演变
  2. 普乐蛙VR航天科普产品|VR太空模拟器|VR科幻飞碟沉浸式体验
  3. 证明:dim(Null(A))+rank(A)=0
  4. 《第五元素》女高音的歌曲
  5. iOS-icon图标
  6. 小程序项目实施_实施对关键业务IT应用程序的持续分析和管理
  7. 应用在研究半导体和半导体材料电学特性的霍尔效应测试系统介绍
  8. ZIP压缩文件如何设置和清除密码?
  9. 百度人脸识别---横屏,竖屏的实现
  10. 《好了歌》和《好了歌注》