最近发现再安卓14的系统上,用户无法正常使用相册图片更换头像
问题一
相册空白(权限问题)
解决方案
添加关键动态权限READ_MEDIA_VISUAL_USER_SELECTED
mainfest仍然需要添加权限
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
<uses-permission android:name="android.permission.READ_MEDIA_VISUAL_USER_SELECTED"
android:minSdkVersion="34" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"
android:maxSdkVersion="32" />
权限动态代码(此处用谷歌EasyPermissions框架,其它框架用法类似,回调省略。。。)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
String[] perms32 = {
Manifest.permission.READ_MEDIA_IMAGES,
Manifest.permission.READ_MEDIA_VISUAL_USER_SELECTED
};
if (!EasyPermissions.hasPermissions(this, perms32)){
EasyPermissions.requestPermissions(this, getString(R.string.permission_request),
READ_MEDIA_IMAGES, perms32);
}
} else if (Build.VERSION.SDK_INT == Build.VERSION_CODES.TIRAMISU) {
//录音下一个版本在开发
String[] perms32 = {
Manifest.permission.READ_MEDIA_IMAGES
};
if (!EasyPermissions.hasPermissions(this, perms32)){
EasyPermissions.requestPermissions(this, getString(R.string.permission_request),
READ_MEDIA_IMAGES, perms32);
}
} else {
String[] perms = {
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE};
if (!EasyPermissions.hasPermissions(this, perms)){
EasyPermissions.requestPermissions(this, getString(R.string.permission_request),
READ_EXTERNAL_STORAGE, perms);
//以上代码兼容各个版本,已经不需要单独兼容安卓11,故以下代码废弃
// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
// Uri uri = Uri.parse("package:" + getPackageName());
// startActivity(new Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION, uri));
// }
}
}
此处就是当选择图片以后 进入系统裁剪
特别说明 Global.setCropPhotoFilePath(imgFile.getAbsolutePath());
全局保存图片的路径,系统裁剪完成之后这个路径就是裁剪后的图片。
此处可以自行优化,安卓13以后,外部存储已经指定了的图片存储位置,只需要知道图片名,即可找到文件
//支持安卓各种版本的裁剪功能
public static void startIconPhotoCrop(Activity context, Uri sourceUri) {
File imgFile;
Intent intent = new Intent("com.android.camera.action.CROP");
intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.putExtra("crop", "true");
intent.putExtra("aspectX", 1); //X方向上的比例
intent.putExtra("aspectY", 1); //Y方向上的比例
intent.putExtra("outputX", 256); //裁剪区的宽
intent.putExtra("outputY", 256); //裁剪区的高
intent.putExtra("scale ", true); //是否保留比例
intent.putExtra("return-data", false);
intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());
intent.setDataAndType(sourceUri, "image/*"); //设置数据源
Uri uri;
try {
// String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
String uuid = AndroidUtil.getUUID().replace("-","");
String fileName = "CROP_"+ uuid +".jpg";
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
imgFile = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES) + File.separator + fileName);
ContentValues values = new ContentValues();
values.put(MediaStore.Images.Media.DISPLAY_NAME, fileName);
values.put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg");
values.put(MediaStore.Images.Media.RELATIVE_PATH, Environment.DIRECTORY_PICTURES);
Uri externalUri = MediaStore.Images.Media.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY);
uri = context.getContentResolver().insert(externalUri, values);
} else if (Build.VERSION.SDK_INT == Build.VERSION_CODES.R) {
imgFile = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES) + File.separator + fileName);
// 通过 MediaStore API 插入file 为了拿到系统裁剪要保存到的uri(因为App没有权限不能访问公共存储空间,需要通过 MediaStore API来操作)
ContentValues values = new ContentValues();
//安卓13起不能使用MediaStore.Images.Media.DATA否则会报错Mutation of _data is not allowed
values.put(MediaStore.Images.Media.DATA, imgFile.getAbsolutePath());
values.put(MediaStore.Images.Media.DISPLAY_NAME, fileName);
values.put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg");
uri = context.getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
} else {
imgFile = FileManager.ofMedia(fileName);
uri = Uri.fromFile(imgFile);
}
intent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
Global.setCropPhotoFilePath(imgFile.getAbsolutePath());
context.startActivityForResult(intent, Constant.RESULT_ZOOM);
} catch (Exception e) {
e.printStackTrace();
return;
}