Android 7.0 之拍照與圖片裁剪適配

lixiaobo 7年前發布 | 26K 次閱讀 安卓開發 Android開發 移動開發

在Android 7.0以上,在相機拍照和圖片裁剪上,可能會碰到以下一些錯誤:

Process: com.yuyh.imgsel, PID: 22995

// 錯誤1
android.os.FileUriExposedException: file:///storage/emulated/0/Android/data/com.yuyh.imgsel/cache/1486438962645.jpg exposed beyond app through ClipData.Item.getUri()

// 錯誤2
android.os.FileUriExposedException: file:///storage/emulated/0/DCIM/RxGalleryFinal/IMG_20161018180127.jpg exposed beyond app through Intent.getData()

主要是由于在Android 7.0以后,用了Content Uri 替換了原本的File Uri,故在targetSdkVersion=24的時候,部分 “`Uri.fromFile()“` 方法就不適用了。 **File Uri 與 Content Uri 的區別** - File Uri 對應的是文件本身的存儲路徑 - Content Uri 對應的是文件在Content Provider的路徑 所以在android 7.0 以上,我們就需要將File Uri轉換為 Content Uri。具體轉換方法如下:

/**
 * 轉換 content:// uri
 * 
 * @param imageFile
 * @return
 */
public Uri getImageContentUri(File imageFile) {
    String filePath = imageFile.getAbsolutePath();
    Cursor cursor = getContentResolver().query(
            MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
            new String[] { MediaStore.Images.Media._ID },
            MediaStore.Images.Media.DATA + "=? ",
            new String[] { filePath }, null);

    if (cursor != null && cursor.moveToFirst()) {
        int id = cursor.getInt(cursor
                .getColumnIndex(MediaStore.MediaColumns._ID));
        Uri baseUri = Uri.parse("content://media/external/images/media");
        return Uri.withAppendedPath(baseUri, "" + id);
    } else {
        if (imageFile.exists()) {
            ContentValues values = new ContentValues();
            values.put(MediaStore.Images.Media.DATA, filePath);
            return getContentResolver().insert(
                    MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
        } else {
            return null;
        }
    }
}

那么,我們在裁剪的時候,應該如下調用:

private void crop(String imagePath) {
    File file = new File("xxx.jpg");
    cropImagePath = file.getAbsolutePath();

    Intent intent = new Intent("com.android.camera.action.CROP");
    intent.setDataAndType(getImageContentUri(new File(imagePath)), "image/*");
    intent.putExtra("crop", "true");
    intent.putExtra("aspectX", config.aspectX);
    intent.putExtra("aspectY", config.aspectY);
    intent.putExtra("outputX", config.outputX);
    intent.putExtra("outputY", config.outputY);
    intent.putExtra("scale", true);
    intent.putExtra("return-data", false);
    intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(file));
    intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());
    intent.putExtra("noFaceDetection", true);
    startActivityForResult(intent, IMAGE_CROP_CODE);
}

這樣就解決了裁剪的問題,但是!!拍照的時候就會出現以下錯誤:

Intent cameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
if (cameraIntent.resolveActivity(getActivity().getPackageManager()) != null) {
    tempFile = new File(FileUtils.createRootPath(getActivity()) + "/" + System.currentTimeMillis() + ".jpg");
    LogUtils.e(tempFile.getAbsolutePath());
    FileUtils.createFile(tempFile);
    cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(tempFile));
    startActivityForResult(cameraIntent, REQUEST_CAMERA);
}
android.os.FileUriExposedException: file:///storage/emulated/0/Android/data/com.yuyh.imgsel/cache/1486438962645.jpg exposed beyond app through ClipData.Item.getUri()

這是因為拍照存儲的文件,也需要以Content Uri的形式,故采用以下辦法解決:

Step.1

修改AndroidManifest.xml

<application
    ...>

    <provider
        android:name="android.support.v4.content.FileProvider"
        android:authorities="{替換為你的包名}.provider"
        android:exported="false"
        android:grantUriPermissions="true">
        <meta-data
            android:name="android.support.FILE_PROVIDER_PATHS"
            android:resource="@xml/provider_paths"/>
    </provider>
</application>

Step.2

在res/xml/下新建provider_paths.xml文件

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <external-path name="external_files" path="."/>
</paths>

Step.3

修改拍照時的參數

cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, FileProvider.getUriForFile(getActivity(),BuildConfig.APPLICATION_ID + ".provider", tempFile)); //Uri.fromFile(tempFile)

搞定!

 

來自:http://blog.csdn.net/yyh352091626/article/details/54908624

 

 本文由用戶 lixiaobo 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!