Android14部分存储权限下如何正确获取用户选择的图片?
Android 14 部分存储权限下无法捕获用户选中图片的解决方案
问题描述
开发支持图库选择照片/视频的Android应用时,在Android 14(API 34)的部分存储权限机制下遇到异常:用户选择「SELECT PHOTOS AND VIDEOS」授予READ_MEDIA_VISUAL_USER_SELECTED权限后,系统自动弹出的媒体选择器选中的图片无法被正确获取,自定义的selectFirstImageFromMedia()方法返回随机旧图而非用户本次选中的内容。
错误原因
核心逻辑错误:当用户授予部分权限时,系统自动启动的媒体选择器,其选中结果不会通过MediaStore查询返回,而是必须通过标准的ActivityResult回调接收。你当前尝试用MediaStore查询获取选中内容的方式,在部分权限模式下只能访问用户之前授权过的媒体文件,和本次选择完全无关。
解决方案
统一使用ActivityResultContracts.PickVisualMedia契约处理所有权限场景的媒体选择,移除错误的MediaStore查询逻辑:
1. 修正权限检查逻辑
public boolean checkPermission(String permission) { int statusCode = ContextCompat.checkSelfPermission(this, permission); return statusCode == PackageManager.PERMISSION_GRANTED; } // 权限检查触发逻辑 int sdk = Build.VERSION.SDK_INT; if (sdk >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) { // 只要有任一权限就启动媒体选择器 if (checkPermission(Manifest.permission.READ_MEDIA_IMAGES) || checkPermission(Manifest.permission.READ_MEDIA_VISUAL_USER_SELECTED)) { selectImage(); } else { permissionLauncher.launch(new String[]{ Manifest.permission.READ_MEDIA_IMAGES, Manifest.permission.READ_MEDIA_VISUAL_USER_SELECTED }); } }
2. 修正权限回调处理
移除selectFirstImageFromMedia()的调用,直接启动媒体选择器:
permissionLauncher = registerForActivityResult(new ActivityResultContracts.RequestMultiplePermissions(), result -> { boolean hasAnyPermission = false; int sdk = Build.VERSION.SDK_INT; if (sdk >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) { hasAnyPermission = checkPermission(Manifest.permission.READ_MEDIA_IMAGES) || checkPermission(Manifest.permission.READ_MEDIA_VISUAL_USER_SELECTED); } if (hasAnyPermission) { selectImage(); } else { Toast.makeText(this, "应用需要权限才能选择图片", Toast.LENGTH_SHORT).show(); } });
3. 保留原有的媒体选择与结果回调逻辑
selectImage()和pickMedia回调无需修改,PickVisualMedia契约会自动适配权限场景:
public void selectImage() { int sdk = Build.VERSION.SDK_INT; if (sdk >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) { pickMedia.launch(new PickVisualMediaRequest.Builder() .setMediaType(ActivityResultContracts.PickVisualMedia.ImageOnly.INSTANCE) .build()); } else { Intent picIntent = new Intent(Intent.ACTION_GET_CONTENT, null); picIntent.setType("image/*"); picIntent.putExtra("return_data", true); startActivityForResult.launch(picIntent); } } // 接收Android 14+的媒体选择结果 pickMedia = registerForActivityResult(new ActivityResultContracts.PickVisualMedia(), uri -> { if (uri != null) { setImageInView(uri); } else { Toast.makeText(getApplicationContext(), "已取消选择", Toast.LENGTH_SHORT).show(); } });
4. 移除无用的selectFirstImageFromMedia()方法
该方法在部分权限场景下无法获取正确结果,直接删除即可。
原理说明
- 当用户授予
READ_MEDIA_VISUAL_USER_SELECTED权限时,系统自动弹出的选择器是权限授权流程的一部分,其选中结果只能通过ActivityResult回调接收,无法通过MediaStore查询获取 PickVisualMedia契约已经适配了Android 14的部分权限机制,无论用户授予全部权限还是部分权限,都会正确返回用户选中的媒体URI
内容的提问来源于stack exchange,提问作者Deyvison Cruz
相关产品推荐
相关产品推荐

