Android 11如何读取相机拍摄图片?更新裁剪库后onActivityResult返回null
问题根因
- Android 7.0开始就禁止跨应用传递
file://类型的Uri,Android 11对分区存储的管控进一步收严,你原有代码里用Uri.fromFile生成的Uri无法被相机应用正常识别写入,导致拍照后返回数据异常。 - 你注释的FileProvider调用参数错误,且没有给相机应用授予临时Uri访问权限,同时预先指定拍照输出路径时,系统本身就不会在
onActivityResult的Intent里携带数据,返回null属于预期行为。
解决方案
1. 配置FileProvider
首先在AndroidManifest.xml的<application>标签内添加Provider声明:
<provider android:name="androidx.core.content.FileProvider" android:authorities="${applicationId}.fileprovider" android:exported="false" android:grantUriPermissions="true"> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths" /> </provider>
然后在res/xml目录下新建file_paths.xml文件,内容如下:
<?xml version="1.0" encoding="utf-8"?> <paths> <external-cache-path name="external_cache" path="." /> </paths>
这里配置的路径对应你代码里用的应用外存缓存目录,保证FileProvider可以正常生成该路径下的Uri。
2. 修正Uri生成方法
修改你的getCaptureImageOutputUri方法,正确使用FileProvider生成Uri:
public static Uri getCaptureImageOutputUri(@NonNull Context context) { Uri outputFileUri = null; File getImage = context.getExternalCacheDir(); if (getImage != null) { File outputFile = new File(getImage.getPath(), "pickImageResult.jpeg"); // 注意这里的authorities要和Manifest里配置的一致,必须加.fileprovider后缀 outputFileUri = FileProvider.getUriForFile(context, context.getPackageName() + ".fileprovider", outputFile); } return outputFileUri; }
3. 调整裁剪库调用逻辑
启动裁剪的时候主动传入你生成的输出Uri,同时不需要依赖返回Intent携带数据,先把生成的Uri保存为全局变量:
// 先生成拍照输出Uri,保存为全局变量方便后续读取 Uri captureUri = getCaptureImageOutputUri(AbcActivity.this); CropImage .activity() .setGuidelines(CropImageView.Guidelines.ON) .setBorderCornerColor(Color.RED) .setBorderLineColor(Color.CYAN) .setAutoZoomEnabled(true) .setRequestedSize(300, 300) // 主动指定拍照输出的Uri .setOutputUri(captureUri) .start(AbcActivity.this);
4. 修正onActivityResult处理逻辑
预先指定输出路径的场景下,返回的Intent为null是正常情况,直接读取你之前生成的captureUri即可:
@Override protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == CropImage.CROP_IMAGE_ACTIVITY_REQUEST_CODE) { CropImage.ActivityResult result = CropImage.getActivityResult(data); if (resultCode == RESULT_OK) { // 优先读取返回的Uri,为空的话直接读你预先定义的captureUri Uri resultUri = result != null ? result.getUri() : captureUri; // 后续处理resultUri即可 } else if (resultCode == CropImage.CROP_IMAGE_ACTIVITY_RESULT_ERROR_CODE) { Exception error = result.getError(); // 处理错误逻辑 } } }
额外注意事项
- 原版ArthurHub的Android Image Cropper库已经停止维护,未适配Android11以上系统,建议切换到社区维护的分支,避免后续出现更多兼容性问题。
- Android11及以上版本不需要申请存储权限即可读写应用私有目录(包括内部存储、外存缓存、外存私有目录),不需要额外申请
READ_EXTERNAL_STORAGE等权限。 - 如果需要访问其他应用的公共媒体文件,再按需申请对应媒体权限即可。
内容的提问来源于stack exchange,提问作者Rezaul Khan
相关产品推荐
相关产品推荐

