使用FileProvider
使用FileProvider的大致步骤如下:
第一步:在manifest清单文件中注册provider
<!--注册provider 赋予Uri权限(grantUriPermissions)--> <provider android:name="android.support.v4.content.FileProvider" android:authorities="com.cjy.fileprovider" android:grantUriPermissions="true" android:exported="false"> <!--设置要分享的路径--> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths" /> </provider>
第二步:指定共享的目录
为了指定共享的目录我们需要在资源(res)目录下创建一个xml目录,然后创建一个名为“file_paths”(名字可以随便起,只要和在manifest注册的provider所引用的resource保持一致即可)的资源文件
<?xml version="1.0" encoding="utf-8"?> <PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"> <paths> <external-path path="cjy" name="myFile" /> </paths> </PreferenceScreen>
注:上述代码中path=""
,是有特殊意义的,它代码根目录,也就是说你可以向其它的应用共享根目录及其子目录下任何一个文件了,如果你将path设为path="pictures"
, 那么它代表着根目录下的pictures目录(eg:/storage/emulated/0/pictures),如果你向其它应用分享pictures目录范围之外的文件是不行的。
1.调用系统相机拍照
以调用系统相机拍照为例,我们需要将上述拍照代码修改为如下:
private Uri imageUri; public void useCamera(){ Intent intent = new Intent(Intent.ACTION_VIEW); intent.setAction(MediaStore.ACTION_IMAGE_CAPTURE);//设置Action为拍照 intent.putExtra("camerasensorytpe", 2); // 调用前置摄像头 intent.putExtra("autofocus", true); // 自动对焦 intent.putExtra("fullScreen", false); // 全屏 intent.putExtra("showActionIcons", false); File file=new File(Environment.getExternalStorageDirectory(), "/cjy/"+System.currentTimeMillis() + ".jpg"); if (!file.getParentFile().exists())file.getParentFile().mkdirs(); // 判断是否是7.0 if(Build.VERSION.SDK_INT >= 24){ // 适配android7.0 ,不能直接访问原路径 // 需要对intent 授权 intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); imageUri = FileProvider.getUriForFile(MainActivity.this, "com.example.administrator.myapplication3.fileprovider", file);//通过FileProvider创建一个content类型的Uri } else { imageUri = Uri.fromFile(file); } intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);//将拍取的照片保存到指定URI startActivityForResult(intent,1006); }
上述代码中主要有两处改变:
1. 将之前Uri的scheme类型为file的Uri改成了有FileProvider创建一个content类型的Uri。2. 添加了intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
来对目标应用临时授权该Uri所代表的文件。
2.裁切照片
File file=new File(Environment.getExternalStorageDirectory(), "/cjy/"+System.currentTimeMillis() + ".jpg"); if (!file.getParentFile().exists())file.getParentFile().mkdirs(); Uri outputUri = FileProvider.getUriForFile(context, "com.cjy.fileprovider",file); Uri imageUri=FileProvider.getUriForFile(context, "com.cjy.fileprovider", new File("/storage/emulated/0/temp/1474960080319.jpg");//通过FileProvider创建一个content类型的Uri Intent intent = new Intent("com.android.camera.action.CROP"); intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); intent.setDataAndType(imageUri, "image/*"); intent.putExtra("crop", "true"); intent.putExtra("aspectX", 1); intent.putExtra("aspectY", 1); intent.putExtra("scale", true); intent.putExtra(MediaStore.EXTRA_OUTPUT, outputUri); intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString()); intent.putExtra("noFaceDetection", true); // no face detection
startActivityForResult(intent,1008);
3.获取文件的Uri
Intent i = new Intent(Intent.ACTION_VIEW); i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); // 判断是否是7.0 if(Build.VERSION.SDK_INT >= 24){ // 适配android7.0 ,不能直接访问原路径 // 需要对intent 授权 i.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); i.setDataAndType(FileProvider.getUriForFile(context, context.getPackageName() + ".fileProvider",new File(filePath)),"application/vnd.android.package-archive"); } else{ i.setDataAndType(Uri.fromFile(new File(filePath)), "application/vnd.android.package-archive"); } context.startActivity(i);
Android 7.0 应用了以下优化措施:
- 在 Android 7.0上 应用不会收到
CONNECTIVITY_ACTION
广播,即使你在manifest清单文件中设置了请求接受这些事件的通知。 但,在前台运行的应用如果使用BroadcastReceiver 请求接收通知,则仍可以在主线程中侦听 CONNECTIVITY_CHANGE。 - 在 Android 7.0上应用无法发送或接收
ACTION_NEW_PICTURE
或ACTION_NEW_VIDEO
类型的广播。