Android 11剪裁照片 以及google相册处理

      在android 11之后,android系统存储权限被强制分区,所以照片存储也变得越来越麻烦,加大了开发出现的问题,以下是本人写的demo,沉余代码比较多,我就不删除了,大家也可以通过这些,看到我的调试过程

1.首先,我们需要给应用授权,并申请权限(这没什么好解释的,开发的都懂)

    <uses-permission android:name="android.permission.INTERNET"/>
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.CAMERA" />
 String permission[] = {"android.permission.WRITE_EXTERNAL_STORAGE", "android.permission.READ_EXTERNAL_STORAGE"};    
 if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED
                || ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED
//                ||ContextCompat.checkSelfPermission(this,Manifest.permission.MANAGE_EXTERNAL_STORAGE)!=PackageManager.PERMISSION_GRANTED
        ) {
            //6.0 以上
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                requestPermissions(permission, 100);
            }
        }

2.android11 之后剪裁照片就不能使用file://了,建议使用 MediaStore.Images.Media 来处理,但是问题是,在相册会对应生成bitmap照片,我的处理方式是,在逻辑完成之后删除生成的照片,避免影响用户体验

   

    private void cut(Uri uri) {

        Intent intent = new Intent("com.android.camera.action.CROP");
        intent.setDataAndType(uri, "image/*");
        intent.putExtra("crop", "true");
        intent.putExtra("scale ", true);  //是否保留比例
        intent.putExtra("aspectX", 1);
        intent.putExtra("aspectY", 1);
        intent.putExtra("outputX", 300);
        intent.putExtra("outputY", 300);
        intent.putExtra("return-data", true);
        intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());
        intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {

            cutUri = createR(uri);
            Log.e("clm", "createR: " + cutUri);
            intent.putExtra(MediaStore.EXTRA_OUTPUT, cutUri);
        }
        cut_x = true;
        launcher.launch(intent);
    }

删除照片

                  getContentResolver().delete(cutUri, null);

3.但是你以为这样就搞定了吗?不,太天真了,还有我们的google手机呢。google相册的Uri和我们手机的不同需要特殊处理,不然无法识别到媒体

以上就是我打印出来的路径,google相册需要转换成常规的media,那就是使用bitmap重新替换一张照片,至少我是这样做的。。。

    private Uri toUri(Uri uri) {
        // 1. 获取 Google Photos 照片 Uri 的输入流,并转为 Bitmap
        InputStream is = null;
        try {
            is = getContentResolver().openInputStream(uri);
        } catch (FileNotFoundException e) {
            throw new RuntimeException(e);
        }
        Bitmap bitmap = BitmapFactory.decodeStream(is);

        // 2. 将 bitmap 保存到手机本地相册中获取返回的 uri
        ByteArrayOutputStream bytes = new ByteArrayOutputStream();
        bitmap.compress(Bitmap.CompressFormat.JPEG, 100, bytes);
        String path = MediaStore.Images.Media.insertImage(getContentResolver(), bitmap, "temp", null);
        Log.e("clm", "path: " + path);
        // 能被正确解析的 uri
        Uri result = Uri.parse(path);
        return result;
    }
  private void cut(Uri uri) {

        Intent intent = new Intent("com.android.camera.action.CROP");
        if (uri.toString().contains("content://com.google.android.apps.photos.contentprovider")) {
            //google相册里面的照片地址是需要转换的
            tempToUri = toUri(uri);
        } else {
            tempToUri = null;
        }
        intent.setDataAndType(tempToUri == null ? uri : tempToUri, "image/*");
        intent.putExtra("crop", "true");
        intent.putExtra("scale ", true);  //是否保留比例
        intent.putExtra("aspectX", 1);
        intent.putExtra("aspectY", 1);
        intent.putExtra("outputX", 300);
        intent.putExtra("outputY", 300);
        intent.putExtra("return-data", false);
        intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());
        intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {

            cutUri = createR(uri);
            Log.e("clm", "createR: " + cutUri);
            intent.putExtra(MediaStore.EXTRA_OUTPUT, cutUri);
        }
        cut_x = true;
        launcher.launch(intent);
    }

 至此,项目关键点都已列出,可以根据需要开发或者修改。另外如果大佬有更好的方法或者文中有错误地方,希望不吝赐教,感谢!!!

以下是全部代码,需要的可以自行copy !

package com.u8.base_dialog;

import android.Manifest;
import android.app.Activity;
import android.content.ContentValues;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.provider.MediaStore;
import android.provider.Settings;
import android.util.Log;
import android.view.View;
import android.widget.ImageView;

import androidx.activity.result.ActivityResult;
import androidx.activity.result.ActivityResultCallback;
import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContract;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityOptionsCompat;
import androidx.core.content.ContextCompat;
import androidx.core.content.FileProvider;
import androidx.core.content.PackageManagerCompat;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;

public class SelectPhotoActivity extends AppCompatActivity {


    String permission[] = {"android.permission.WRITE_EXTERNAL_STORAGE", "android.permission.READ_EXTERNAL_STORAGE"};

    private ImageView iv_photo;

    private boolean cut_x = false;

    private Uri cutUri;
    private Uri tempToUri;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.select_photo_activity);
        iv_photo = findViewById(R.id.iv_photo);


        findViewById(R.id.btn_select_photo).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                cut_x = false;
                selectPhoto();
            }
        });

        findViewById(R.id.btn_test_ac).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                testActivity();
            }
        });

        if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED
                || ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED
//                ||ContextCompat.checkSelfPermission(this,Manifest.permission.MANAGE_EXTERNAL_STORAGE)!=PackageManager.PERMISSION_GRANTED
        ) {
            //6.0 以上
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                requestPermissions(permission, 100);
            }
        }


    }


    private ActivityResultLauncher launcher = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), new ActivityResultCallback<ActivityResult>() {
        @Override
        public void onActivityResult(ActivityResult result) {
//            Log.e("clm","----action: "+result.getData().getAction());
//            Log.e("clm","----cate: "+result.getData().getCategories());
            Log.e("clm", "----: " + result.getResultCode());
            Log.e("clm", "----result ok: " + Activity.RESULT_OK);
            if (result.getData() != null) {
                Uri uri = result.getData().getData();
                Log.e("clm", "uri: " + uri);

                if (uri != null) {

                    if (!cut_x) {
                        cut(uri);
                        return;
                    }

                    Bitmap bitmap = null;
                    try {
                        bitmap = BitmapFactory.decodeStream(getContentResolver().
                                openInputStream(uri));
                        Log.e("clm", "bitmap: " + bitmap);
                    } catch (FileNotFoundException e) {
                        throw new RuntimeException(e);
                    }
                    if (bitmap == null) {
                        Bundle bundle = result.getData().getExtras();
                        if (bundle != null) {
                            bitmap = (Bitmap) bundle.get("data");
                        }
                    }
                    saveImg(bitmap);
                    iv_photo.setImageBitmap(bitmap);


                    //删除临时保存在相册的文件
                    /**
                     * 轻轻的存 正如我轻轻的删   不留下一张照片
                     */
                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
                        getContentResolver().delete(cutUri, null);
                        if (tempToUri != null) {
                            getContentResolver().delete(tempToUri, null);
                        }
                    }
                    Log.e("clm", "走了这里111111");
                } else {
                    Bitmap bitmap;

                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
                        try {
                            bitmap = BitmapFactory.decodeStream(getContentResolver().
                                    openInputStream(cutUri));
                        } catch (FileNotFoundException e) {
                            throw new RuntimeException(e);
                        }
                    } else {
                        bitmap = result.getData().getExtras().getParcelable("data");
                        saveImg(bitmap);

                    }
                    iv_photo.setImageBitmap(bitmap);
                    Log.e("clm", "走了这里2222");
                }
            }
        }
    });

    private void selectPhoto() {
        Intent intent = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
        intent.setType("image/*");
        launcher.launch(intent);

    }


    private void cut(Uri uri) {

        Intent intent = new Intent("com.android.camera.action.CROP");
        if (uri.toString().contains("content://com.google.android.apps.photos.contentprovider")) {
            //google相册里面的照片地址是需要转换的
            tempToUri = toUri(uri);
        } else {
            tempToUri = null;
        }
        intent.setDataAndType(tempToUri == null ? uri : tempToUri, "image/*");
        intent.putExtra("crop", "true");
        intent.putExtra("scale ", true);  //是否保留比例
        intent.putExtra("aspectX", 1);
        intent.putExtra("aspectY", 1);
        intent.putExtra("outputX", 300);
        intent.putExtra("outputY", 300);
        intent.putExtra("return-data", false);
        intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());
        intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {

            cutUri = createR(uri);
            Log.e("clm", "createR: " + cutUri);
            intent.putExtra(MediaStore.EXTRA_OUTPUT, cutUri);
        }
        cut_x = true;
        launcher.launch(intent);
    }


    private Uri toUri(Uri uri) {
        // 1. 获取 Google Photos 照片 Uri 的输入流,并转为 Bitmap
        InputStream is = null;
        try {
            is = getContentResolver().openInputStream(uri);
        } catch (FileNotFoundException e) {
            throw new RuntimeException(e);
        }
        Bitmap bitmap = BitmapFactory.decodeStream(is);

        // 2. 将 bitmap 保存到手机本地相册中获取返回的 uri
        ByteArrayOutputStream bytes = new ByteArrayOutputStream();
        bitmap.compress(Bitmap.CompressFormat.JPEG, 100, bytes);
        String path = MediaStore.Images.Media.insertImage(getContentResolver(), bitmap, "temp", null);
        Log.e("clm", "path: " + path);
        // 能被正确解析的 uri
        Uri result = Uri.parse(path);
        return result;
    }


    private Uri createR(Uri uri) {

        File file = new File(Environment.getExternalStorageDirectory().getPath() + File.separator + "clm.jpg");
        if (!file.getParentFile().exists())
        {
            file.getParentFile().mkdirs();
        }
        ContentValues contentValues = new ContentValues();
        contentValues.put(MediaStore.Images.Media.DATA, file.getAbsolutePath());
        contentValues.put(MediaStore.Images.Media.DISPLAY_NAME, "clm.jpg");
        contentValues.put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg");
        contentValues.put(MediaStore.Video.Media.DATE_ADDED, System.currentTimeMillis() / 1000);
        contentValues.put(MediaStore.Video.Media.DATE_MODIFIED, System.currentTimeMillis() / 1000);
        Uri newUrl = getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues);
        return newUrl;
    }

    private void saveImg(Bitmap bitmap) {

        String testPath = Environment.getExternalStorageDirectory() + File.separator + "test.jpg";
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
            testPath = getExternalFilesDir("clm").getAbsolutePath() + File.separator + "test.jpg";
            File file = new File(testPath);
            if (!file.getParentFile().exists()) {
                file.getParentFile().mkdir();
            }

        }
        Log.e("clm", "testPath:  " + testPath);
        File file = new File(testPath);
        try {
            FileOutputStream fileOutputStream = new FileOutputStream(file);
            bitmap.compress(Bitmap.CompressFormat.PNG, 100, fileOutputStream);
            fileOutputStream.flush();
            fileOutputStream.close();
        } catch (FileNotFoundException e) {
            throw new RuntimeException(e);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    private void testActivity() {
        launcher.launch(new Intent(this, MainActivity.class));
    }
}

猜你喜欢

转载自blog.csdn.net/chenluming210/article/details/132490589
今日推荐