Android7.0调用相机出现android.os.FileUriExposedException异常

Android  N。。。android

昨天把项目targetSdkVersion改为了26。问题接踵而来。bash

最严重的就是项目中有地方调用到了系统相机拍照功能,拍完返回图片一张。app

(Android中很多地方须要这样作的)有两种实现方法。其实这里的两种实现方法原理都是同样的。都是隐士Intent开启系统相机。拍完照后返回所拍摄的照片。ide

只不过两种方法返回的东西不同。ui

一种直接返回图片this

一种返回启动相机界面前指定的存储拍摄图片的Urispa

第一种方法:code

Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE)
                startActivityForResult(intent, TAKE_PHOTO_REQUEST)
复制代码

这里咱们只须要指定Intent的actioni就能够实现了。xml

能够在onActivityResult的回调中经过intent回传获取到图片对象。对象

Bitmap  photo = intent.getParcelableExtra("data")复制代码

这样的图片对象回传不用想指定是没有第二种方法更为节省内存

项目中也是使用的第二种方法:

root_dir = Environment.getExternalStorageDirectory().toString() + File.separator + Constant.CACHE_PATH
pt_dir = root_dir + File.separator + "bike_operation.jpg"复制代码

先指定好图片要存储的路径。

下面先说一下N之前的操做。

你只须要以下:

val intentFromCapture = Intent(MediaStore.ACTION_IMAGE_CAPTURE)

  intentFromCapture.putExtra(MediaStore.EXTRA_VIDEO_QUALITY, 1)
intentFromCapture.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(File(pt_dir)))startActivityForResult(intentFromCapture, Constant.PAIZHAO_REQUEST)
复制代码

经过Uri。fromFile指定一下图片存储路径对应的Uri

就能够在onActivityResult的回调中再次获取到这个Uri从而经过解析Uri拿到对应的文件路径。生成对应的Bitmap。

然而,由于昨天的targetSdkVersion改为了26在N设备上运行该代码的时候报了以下错误

android.os.FileUriExposedException: file:///storage/emulated/0/mangoebike_operation_cache/bike_damage.jpg exposed beyond app through ClipData.Item.getUri()
复制代码

文件Uri解析异常Google一下才晓得了就是7.0增长了更为严格的进程间文件数据共享的机制

Uri的获取方式不能再像往常同样获取了。须要以下作法

<provider
    android:name="android.support.v4.content.FileProvider"
    android:authorities="com.whxxcy.mango_operation.fileProvider"
    android:exported="false"
    android:grantUriPermissions="true">
    <meta-data
        android:name="android.support.FILE_PROVIDER_PATHS"
        android:resource="@xml/file_paths" />
</provider>
复制代码

清单application节点下面指定provider属性。authorities属性能够本身随意指定。可是要记得代码中待会儿还要用到它。这里咱们就以包名加.fileProvider.字段来指定。

再一个须要咱们指定的就是这个resource属性了。在res文件目录下新建xml文件夹再在文件夹中建立file_paths文件。

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <paths>
        <external-path
            name="bike_operation"
            path="mangoebike_operation_cache" />
    </paths>
</resources>

复制代码

path属性在个人理解是用来拼接Uri的就是你不写它会在根目录中去寻找存放文件。

name属性必须指定。不指定编译通不过。在个人理解这个name属性实际上是你在代码中拍照生成的文件的名字。

指定完这两个属性来看代码:

val intentFromCapture = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
intentFromCapture.putExtra(MediaStore.EXTRA_VIDEO_QUALITY, 1)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
    val contentUri = FileProvider.getUriForFile(this@OperationActivity, packageName + ".fileProvider", File(pt_dir))
    intentFromCapture.putExtra(MediaStore.EXTRA_OUTPUT, contentUri)     //将拍取的照片保存到指定URI
} else {
    intentFromCapture.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(File(pt_dir)))
}
startActivityForResult(intentFromCapture, Constant.PAIZHAO_REQUEST)复制代码

若是当前sdk版本大于等于24Uri的获取方式就变成

= FileProvider.getUriForFile(this@OperationActivity, packageName + ".fileProvider", File(pt_dir))复制代码

参数1: 上下文。参数2: 就是在provider中指定的authitrites。参数3:File对象一开始指定的存储拍摄照片的路径

而后在onActivityResult的回调中解析Uri获得Bitmap对象就能够啦。。。有描述不许确的地方后续再改正。。。。

相关文章
相关标签/搜索