android相机、相册相关(android13 适配)13又又又又又又搞事,让第三方难以生存,踩坑

这篇具有很好参考价值的文章主要介绍了android相机、相册相关(android13 适配)13又又又又又又搞事,让第三方难以生存,踩坑。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前几天公司开发的新项目要上线,结果......

由于项目中有用户更换头像功能,应用市场经过检测android13无法更换头像,也没有崩溃也没有反应,所以App就被无情退回,相当无奈,那就查问题,手头有没有android13测试机,怎么办,怎么办,怎么办...那就想办法,还好vivo有云测试,也是真机那种,关键还免费,帮了大忙。

    开始不是太了解android13究竟更新了什么,一顿查找资料.......过了几天其实还是很懵逼,网上资料很少介绍,那就自己一点一点一点试呗,中国有句古话(只要功夫深铁杵磨成针)让我听从古训,坚持磨针。就开始将之前第三方选择照片框架去掉自己就用原生试。果然经过很多弯路终于解决问题,一下给大家分享。

android13 之前读写文件权限是这样写的
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE">
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE">
<uses-permission android:name="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" />

将读取本地图片、视频、音频权限细分

开始我真的没有怎么明白怎么回事,用法上也有错误、我判断版本进行申请不同的权限,结果就是实现不了,一直有错,有一顿查看资料,一顿试,最终上天被我感动赐我一缕灵光,上代码

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("权限被拒绝!!!");
                }
            }
        });

就是上面的代码,你说可气不可气,直接申请新权限即可,当你申请新权限时,也就直接默认同一之前的权限了,也可以理解为新权限覆盖了老权限不用苦逼的判断版本什么的了。XXPermissions权限框架自己网上查看

权限申请完既可以调用相机相册功能了,但是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);

这是点击按钮后调用,根据type区分拍照还是相册选取,CAMERA_REQUEST_CODE这是自己定义的code方便onActivityResult返回是接收你的图片

希望能帮助需要帮助的人,有问题可以私聊文章来源地址https://www.toymoban.com/news/detail-456449.html

到了这里,关于android相机、相册相关(android13 适配)13又又又又又又搞事,让第三方难以生存,踩坑的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Android相册选择图片、相机拍照上传功能实现(上)

    先上效果图 下面就来说一下相册选择图片和相机拍照的实现 相册选择图片很简单,只需要通过 Intent 设置拉起就可以了 Intent 拉起相册 /** 打开相册 @param type 打开类型区分码(type是我用来区分回调的) / private void openGallery(int type) { Intent gallery = new Intent(Intent.ACTION_PICK); galler

    2024年04月16日
    浏览(54)
  • Android 使用 registerForActivityResult() 打开系统相册或相机获取图像

    当使用了 AndroidX 后,发现 `startActivityForResult()` 标记为过时了,而是推荐我们使用 `registerForActivityResult()` 函数。 `registerForActivityResult()` 函数是 Android 中用于启动 Activity 结果回调的新方式。这个函数的目的是简化在 Activity 和 Fragment 之间进行启动其他 Activity 并接收结果的过程

    2024年02月08日
    浏览(52)
  • Android打开系统相机或从相册中选择图片并显示

    xml代码 展示  java代码 实机演示  

    2024年02月11日
    浏览(56)
  • Android(6-13)适配

    Android 6 1、运行时权限 android6.0以前,我们把app需要用到的权限全部罗列在Manifest清单文件中。安装app时android系统会询问用户是否授予这些权限,拒绝后则无法安装app。如果授予,则安装app,之后无法修改授予状态。 android6.0将权限分为普通权限(不涉及用户隐私和安全)和危

    2024年02月02日
    浏览(49)
  • Android 13 适配指南

    是的,你没看错,现在就要带你适配 Android13 。 2022 的Google I/O 发布了 Android 13 beta 2 和 Android 13 Beta 1 国内厂商的设备支持列表,虽然按照惯例, Android 13 应该是年末才发布正式版,但是相信有的开发者已经收到了平台的 Android13 的适配要求,所以本篇也是结合 Oppo 的 Android 1

    2024年02月05日
    浏览(44)
  • Android13音频录制适配

    之前写过一篇音频录制的文章,当时是在Android10以下的手机可以成功录制和播放,但是Android10及以上手机提示创建文件失败,最近做过Android13的适配,索性一起把之前的录音也适配了,记录一下适配的过程。 主要就是文件的生成和创建,由于Android10以后不能随意创建私有文件

    2024年02月21日
    浏览(44)
  • Android 13 变更及适配攻略

    首先将我们项目中的 targetSdkVersion 和 compileSdkVersion 升至 33。 1.通知受限 对新安装的应用的影响: 如果用户在搭载 Android 13 或更高版本的设备上安装您的应用,应用的通知默认处于关闭状态。在您请求新的权限且用户向您的应用授予该权限之前,您的应用都将无法发送通知。

    2024年02月03日
    浏览(45)
  • android8、android13自适应图标适配

    前言:为了解决应用图标在不同android手机上的外观样式问题,google官方在android8和android13两个版本做了变更(这2个版本都提供了向下兼容),下文介绍适配方法以及 注意事项(此处有彩蛋) 。 一、android8(API27)适配 1、找到资源文件夹:mipmap-anydpi-v26(若旧的as里没有默认生成,

    2024年02月09日
    浏览(69)
  • Android13适配所有文件管理权限

    很早之前在Android11上面就适配过所有文件管理权限,这次是海外版升级到Android13,由于选择相册用的是第三方库,组内的同事没有上架Google的经验直接就提交代码,虽然功能没有问题,但是上架的时候被打回了,于是记录一下适配工作. 绝大多数需要共享存储空间访问权限的

    2024年01月22日
    浏览(39)
  • Android CameraX适配Android13的踩坑之路

    最近把AGP插件升级到8.1.0,新建项目的时候目标版本和编译版本都是33,发现之前的demo使用Camerax拍照和录像都失败了,于是查看了一下官网和各种资料,找到了Android13的适配方案. 与早期版本一样,Android 13 包含一些行为变更,这些变更可能会影响您的应用。以下行为变更仅影

    2024年02月12日
    浏览(75)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包