Android7.0 调用相机拍照并裁剪及遇到的坑

之前用的几年的选择头像上传中的拍照上传报错无法使用,错误懒得再重现,大概错误过程如下:
① 代码中无法直接使用imageUri = Uri.fromFile(f);
会报FileUriExposedException,因为在android 6.0 权限需要在运行时候检查, 其他app可能没有读写文件的权限, 所以在android 7.0的时候加上了这个限制。上网查了一下需要使用 FileProvider 解决这个问题。

/**
     * 拍照
     */
    private void takePhoto() {
        Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
        try {
            //错误②
            File f = getCreateFile();
             //错误①
            imageUri = Uri.fromFile(f);
            takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
            startActivityForResult(takePictureIntent, PHOTO_REQUEST_TAKEPHOTO);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

解决方案:在mainfest.xml中配置如下代码:

</application>
        <provider
            android:authorities="应用包名.fileprovider"
            android:name="android.support.v4.content.FileProvider"
            android:grantUriPermissions="true"
            android:exported="false">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/file_paths"/>
        </provider>

</application>

其中内容提供器的grantUriPermissions属性被设置为true,表示权限能够被授予内容提供器范围内的任何数据。但是,如果grantUriPermission属性被设置为false,那么权限就只能授予这个元素所指定的数据子集。一个内容提供器能够包含任意多个个元素。每个都只能指定一个路径(三个可能属性中的一个)。
另外权限不要忘了:
file_paths文件内容如下:

<?xml version="1.0" encoding="utf-8"?> 
<paths>
    <!-- external-path:sd ;path:你的应用保存文件的根目录;name随便定义-->
    <!-- root-path 手机存储根目录 -->
    <root-path path="" name="robot" /> 
</paths>

然后拍照代码改为:

 /**
     * 拍照
     */
    private void takePhoto() {
        Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
        try {
            // 指定存放拍摄照片的位置
            //
            File f =getCreateFile();
            if (Build.VERSION.SDK_INT >= 24) {
                takePictureIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
                imageUri = FileProvider.getUriForFile(getApplicationContext(), _context.getPackageName()+".fileprovider", f);
            } else {
                imageUri = Uri.fromFile(f);
            }
            imageUri = uri;
            takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri );
            startActivityForResult(takePictureIntent, PHOTO_REQUEST_TAKEPHOTO);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

拍照可以了,可是返回执行裁剪操作时又提示toast“无法加载此图片”。着实郁闷,找了找网上的说法,没特别对应的,只好下了个demo,对照排查,发现了错误:
② File f =getCreateFile(); 这个文件已经不能随便找个目录创建了。
原来出错的getCreateFile()方法如下:

 /**
     * 把程序拍摄的照片放到 SD卡的 Pictures目录中 robot 文件夹中
     * 照片的命名规则为:robot_20131106_093721.jpg
     *
     * @return
     * @throws IOException
     */
    @SuppressLint("SimpleDateFormat")
    private File getCreateFile() throws IOException {

        SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd_HHmmss");
        String timeStamp = format.format(new Date());
        imageFileName = "robot_" + timeStamp + ".png";

        File image = new File(PictureUtil.getAlbumDir(), imageFileName);
        mCurrentPhotoPath = image.getAbsolutePath();
        return image;
    }

更改为:

private  File getCreateFile() {

        String cachePath = null;
        if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())
                || !Environment.isExternalStorageRemovable()) {
            cachePath = _context.getExternalCacheDir().getPath();
        } else {
            cachePath = _context.getCacheDir().getPath();
        }
        File dir = new File(cachePath);
        SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd_HHmmss");
        String timeStamp = format.format(new Date());
        String fileName = "robot_" + timeStamp + ".png";
        File file = new File(dir, fileName);
        if (file.exists()) {
            file.delete();
        }
        try {
            file.createNewFile();
        } catch (IOException e) {
            e.printStackTrace();
        }
        mCurrentPhotoPath = file.getAbsolutePath();
        return file;
    }

不太清楚之前的创建路径有什么问题,但是改成下面的代码,在裁剪的时候正常运行了,剪切在sdk24以上需要加上intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
否则会提示toast 无法加载该图片。

猜你喜欢

转载自blog.csdn.net/xinleiweikai/article/details/61417911