最近在项目中有用到相机的功能,通常用法
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION
| Intent.FLAG_GRANT_WRITE_URI_PERMISSION
|Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION);
//file是图片路劲
Uri uri = Uri.fromFile(file);
intent.putExtra(MediaStore.Images.Media.ORIENTATION, 0);
//设置MediaStore.EXTRA_OUTPUT的输出路径为imageFileUri
intent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
activity.startActivityForResult(intent, requestCode);
这样就可以调转相机,前两天还好好的呢,可是今天发现不行了,直接就崩溃了。。错误日志如下,权限异常了。。。
android.os.FileUriExposedException: file:///storage/emulated/0/DCIM/IMG_1041503431.jpg
看了下源码,在targetSdk>=24的时候就得使用content://了
//创建一个图片保存的Uri 在7.0上必须使用contentProvider创建,否则会崩
ContentValues contentValues = new ContentValues(1);
contentValues.put(MediaStore.Images.Media.DATA, file.getAbsolutePath()); uri=activity.getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues);
这时候在7.0手机上运行发现没事了,可是在低版本上运行,就又不行了,所以还得做下区分,最终的使用姿势
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION
| Intent.FLAG_GRANT_WRITE_URI_PERMISSION
| Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION);
Uri uri;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
//创建一个图片保存的Uri 在7.0上必须使用contentProvider创建,否则会崩
ContentValues contentValues = new ContentValues(1);
contentValues.put(MediaStore.Images.Media.DATA, file.getAbsolutePath());
uri = activity.getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues);
} else {
uri = Uri.fromFile(file);
}
intent.putExtra(MediaStore.Images.Media.ORIENTATION, 0);
//设置MediaStore.EXTRA_OUTPUT的输出路径为imageFileUri
intent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
activity.startActivityForResult(intent, requestCode);
就是判断下版本>=24的时候就使用contentValues这种方式,当然还有一种就是在清单文件中注册contentProvider的方式,如下:
<provider android:name="android.support.v4.content.FileProvider" //固定值 android:authorities="com.test.test.fileprovider"//路径 前面为包名,后面为fileprovider固定值,使用包名便于区分
android:exported="false"//是否支持其它应用调用当前组件 ,要求为flase
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"//固定值
android:resource="@xml/filepaths"/>//在res目录下定义的filepaths.xml文件,名字可以自定义
还需要在res文件夹下创建xml文件夹,在创建filePath.xml
<paths>
<!-- xml文件是唯一设置分享的目录 ,不能用代码设置
1.<files-path>getFilesDir() /data/data//files目录
2.<cache-path>getCacheDir() /data/data//cache目录
3.<external-path>Environment.getExternalStorageDirectory()
SDCard/Android/data/你的应用的包名/files/ 目录
4.<external-files-path> Context#getExternalFilesDir(String) Context.getExternalFilesDir(null).
5.<external-cache-path> Context.getExternalCacheDir().
-->
<!-- path :代表设置的目录下一级目录 eg:<external-path path="images/" 整个目录为Environment.getExternalStorageDirectory()+"/images/"
name: 代表定义在Content中的字段 eg:name = "myimages" ,并且请求的内容的文件名为default_image.jpg
则 返回一个URI content://com.example.myapp.fileprovider/myimages/default_image.jpg-->
<!--当path 为空时 5个全配置就可以解决-->
<!--下载apk-->
<external-path path="" name="sdcard_files" />
<!--相机相册裁剪-->
<external-files-path path="" name="camera_has_sdcard"/>
<files-path path="" name="camera_no_sdcard"/>
</paths>
上面注释各个标签的意思已经写清楚了。用哪个看你自己了。。
使用的姿势如下,代替了contentValues那些
一定要注意这里的com.test.test.fileprovider一定要与清单文件中的一样,否则会报错滴。。
Uri uriForFile = FileProvider.getUriForFile(getActivity(), "com.renwohua.conch.fileprovider", mCameraFile); intentFromCapture.putExtra(MediaStore.EXTRA_OUTPUT, uriForFile); intentFromCapture.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); intentFromCapture.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
还有一个就是安装apk,这是都会用的吧。也是前两天用
Intent installIntent = new Intent(Intent.ACTION_VIEW);
installIntent.addCategory(Intent.CATEGORY_DEFAULT);
installIntent.setDataAndType(Uri.fromFile(apkFile),"application/vnd.android.package-archive");
activity.startActivityForResult(installIntent,0x1001);
这样使用没有问题,问了监听是否安装使用了forResult,可是今天在7.0上就完蛋了。。。。一看还是一样的错误,又不行了,需要使用contentProvider来获取路径,真坑啊,忽然就改了,,,幸好还没上线。。。解决办法如下:
Intent installIntent = new Intent(Intent.ACTION_VIEW); installIntent.addCategory(Intent.CATEGORY_DEFAULT); installIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.M) { installIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
String providerString = getFileProviderString(activity);
Uri uri = FileProvider.getUriForFile(activity.getApplicationContext(), providerString, apkFile);
installIntent.setDataAndType(uri, "application/vnd.android.package-archive");
} else {
installIntent.setDataAndType(Uri.fromFile(apkFile), "application/vnd.android.package-archive");
}
activity.getApplication().startActivity(installIntent);
在这里不能使用forResult了,因为使用了Intent.FLAG_ACTIVITY_NEW_TASK标记,如果想监听是否取消另想办法喽。。