React Native CameraRoll安卓11/12保存图片报Operation not permitted错误
问题根因
这个报错是Android 11(API 30)及以上版本分区存储规则限制导致的,当前配置和代码存在三个明确问题:
android:requestLegacyExternalStorage="true"仅对Android 10生效,targetSdkVersion >=30时系统会直接忽略该配置,无法开启旧版存储兼容模式WRITE_EXTERNAL_STORAGE权限在Android 11+不再授予公共存储目录的写入权限,普通应用申请该权限也无法写入相册目录MANAGE_EXTERNAL_STORAGE是全量文件访问权限,仅面向文件管理、数据恢复等核心功能需要访问全磁盘文件的应用开放,普通图片保存场景申请该权限既不必要,上架应用商店还会被拒审
修复步骤
1. 调整AndroidManifest配置
移除无效权限声明,补充高版本系统所需权限,修改AndroidManifest.xml内容:
<!-- 移除WRITE_EXTERNAL_STORAGE、MANAGE_EXTERNAL_STORAGE权限声明 --> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="32" /> <!-- Android 13+读取媒体图片需要单独申请READ_MEDIA_IMAGES权限 --> <uses-permission android:name="android.permission.READ_MEDIA_IMAGES" /> <application <!-- 保留requestLegacyExternalStorage兼容Android 10,高版本系统自动忽略不影响功能 --> android:requestLegacyExternalStorage="true" ...> <!-- 原有组件配置保持不变 --> </application>
2. 更新依赖版本
旧版本@react-native-community/cameraroll未适配Android 11+的分区存储规则,升级到适配版本即可,不需要额外安装fbjs依赖:
yarn add @react-native-community/cameraroll@4.1.2 # 移除之前手动安装的fbjs依赖,新版本已修复相关依赖问题 yarn remove fbjs
RN 0.68.2默认支持依赖自动链接,不需要手动修改settings.gradle中的依赖配置,手动配置反而可能出现版本不匹配问题。
3. 修复权限申请与保存逻辑
不同Android版本需要申请的权限不同,替换原有代码如下:
import { PermissionsAndroid, Platform } from 'react-native'; import CameraRoll from "@react-native-community/cameraroll"; async function hasAndroidPermission() { // Android 13及以上版本申请媒体图片读取权限 if (Platform.Version >= 33) { const permission = PermissionsAndroid.PERMISSIONS.READ_MEDIA_IMAGES; const hasPermission = await PermissionsAndroid.check(permission); if (hasPermission) return true; const status = await PermissionsAndroid.request(permission); return status === 'granted'; } // Android 12及以下版本申请外部存储写入权限 const permission = PermissionsAndroid.PERMISSIONS.WRITE_EXTERNAL_STORAGE; const hasPermission = await PermissionsAndroid.check(permission); if (hasPermission) return true; const status = await PermissionsAndroid.request(permission); return status === 'granted'; } const savePicture = async (path, album) => { if (Platform.OS === "android" && !(await hasAndroidPermission())) { return; } // 增加异常捕获,避免出现未处理的Promise rejection警告 return CameraRoll.save(path, { album, type: 'photo' // 明确指定保存类型为图片,减少兼容问题 }).catch(err => { console.error('保存图片到相册失败:', err); }); }
验证注意事项
- 测试前先到应用设置页面清空已有存储权限,或者清除应用数据,避免旧权限缓存导致测试结果异常
- 待保存的图片如果存放在应用私有目录,cameraroll会自动通过MediaStore API完成文件写入,不需要额外做文件复制或路径转换
- 适配完成后在Android 9/10/11/12/13系统上均可正常保存图片,不需要申请全量文件访问权限
内容的提问来源于stack exchange,提问作者Emanuele Ago
相关产品推荐
相关产品推荐

