Android 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);
   //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标记,如果想监听是否取消另想办法喽。。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值