Android 11 recorta fotos y procesa álbumes de fotos de Google

      Después de Android 11, los permisos de almacenamiento del sistema Android se ven obligados a particionarse, por lo que el almacenamiento de fotos se vuelve cada vez más problemático, lo que aumenta los problemas de desarrollo. La siguiente es una demostración escrita por mí. Hay mucho código, así que no lo eliminaré. it. , también puedes ver mi proceso de depuración a través de estos

1. Primero, debemos autorizar la aplicación y solicitar permiso (esto no es nada que explicar, todos los desarrolladores lo entienden)

    <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. Después de Android11, ya no puedes usar file:// para recortar fotos. Se recomienda usar MediaStore.Images.Media para procesar. Sin embargo, el problema es que las fotos de mapa de bits se generarán correspondientemente en el álbum. Mi método de El procesamiento es eliminar las fotos generadas una vez completada la lógica para evitar afectar la experiencia del usuario.

   

    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);
    }

borrar foto

                  getContentResolver().delete(cutUri, null);

3. ¿Pero crees que es eso? No, eso es demasiado ingenuo. Todavía tenemos nuestros teléfonos Google. El Uri de Google Photos es diferente al de nuestros teléfonos móviles y requiere un procesamiento especial; de lo contrario, no se pueden reconocer los medios.

Lo anterior es la ruta que imprimí. Google Photos debe convertirse a un medio normal, es decir, usar un mapa de bits para reemplazar una foto, al menos eso es lo que hice. . .

    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);
    }

 En este punto, se han enumerado los puntos clave del proyecto y se pueden desarrollar o modificar según sea necesario. Además, si tienes un método mejor o hay errores en el artículo, espero que me ilumines, ¡gracias! ! !

El siguiente es todo el código, ¡puede copiarlo usted mismo si es necesario!

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));
    }
}

Supongo que te gusta

Origin blog.csdn.net/chenluming210/article/details/132490589
Recomendado
Clasificación