안드로이드 카메라, 사진첩 관련(안드로이드13적응) 13 번번이 말썽을 일으켜 서드파티가 살아남기 어렵게 구덩이를 밟고

며칠 전 회사에서 개발한 새 프로젝트가 온라인으로 진행되었고 그 결과...

사용자가 프로젝트에서 아바타를 변경할 수 있는 기능으로 인해 앱 시장에서 android13이 아바타를 변경할 수 없다는 것을 테스트했으며 충돌이나 응답이 없으므로 앱이 무자비하게 반환되었습니다. 매우 무력한 다음 문제를 확인하십시오. android13 테스트 기계가 있는데 어떻게 해야 할까요 무엇을 해야할지 어떻게 해야할지..그럼 방법을 생각해보세요.다행히 비보에는 클라우드 테스트가 있는데 이것도 일종의 실제 전화입니다.핵심은 그것은 무료이며 큰 도움이 됩니다.

    처음에는 android13에서 업데이트된 내용에 대해 잘 모르고 정보를 찾아보았는데 며칠이 지나도 여전히 매우 혼란스럽고 온라인 정보가 거의 없어서 조금씩 해보았습니다, 중국 (쿵푸가 깊고 쇠공이를 갈아서 바늘로 만드는 한) 옛말을 따르고 바늘을 갈아야 한다고 주장하는 옛말이 있습니다. 이전에 타사에서 선택한 포토 프레임을 제거하기 시작하여 네이티브로 시도했습니다. 아니나 다를까, 많은 우회 끝에 마침내 문제가 해결되었으므로 여러분과 공유하겠습니다.

android13 이전 의 읽기 및 쓰기 파일 권한은 다음과 같이 작성됩니다 . = "android.permission.MANAGE_EXTERNAL_STORAGE">


android13 이후 파일 권한 읽기 및 쓰기는 다음과 같이 작성됩니다.

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"
    android:maxSdkVersion="32"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
    android:maxSdkVersion="32"/>
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"
    android:maxSdkVersion="32"/>

추가해야 합니다(강조).

<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
<uses-permission android:name="android.permission.READ_MEDIA_AUDIO" />
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />

로컬 사진, 비디오, 오디오 권한 세분화를 읽습니다.

처음에는 정말 무슨 내용인지 잘 이해가 되지 않고 사용상의 실수도 있었고 버전을 판단하고 다른 권한을 신청했지만 결과적으로는 구현이 되지 않았습니다. A ray of inspiration, on 코드

XXPermissions.with(activity)
        // 不适配分区存储应该这样写
        //.permission(Permission.MANAGE_EXTERNAL_STORAGE)android 13 废弃AndroidManifest.xml也要去掉
        // 适配分区存储应该这样写
        .permission(Permission.CAMERA)//android 13使用一下权限
        .permission(Permission.READ_MEDIA_IMAGES)//读取照片
        .permission(Permission.READ_MEDIA_VIDEO)//读取视频
        .permission(Permission.READ_MEDIA_AUDIO)//读取音频(按需申请)
        .interceptor(new PermissionInterceptor())
        .request(new OnPermissionCallback() {

            @Override
            public void onGranted(@NonNull List<String> permissions, boolean allGranted) {
                if (allGranted) {
                    if ("1".equals(type)) {//这是自己写的工具类下面给你们贴出源码
                        PhotoUtils.getPicFromCamera(activity, resultCode);
                    } else {
                        PhotoUtils.getPicFromAlbm(activity, resultCode);
                    }
                }

            }

            @Override
            public void onDenied(@NonNull List<String> permissions, boolean doNotAskAgain) {
                OnPermissionCallback.super.onDenied(permissions, doNotAskAgain);
                if (doNotAskAgain) {
                    ToastUtil.show("权限被拒绝!!!");
                }
            }
        });

위의 코드입니다. 화를 낼 수 없다고 하면 새 권한을 신청하면 됩니다. 새 권한을 신청하면 바로 이전 권한이 기본으로 적용됩니다. 권한은 이전 권한을 포함하므로 강제할 필요가 없습니다. 버전이 무엇인지 확인합니다. XX 권한 온라인에서 직접 볼 수 있는 권한 프레임워크

권한 신청 후 카메라 앨범 기능을 호출할 수 있는데 android11 ​​이후로 많은 부분이 변경되었고 android13에서 파일 관리에 대한 조정을 했습니다. 위의 수술 후 다시 여기에 붙어 공부를 계속했는데 아흔 아홉, 여든 하나의 어려움 끝에 해결되었습니다. 코드

 /**
     * 从相机获取图片
     *
     * @param activity   上下文
     * @param resultCode 请求吗
     */
    public static void getPicFromCamera(Activity activity, int resultCode) {
        //用于保存调用相机拍照后所生成的文件
        tempFile = new File(activity.getExternalFilesDir(DIRECTORY_DCIM), "/wy_head.jpg");
        //跳转到调用系统相机
        Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
        //判断版本
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {  
 //如果在Android7.0以上,使用FileProvider获取Uri xxx.client.xxx.fileProvider 红色是自己的//包名,也可以自己定义,反正要和AndroidManifest.xml里面定义的一致就行 intent.setFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
            Uri contentUri = FileProvider.getUriForFile(activity, file_provider, tempFile);
            intent.putExtra(MediaStore.EXTRA_OUTPUT, contentUri);

        } else {    //否则使用Uri.fromFile(file)方法获取Uri
            intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(tempFile));
        }
        activity.startActivityForResult(intent, resultCode);
    }

    /**
     * 从相册获取图片
     *
     * @param activity   上下文
     * @param resultCode 请求吗
     */
    public static void getPicFromAlbm(Activity activity, int resultCode) {
        Intent photoPickerIntent = new Intent(Intent.ACTION_PICK);
        photoPickerIntent.setType("image/*");
        activity.startActivityForResult(photoPickerIntent, resultCode);
    }

이것은 내가 천천히 알아 낸 것입니다. 아마도 위대한 신들도 그것을했을 것입니다. 그러나 나는 그것을 시도하고 제대로 할 수 없었기 때문에 마스터의 블로그를 읽으면서 스스로 해결책을 찾기 시작했고 해결할 수있었습니다. .

@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if (resultCode == RESULT_OK) {
        Bitmap bitmap;
        File imageFile = new File(getExternalFilesDir(DIRECTORY_DCIM), "/wy_img.jpg");
        switch (requestCode) {
            case CAMERA_REQUEST_CODE:
                //用相机返回的照片去调用剪裁也需要对Uri进行处理
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                    bitmap = PhotoUtils.getBitmapFromUri(LaunchComplaintActivity.this, PhotoUtils.getUri(LaunchComplaintActivity.this));
                } else {
                    bitmap = PhotoUtils.getBitmapFromUri(LaunchComplaintActivity.this, Uri.fromFile(PhotoUtils.tempFile));
                }
                PhotoUtils.qualityCompress(bitmap, imageFile);//压缩图片
                UPlLoad(imageFile);
                break;
            case ALBUM_REQUEST_CODE:
                bitmap = PhotoUtils.getBitmapFromUri(LaunchComplaintActivity.this, data.getData());
                PhotoUtils.qualityCompress(bitmap, imageFile);//压缩图片
                UPlLoad(imageFile);
                break;
            default:
                break;
        }
    }
}

기본 코드는 다음과 같습니다. 일부 도구 소스 코드는 아래에서 공유됩니다.

package sol.client.com.utils;

import static android.os.Environment.DIRECTORY_DCIM;
import static android.os.Environment.DIRECTORY_DOWNLOADS;

import android.app.Activity;
import android.content.Intent;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.provider.MediaStore;

import androidx.annotation.NonNull;
import androidx.core.content.FileProvider;

import com.base_libs.utils.ToastUtil;
import com.hjq.permissions.OnPermissionCallback;
import com.hjq.permissions.Permission;
import com.hjq.permissions.XXPermissions;

import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.List;

import sol.client.com.permission.PermissionInterceptor;

public class PhotoUtils {


    public static File tempFile;
    /**
     * 这个要和 AndroidManifest provider一致
     * 他的值和 AndroidManifest 一致即可没有标准
     **/
    private static final String file_provider = "sol.client.com.fileProvider";

    /**
     * 拍照相册权限 适配android 13
     *
     * @param activity
     * @param type       1、相机请求 2、相册请求(可自己定义)
     * @param resultCode
     */
    public static void requirePermission(Activity activity, String type, int resultCode) {

        XXPermissions.with(activity)
                // 不适配分区存储应该这样写
                //.permission(Permission.MANAGE_EXTERNAL_STORAGE)android 13 废弃AndroidManifest.xml也要去掉
                // 适配分区存储应该这样写
                .permission(Permission.CAMERA)//android 13使用一下权限
                .permission(Permission.READ_MEDIA_IMAGES)
                .permission(Permission.READ_MEDIA_VIDEO)
                .permission(Permission.READ_MEDIA_AUDIO)
                .interceptor(new PermissionInterceptor())
                .request(new OnPermissionCallback() {

                    @Override
                    public void onGranted(@NonNull List<String> permissions, boolean allGranted) {
                        if (allGranted) {
                            if ("1".equals(type)) {
                                PhotoUtils.getPicFromCamera(activity, resultCode);
                            } else {
                                PhotoUtils.getPicFromAlbm(activity, resultCode);
                            }
                        }

                    }

                    @Override
                    public void onDenied(@NonNull List<String> permissions, boolean doNotAskAgain) {
                        OnPermissionCallback.super.onDenied(permissions, doNotAskAgain);
                        if (doNotAskAgain) {
                            ToastUtil.show("权限被拒绝!!!");
                        }
                    }
                });
    }

    /**
     * 从相机获取图片
     *
     * @param activity   上下文
     * @param resultCode 请求吗
     */
    public static void getPicFromCamera(Activity activity, int resultCode) {
        //用于保存调用相机拍照后所生成的文件
        tempFile = new File(activity.getExternalFilesDir(DIRECTORY_DCIM), "/wy_head.jpg");
        //跳转到调用系统相机
        Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
        //判断版本
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {   //如果在Android7.0以上,使用FileProvider获取Uri
//            intent.setFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
            Uri contentUri = FileProvider.getUriForFile(activity, file_provider, tempFile);
            intent.putExtra(MediaStore.EXTRA_OUTPUT, contentUri);

        } else {    //否则使用Uri.fromFile(file)方法获取Uri
            intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(tempFile));
        }
        activity.startActivityForResult(intent, resultCode);
    }

    /**
     * 从相册获取图片
     *
     * @param activity   上下文
     * @param resultCode 请求吗
     */
    public static void getPicFromAlbm(Activity activity, int resultCode) {
        Intent photoPickerIntent = new Intent(Intent.ACTION_PICK);
        photoPickerIntent.setType("image/*");
        activity.startActivityForResult(photoPickerIntent, resultCode);
    }

    /**
     * 保存切图到本地 DOWNLOADS-WYXY文件夹
     *
     * @param activity
     * @param name
     * @param bmp
     * @return
     */
    public static String saveImage(Activity activity, String name, Bitmap bmp) {
        File appDir = new File(activity.getExternalFilesDir(DIRECTORY_DOWNLOADS), "WYXY");
        if (!appDir.exists()) {
            appDir.mkdir();
        }
        String fileName = name + ".jpg";
        File file = new File(appDir, fileName);
        try {
            FileOutputStream fos = new FileOutputStream(file);
            bmp.compress(Bitmap.CompressFormat.PNG, 100, fos);
            fos.flush();
            fos.close();
            return file.getAbsolutePath();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }


    public static Uri getUri(Activity activity) {
        return FileProvider.getUriForFile(activity, file_provider, PhotoUtils.tempFile);
    }

    //Uri转化为Bitmap
    public static Bitmap getBitmapFromUri(Activity activity, Uri uri) {
        Bitmap bitmap = null;
        try {
            bitmap = BitmapFactory.decodeStream(activity.getContentResolver().openInputStream(uri));
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        return bitmap;
    }

    public static String getPathToUri(Activity activity, Uri uri) {
        String[] proj = {MediaStore.Images.Media.DATA};
        Cursor cursor = activity.managedQuery(uri, proj, null, null, null);
        int actual_image_column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
        //游标跳到首位,防止越界
        cursor.moveToFirst();
        return cursor.getString(actual_image_column_index);
    }

    public File saveFile(Bitmap bm, String fileName) {//将Bitmap类型的图片转化成file类型,便于上传到服务器
        String path = Environment.getExternalStorageDirectory() + "/wy";
        File dirFile = new File(path);
        if (!dirFile.exists()) {
            dirFile.mkdir();
        }
        File myCaptureFile = new File(path + fileName);
        BufferedOutputStream bos = null;
        try {
            bos = new BufferedOutputStream(new FileOutputStream(myCaptureFile));
            bm.compress(Bitmap.CompressFormat.JPEG, 80, bos);
            bos.flush();
            bos.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

        return myCaptureFile;

    }

    /**
     * 质量压缩
     * 设置bitmap options属性,降低图片的质量,像素不会减少
     * 第一个参数为需要压缩的bitmap图片对象,第二个参数为压缩后图片保存的位置
     * 设置options 属性0-100,来实现压缩(因为png是无损压缩,所以该属性对png是无效的)
     *
     * @param bmp
     * @param file 保存到的位置
     */
    public static void qualityCompress(Bitmap bmp, File file) {
        // 0-100 100为不压缩
        int quality = 70;
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        // 把压缩后的数据存放到baos中
        bmp.compress(Bitmap.CompressFormat.JPEG, quality, outputStream);
        try {
            FileOutputStream fos = new FileOutputStream(file);
            fos.write(outputStream.toByteArray());
            fos.flush();
            fos.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <paths>
        <root-path
            name="camera_photos"
            path="" />
    </paths>
</resources>

    @Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (resultCode == RESULT_OK) {
            Bitmap bitmap;
            File imageFile = new File(getExternalFilesDir(DIRECTORY_DCIM), "/wy_img.jpg");
            switch (requestCode) {
                case CAMERA_REQUEST_CODE:
                    //用相机返回的照片去调用剪裁也需要对Uri进行处理
                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                        bitmap = PhotoUtils.getBitmapFromUri(LaunchComplaintActivity.this, PhotoUtils.getUri(LaunchComplaintActivity.this));
                    } else {
                        bitmap = PhotoUtils.getBitmapFromUri(LaunchComplaintActivity.this, Uri.fromFile(PhotoUtils.tempFile));
                    }
                    PhotoUtils.qualityCompress(bitmap, imageFile);//压缩图片
                    UPlLoad(imageFile);//自己写上传代码逻辑
                    break;
                case ALBUM_REQUEST_CODE:
                    bitmap = PhotoUtils.getBitmapFromUri(LaunchComplaintActivity.this, data.getData());
                    PhotoUtils.qualityCompress(bitmap, imageFile);//压缩图片
                    UPlLoad(imageFile);//自己写上传代码逻辑
                    break;
                default:
                    break;
            }
        }
    }

메모:

PhotoUtils.requirePermission(LaunchComplaintActivity.this, "1", CAMERA_REQUEST_CODE);

버튼 클릭 후 호출되며, 종류에 따라 사진을 찍을 것인지, 앨범을 선택할 것인지를 구분하기 위해 사용되며, CAMERA_REQUEST_CODE는 onActivityResult의 반환을 용이하게 하여 사진을 받을 수 있도록 자체 정의한 코드입니다.

도움이 필요한 분들에게 도움이 되었으면 합니다. 궁금한 점이 있으면 비공개 채팅을 할 수 있습니다.

Supongo que te gusta

Origin blog.csdn.net/qiankun_zyk/article/details/129797081
Recomendado
Clasificación