Flutter在Rooted Device复制文件遇Permission denied(errno=13)问题求助
问题
在已Root的Android设备上,使用Flutter 3.7.11、Android SDK 33.0.2开发应用,通过root_access和permission_handler包尝试将/data/file.txt复制到外部存储/storage/emulated/0/documents/file.txt时,尽管已申请并获取所有必要权限,仍报错:
OS Error: Permission denied, errno = 13
已在AndroidManifest.xml中添加对应权限,且普通存储间的复制操作正常。
引发错误的代码片段:
import 'dart:async'; import 'dart:io'; import 'package:permission_handler/permission_handler.dart'; import 'package:root_access/root_access.dart'; Future<void> copyrootfile() async { var status = await Permission.storage.status; var status2 = await Permission.accessMediaLocation.status; var status3 = await Permission.manageExternalStorage.status; if (!status.isGranted) { await Permission.storage.request(); } if (!status2.isGranted) { await Permission.accessMediaLocation.request(); } if (!status3.isGranted) { await Permission.manageExternalStorage.request(); } await RootAccess.requestRootAccess; var rootFileText = "/data/file.txt"; final rootFile = File(rootFileText); var copyTo = '/storage/emulated/0/documents/file.txt'; if(rootFile.existsSync()){ await rootFile.copy(copyTo); } }
更新后的错误日志:
E/flutter (27371): [ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: FileSystemException: Cannot copy file to '/storage/emulated/0/Documents/file.txt', path = '/data/file.txt' (OS Error: Permission denied, errno = 13) E/flutter (27371): #0 _checkForErrorResponse (dart:io/common.dart:42:9) E/flutter (27371): #1 _File.copy.<anonymous closure> (dart:io/file_impl.dart:339:7) E/flutter (27371): <asynchronous suspension> E/flutter (27371): #2 _MyHomePageState.copyrootfile (package:rootcopy/main.dart:90:7) E/flutter (27371): <asynchronous suspension> E/flutter (27371): #3 _MyHomePageState.build.<anonymous closure> (package:rootcopy/main.dart:130:17) E/flutter (27371): <asynchronous suspension>
解决建议
问题核心:Flutter原生的
File.copy()是在应用自身进程权限下执行的,即便请求了Root权限,这个方法也不会自动以Root身份运行。/data属于系统级目录,普通应用进程无法直接访问,必须通过Root权限执行Shell命令才能操作。具体修复步骤:
- 替换
File.copy()方法,改用RootAccess.executeCommand()执行系统cp命令完成复制。 - 修改后的代码示例:
Future<void> copyrootfile() async { // 保留原有权限请求逻辑 var status = await Permission.storage.status; var status2 = await Permission.accessMediaLocation.status; var status3 = await Permission.manageExternalStorage.status; if (!status.isGranted) await Permission.storage.request(); if (!status2.isGranted) await Permission.accessMediaLocation.request(); if (!status3.isGranted) await Permission.manageExternalStorage.request(); // 确认Root权限获取成功 bool hasRoot = await RootAccess.requestRootAccess; if (!hasRoot) { // 处理Root授权失败的情况,比如弹窗提示用户 return; } final sourcePath = "/data/file.txt"; final destPath = "/storage/emulated/0/Documents/file.txt"; // 提前创建目标目录(防止目录不存在导致复制失败) Directory(destPath.split('/').sublist(0, -1).join('/')).createSync(recursive: true); // 执行Root级别的复制命令,部分设备需用完整路径:/system/bin/cp final result = await RootAccess.executeCommand("cp $sourcePath $destPath"); // 可根据result判断命令执行是否成功,做后续处理 } - 额外注意点:
- 部分设备的
cp命令可能需要指定绝对路径(如/system/bin/cp),如果直接用cp失败,可尝试替换为完整路径。 - 执行Shell命令后,可通过返回的
result内容判断操作是否成功,针对性处理异常情况。
- 部分设备的
- 替换
内容的提问来源于stack exchange,提问作者Ashok
相关产品推荐
相关产品推荐

