如何在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
相关产品推荐
相关产品推荐

