使用React Native FS将文件写入Android外部存储

问题描述

我的React Native Android应用程序需要将JSON文件保存在外部存储中的特殊文件夹中。我正在尝试通过RNFS(https://github.com/itinance/react-native-fs)来做到这一点:

const saveData = async () => {
    var path = `${RNFS.ExternalStorageDirectoryPath}/MyApp`;
    RNFS.mkdir(path);
    path += '/data.json';
    RNFS.writeFile(path,JSON.stringify(getData()),'utf8')
      .then((success) => {
        console.log('Success');
      })
      .catch((err) => {
        console.log(err.message);
      });
  }

它运行良好,但在Android Q设备上无法运行。显示此错误:

Error: Directory could not be created

如果我尝试写一个普通文件而不创建目录,则会抛出此错误:

ENOENT: open failed: ENOENT (No such file or directory),open '/storage/emulated/0/data.json'

但是,我已经将此权限添加到了AndroidManifest.xml

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

并在设置中授予了外部存储权限。但是,如果我将RNFS.ExternalStorageDirectoryPath更改为RNFS.DocumentDirectoryPath,它将可以正常工作。但是我需要访问外部存储。有什么办法吗?

解决方法

我发现Android API 29+需要旧版外部存储访问权限。因此,我像这样编辑了AndroidManifest.xml(位于android/app/src/main/中):

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
  package="com.appName">

    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>

    <application
    ...
      android:requestLegacyExternalStorage="true"
    ...
    >
    </application>
</manifest>

一切都开始起作用。另外,我还添加了一个向saveData函数授予权限的请求:

const saveData = async () => {
    try {
      const granted = await PermissionsAndroid.requestMultiple([
        PermissionsAndroid.PERMISSIONS.WRITE_EXTERNAL_STORAGE,PermissionsAndroid.PERMISSIONS.READ_EXTERNAL_STORAGE,]);
    } catch (err) {
      console.warn(err);
    }
    const readGranted = await PermissionsAndroid.check(PermissionsAndroid.PERMISSIONS.READ_EXTERNAL_STORAGE); 
    const writeGranted = await PermissionsAndroid.check(PermissionsAndroid.PERMISSIONS.WRITE_EXTERNAL_STORAGE);
    if(!readGranted || !writeGranted) {
      console.log('Read and write permissions have not been granted');
      return;
    }
    var path = `${RNFS.ExternalStorageDirectoryPath}/MyApp`;
    RNFS.mkdir(path);
    path += '/data.json';
    RNFS.writeFile(path,JSON.stringify(getData()),'utf8')
      .then((success) => {
        console.log('Success');
      })
      .catch((err) => {
        console.log(err.message);
      });
  }
,

在Android版本10(API级别29)中,引入了范围存储的概念。 根据Docs-

“使用户可以更好地控制其文件并限制文件 杂乱无章,针对Android 10(API级别29)及更高版本的应用 通过以下方式获得对外部存储或范围存储的范围内访问: 默认。此类应用只能访问以下位置的应用特定目录: 外部存储以及该应用具有的特定媒体类型 已创建。”

对于Android版本10,您可以选择通过以下方式退出作用域存储 加 AndroidManifest.xml中的android:requestLegacyExternalStorage="true"

这是一个临时解决方案,仅适用于android版本10及其更高版本。 另外,请确保您要求运行时权限来读取/写入外部存储。

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...