在安卓开发中调用系统相机本来是一个非常方便的事情,但是最近使用了安卓N模拟器去调用相机出现崩溃,查看一下原因原来是google在API24以后对权限设置进行了更改,使用API24版本以后的系统,在调用系统相机的时候要注意咯,原先的方式不行了。行不行的我自己先总结一下。
一般情况,以上代码在Android6.0以下,也就是api<24时,运行是没有任何问题的。可是当targetSdkVersion变成24及其以上并且在android6.0(及以上版本)系统运行时,会抛出异常:FileUriExposedException。这是因为google之后修改了权限 android N以后收回了访问文件的权限,按照android N的要求,若在应用间共享文件,需要发送Content://Uri,而不再是File://Uri,并且需要对此Uri进行临时访问授权。 不太清楚,大家网上一搜很多教程。那我只写写如何做。
首先在清单文件中进行FileProvider注册。 如图
<!--安卓6.0以后手机相机访问权限--> <provider android:name="android.support.v4.content.FileProvider" android:authorities="com.shao.jobsnaps.provider" android:exported="false" android:grantUriPermissions="true"> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths" /> </provider>在你的res下创建一个xml的目录,接着创建一个file_paths.xml (file_paths可以随便起名,只要再配置清指定一下就可以了) xml里边配置
<?xml version="1.0" encoding="utf-8"?> <resources> <paths xmlns:android="http://schemas.android.com/apk/res/android"> <external-path name="my_camera" path="" /> <external-path name="files_root" path="Android/data/com.shao.jobsnaps/" /> <external-path name="external_storage_root" path="." /> </paths> </resources>补充:下一般常用以下子节点: <files-path>:Context.getFilesDir()——指向内部存储要共享的目录 <cache-path>:Context.getCacheDir()——指向缓存要共享的目录 <external-path>:Environment.getExternalStorageDirectory()——指向外部存储要共享的目录 <root-path>:尚未发现官方对其的说明,知道的童鞋欢迎补充。根据字面理解,为整个存储的根路径,针对诸如查找不到照片地址的Bug。 name为自定义的名字,path为目录,path=”“指的是全部录|path=”.”即为当前的根目录
如果你不做什么要求,你只需要写一个就ok了 path留空 ,如下:
<?xml version="1.0" encoding="utf-8"?> <resources> <paths xmlns:android="http://om/apk/res/android"> <external-path name="my_camera" path=" /> </path> </resources>相机代码,这里边加了24api之前的调用
public static Uri takePiture(Activity context, String photoPath, int requestCode) { Uri imageUri; if (ContextCompat.checkSelfPermission(context, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED || ContextCompat.checkSelfPermission(context, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { //申请相机权限 ActivityCompat.requestPermissions(context, new String[]{Manifest.permission.CAMERA}, 1); if (ActivityCompat.shouldShowRequestPermissionRationale(context, Manifest.permission.CAMERA)) { // ToastUtils.showShort(this, "您已经拒绝过一次"); showMsg("您已经拒绝过一次"); } // ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA, Manifest.permission.READ_EXTERNAL_STORAGE}, CAMERA_PERMISSIONS_REQUEST_CODE);*//* FileUtils.verifyStoragePermissions(context); } else {///有权限直接调用系统相机拍照 /* FileModel model = new FileModel(); String photoPath = model.getCurrentFilePath(projectId, parentId) + "IMG-"+DateUtils.getStringDate()+ ".jpg";*/ imageUri = Uri.fromFile(new File(photoPath)); Intent intent = new Intent(); intent.setAction(MediaStore.ACTION_IMAGE_CAPTURE); if (FileUtils.checkSDWritable()) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) // 将文件转换成content://Uri的形式 imageUri = FileProvider.getUriForFile(context, context.getPackageName() + ".provider", new File(photoPath)); // 申请临时访问权限 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION); intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri); } else { intent.addCategory(Intent.CATEGORY_DEFAULT); Uri uri = Uri.parse("file://" + photoPath); intent.putExtra(MediaStore.EXTRA_OUTPUT, uri); } context.startActivityForResult(intent,requestCode); return imageUri }