React Native存储Realm文件至SD卡遇Read-Only Filesystem错误求助
解决React Native中Realm存储到外部SD卡的"Read-Only Filesystem"错误
首先得明确这个错误的核心原因:Android 10及以上的分区存储机制,哪怕你申请了WRITE_EXTERNAL_STORAGE权限,也没法直接写入外部SD卡的任意目录——系统默认限制了普通应用对SD卡公共区域的写入权限,必须通过特定方式获取可写的目录权限。
下面是一步步的解决方案:
1. 完善权限配置
(1)更新AndroidManifest.xml
确保权限配置覆盖不同Android版本的要求:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="28" /> <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" android:minSdkVersion="30" /> <!-- 针对Android 10,临时兼容旧存储模式(Android 12+该属性失效) --> <application ... android:requestLegacyExternalStorage="true">
WRITE_EXTERNAL_STORAGE仅在Android 10(API29)以下有效,10及以上已被弱化。MANAGE_EXTERNAL_STORAGE是Android 11(API30)及以上需要的全存储管理权限,但这个权限不能通过常规弹窗请求,必须引导用户到应用设置页面手动开启。
(2)权限请求的代码实现
在React Native中,针对不同Android版本处理权限:
import { Platform, Linking } from 'react-native'; import PermissionsAndroid from 'react-native/Libraries/PermissionsAndroid'; const checkAndRequestStoragePermission = async () => { if (Platform.OS !== 'android') return true; if (Platform.Version >= 30) { const hasPermission = await PermissionsAndroid.check(PermissionsAndroid.PERMISSIONS.MANAGE_EXTERNAL_STORAGE); if (!hasPermission) { // 跳转到应用设置页面让用户开启权限 await Linking.openSettings(); } } else { // Android 10及以下,请求WRITE_EXTERNAL_STORAGE const granted = await PermissionsAndroid.request( PermissionsAndroid.PERMISSIONS.WRITE_EXTERNAL_STORAGE, { title: '存储权限请求', message: '应用需要访问外部存储来保存Realm文件', buttonNeutral: '稍后', buttonNegative: '取消', buttonPositive: '确定', }, ); return granted === PermissionsAndroid.RESULTS.GRANTED; } return true; };
2. 正确获取SD卡的可写路径
你用RFNS拿到的路径可能是SD卡的公共目录(比如根目录、Download),这些目录现在是只读的,得换两种可写路径:
(1)应用专属的外部SD卡目录
每个应用在SD卡上有专属的读写目录(/storage/<SD卡ID>/Android/data/<你的包名>/files/),不需要额外权限就能用,用RFNS获取:
import RNFS from 'react-native-fs'; const getAppSdCardDir = async () => { const externalDirs = await RNFS.getExternalDirectoryPaths(); // 数组第一个是内置存储,第二个是SD卡(如果存在) if (externalDirs.length > 1) { return externalDirs[1]; } // 没有SD卡则返回内置外部存储 return externalDirs[0]; };
(2)通过SAF获取用户授权的自定义目录
如果要存到SD卡的非应用专属目录,必须用SAF让用户手动选择目录并授权,可借助react-native-document-picker实现:
import DocumentPicker from 'react-native-document-picker'; const pickSdCardDir = async () => { try { const res = await DocumentPicker.pickDirectory({ mode: 'open', }); // res.uri就是用户选中的SD卡目录Uri return res.uri; } catch (err) { if (DocumentPicker.isCancel(err)) { // 用户取消选择,可做提示 } else { throw err; } } };
3. 配置Realm使用指定路径
拿到可写路径后,初始化Realm时指定path参数:
import Realm from 'realm'; const initRealmWithSdCardPath = async () => { const sdCardDir = await getAppSdCardDir(); // 或用pickSdCardDir()获取的Uri const realmPath = `${sdCardDir}/myRealm.realm`; const realm = await Realm.open({ schema: [YourDataSchema], // 替换成你的Realm Schema path: realmPath, }); return realm; };
关键注意事项
- 优先用应用专属目录:Android 12+分区存储限制更严格,应用专属目录兼容性最好,无需额外授权。
- 文件迁移:如果之前Realm文件在内部存储,需要手动复制到SD卡新路径,再修改初始化配置。
- 权限检查时机:每次使用Realm前都要确认权限已获取,避免用户后续关闭权限导致报错。
内容的提问来源于stack exchange,提问作者Ian Ferreira
相关产品推荐
相关产品推荐

