全部代码:点击下载
注意:如果你原先的应用的targetSdkVersion本来就小与27。那就拍照。什么都不修改。也不会崩溃。但是、一旦你修改了你的targetSdkVersion为27.或者28。那你的应用就会报出这些问题。。具体原因。请自行百度下targetSdkVersion的意义。
Android 7.0以上的系统。在拍照的时候。报错:
android.os.FileUriExposedException: file:///storage/emulated/0/Android/data/XXX/files/avatar.jpg exposed beyond app through ClipData.Item.getUri()
在网上查一下就可以知道。这是Android7.0的“私有目录被限制访问”。具体的解释简书的一篇文章:
https://www.jianshu.com/p/2275bb552327
里面讲的很仔细。
然后我们知道问题的解决办法就是通过FileProvider.可是我们应该怎么用。在哪个地方使用。
A:FileProvider的使用步骤:
1:在资源(res)目录下创建一个xml目录,然后创建一个名为"file_paths"的资源文件
(res-->new -->Directory.然后输入xml。在xml上右击--》new--》XML--->ValuesXmL-->输入名字file_paths
不过会跑到values下面去。。不慌我们剪切到xml下面即可)
xml里面的内容如下:
具体解释:借用上面链接文章里面的一段文字:
所以:我上面的路径应该是:/storage/emulated/0/Android/data/com.example.zongm.testapplication/ 之所以这样写。是想要在应用删除的时候。在应用里面拍的照片也能够被删除掉。
2:在manifest清单文件中注册provider(放在application节点里面)
<provider android:name="android.support.v4.content.FileProvider" android:authorities="com.example.zongm.testapplication.provider" android:exported="false" android:grantUriPermissions="true"> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths" /> </provider>
解释:
android:authorities="com.example.zongm.testapplication.provider" 这个值可以随便写。我用的是appid。这个值决定了fileProVider生成的uri的路径。后面详细介绍
exported:要求必须为false,为true则会报安全异常。grantUriPermissions:true,表示授予 URI 临时访问权限。
然后我们就可以在代码中使用FileProvider了。
使用:
private Uri getImageUri() { if (isSdCardExist()) { photo_image = new SimpleDateFormat("yyyy_MMdd_hhmmss").format(new Date()); File[] dirs = ContextCompat.getExternalFilesDirs(this, null); if (dirs != null && dirs.length > 0) { File dir = dirs[0]; File file = new File(dir, photo_image); takePath = file.getAbsolutePath(); Log.e("zmm", "图片的路径---》" + takePath); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { //FileProvider.getUriForFile();第一个参数是context. // 第二个值。比较关键、这个也就是我们在manifest里面的provider里面的 //android:authorities="com.example.zongm.testapplication.provider" //因为我用的就是AppId.所以。这里就直接用BuildConfig.APPLICATION_ID了。 //如果你的android:authorities="test.provider"。那这里第二个参数就应该是test.provider return FileProvider.getUriForFile(getApplicationContext(), BuildConfig.APPLICATION_ID + ".provider", file); } else { return Uri.fromFile(file); } } } return Uri.EMPTY; }
下面通过一个例子来看看我们如何使用。代码注释写的很清楚了应该:
public class Main3Activity extends AppCompatActivity { //打开相机的返回码 private static final int CAMERA_REQUEST_CODE = 1; //选择图片的返回码 private static final int IMAGE_REQUEST_CODE = 2; //剪切图片的返回码 public static final int CROP_REREQUEST_CODE = 3; private ImageView iv; //相机 public static final int REQUEST_CODE_PERMISSION_CAMERA = 100; public static final int REQUEST_CODE_PERMISSION_GALLERY = 101; //照片图片名