You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Flutter的JNI(C代码)中访问/storage/emulated/0/Documents/目录

问题描述

在Android环境中,已确认/storage/emulated/0/Documents/路径下的文件存在,但通过JNI(C代码)访问该路径读取文件时,因权限问题无法打开文件。已配置以下权限及参数:

已配置的权限

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

<!-- 在<application>标签内 -->
android:requestLegacyExternalStorage="true"
android:preserveLegacyExternalStorage="true"

相关代码片段

Dart层

int nResult = (i ~/ 100) * 100;
File agingFile = File("/storage/emulated/0/Documents/$nResult/$i.C03");

await platform.invokeMethod("readFile", agingFile.path);

Java层

if(call.method.equals("readFile")){
   String path = call.arguments();
   ReadFile(path);
}

解决方法

1. 确保动态申请并验证权限状态

  • READ_EXTERNAL_STORAGE/WRITE_EXTERNAL_STORAGE需在运行时动态申请,不能仅依赖Manifest配置;
  • MANAGE_EXTERNAL_STORAGE权限需引导用户跳转到系统设置开启,Java示例代码:
    if (!Environment.isExternalStorageManager()) {
        Intent intent = new Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION);
        Uri uri = Uri.fromParts("package", getPackageName(), null);
        intent.setData(uri);
        startActivity(intent);
    }
    
  • 调用JNI读文件前,必须用Context.checkSelfPermission()确认所有所需权限已授予。

2. 改用文件描述符传递给JNI

JNI直接访问外部存储路径易受沙箱限制,更可靠的方式是Java层先获取文件描述符再传给JNI:

Java层

public static void ReadFile(String path) throws IOException {
    File file = new File(path);
    FileInputStream fis = new FileInputStream(file);
    nativeReadFile(fis.getFD());
    fis.close();
}

// 声明native方法
private native void nativeReadFile(FileDescriptor fd);

JNI层

JNIEXPORT void JNICALL Java_com_your_package_YourClass_nativeReadFile(JNIEnv *env, jobject thiz, jobject fd) {
    int fileDescriptor = (*env)->GetIntField(env, fd, (*env)->GetFieldID(env, (*env)->FindClass(env, "java/io/FileDescriptor"), "descriptor", "I"));
    FILE *file = fdopen(fileDescriptor, "r");
    if (file == NULL) {
        // 处理打开失败逻辑
        return;
    }
    // 执行文件读取操作
    fclose(file);
}

3. 适配不同Android版本的存储策略

  • Android 10(API 29)及以上,即使开启requestLegacyExternalStorage,部分场景仍会限制直接路径访问;
  • Android 11(API 30)及以上,MANAGE_EXTERNAL_STORAGE是访问全量外部文件的必要权限,但注意该权限仅适用于文件管理器类应用,不符合Google Play政策的应用可能被拒审。

4. 排查JNI路径处理问题

  • 打印JNI中接收的路径,确认与Java层传递的完全一致,避免字符串编码错误;
  • 检查JNI中open()函数的错误码(如errno),EACCES表示权限拒绝,ENOENT表示文件路径错误,精准定位问题。

内容的提问来源于stack exchange,提问作者Jungwon

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 08:20:43