有什么方法可以用 flutter 将文件写入 SDCard File.writeAsStringSync
Is there any way of writing files to SDCard with flutter File.writeAsStringSync
我正在尝试写入位于 SDCard 中的文件,我发现我需要对可移动存储的特殊权限,这在任何已知的 flutter 权限处理程序插件中都找不到(我试过 simple_permission 和 permission_handler 没用)。
我尝试使用事物的 android 方面获取这些权限,因此我编写了一个简单的函数来显示对话框,用户将允许该应用修改 SDCard 的内容。
即使在获得 SD 卡的权限后,我在尝试使用 File.writeAsStringSync 方法将文件保存到 SDCard 时仍然遇到相同的权限被拒绝的错误。
想知道有没有什么已知的way/hack/workaround可以在flutter中保存文件到SD卡
我使用的 android 代码与此答案相同:
注意: 我的目标是 android 7 及以后,但不是 android 11.
我通过放弃保存 dart 文件并使用 android SAF 解决了这个问题。
首先,我所做的是尝试获取 sdCard 修改权限。
之后,我开始保存我需要的文件。
这是我用来获取权限的代码(又名“允许此应用修改您的 sdCard 上的内容”对话框)
public void takeCardUriPermission(String sdCardRootPath) {
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) {
File sdCard = new File(sdCardRootPath);
StorageManager storageManager = (StorageManager) getSystemService(Context.STORAGE_SERVICE);
StorageVolume storageVolume = storageManager.getStorageVolume(sdCard);
Intent intent = storageVolume.createAccessIntent(null);
try {
startActivityForResult(intent, 4010);
} catch (ActivityNotFoundException e) {
Log.e("TUNE-IN ANDROID", "takeCardUriPermission: "+e);
}
}
}
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == 4010) {
Uri uri = data.getData();
grantUriPermission(getPackageName(), uri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION |
Intent.FLAG_GRANT_READ_URI_PERMISSION);
final int takeFlags = data.getFlags() & (Intent.FLAG_GRANT_WRITE_URI_PERMISSION |
Intent.FLAG_GRANT_READ_URI_PERMISSION);
getContentResolver().takePersistableUriPermission(uri, takeFlags);
methodChannel.invokeMethod("resolveWithSDCardUri",getUri().toString());
}
}
public Uri getUri() {
List<UriPermission> persistedUriPermissions = getContentResolver().getPersistedUriPermissions();
if (persistedUriPermissions.size() > 0) {
UriPermission uriPermission = persistedUriPermissions.get(0);
return uriPermission.getUri();
}
return null;
}
因此,为了开始整个权限获取过程,您必须先调用 takeCardUriPermission
并传递 sdCard 路径的 URI。
注意:在我的 FlutterActivity 上,我可以直接使用 getExternalCacheDirs()[1].toString()
获取 sdCardPath
调用 takeCardUriPermission
后,一旦按下允许按钮(或拒绝),将调用 activity 结果事件并调用 onActivtyResult 方法。 requestCode
检查在您有多个事件并且需要过滤掉这个事件时很有用。
activity 结果代码将授予应用程序修改 sdCard 上文件的权限。
getUri
方法是我们稍后尝试将字节保存到文件时使用的方法,它 returns 我们选择的 SDCard 的 URI(您可以有多个 sdCard ).
保存文件
我用的保存文件的方法很直接。首先我们需要获取 sdCard 的 URI 并从中创建一个 Documentfile
,然后我们遍历该目录的层次结构(DocumentFile
可以引用文件和目录)以根据需要找到所需的文件这是 URI。
我们通过将文件 URI 分成多个部分来执行此搜索,然后通过测试每个部分是否存在来导航层次结构。一旦我们测试了所有部分,我们就会到达我们的文件,如果它存在,或者我们被困在我们到达的最后一个目录。
这次迭代的结果是 DocumentFile
我们可以对其执行操作。
以下是完整的文件保存代码:
String filepath = (String) arguments.get("filepath");
final byte[] bytes = methodCall.argument("bytes");
try{
if(filepath==null || bytes==null)throw new Exception("Arguments Not found");
DocumentFile documentFile = DocumentFile.fromTreeUri(getApplicationContext(), getUri());
String[] parts = filepath.split("/");
for (int i = 0; i < parts.length; i++) {
DocumentFile nextfile = documentFile.findFile(parts[i]);
if(nextfile!=null){
documentFile=nextfile;
}
}
if(documentFile!=null && documentFile.isFile()){
OutputStream out = getContentResolver().openOutputStream(documentFile.getUri());
out.write(bytes);
out.close();
}else{
throw new Exception("File Not Found");
}
}catch (Exception e){
result.error("400",e.getMessage(),e);
return;
}
result.success(true);
注意:在我的代码中,我在 MethodChannel
的 MethodCallHandler
下调用它,这将给我我需要的参数:filePath
这是我要写入的文件的字符串 URI 和代表我要保存的数据的 bytes
字节数组。对于 result.success
也可以这样说
文件写入代码很简单:打开文件,写入数据,关闭文件。
我正在尝试写入位于 SDCard 中的文件,我发现我需要对可移动存储的特殊权限,这在任何已知的 flutter 权限处理程序插件中都找不到(我试过 simple_permission 和 permission_handler 没用)。
我尝试使用事物的 android 方面获取这些权限,因此我编写了一个简单的函数来显示对话框,用户将允许该应用修改 SDCard 的内容。
即使在获得 SD 卡的权限后,我在尝试使用 File.writeAsStringSync 方法将文件保存到 SDCard 时仍然遇到相同的权限被拒绝的错误。
想知道有没有什么已知的way/hack/workaround可以在flutter中保存文件到SD卡
我使用的 android 代码与此答案相同:
注意: 我的目标是 android 7 及以后,但不是 android 11.
我通过放弃保存 dart 文件并使用 android SAF 解决了这个问题。 首先,我所做的是尝试获取 sdCard 修改权限。 之后,我开始保存我需要的文件。
这是我用来获取权限的代码(又名“允许此应用修改您的 sdCard 上的内容”对话框)
public void takeCardUriPermission(String sdCardRootPath) {
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) {
File sdCard = new File(sdCardRootPath);
StorageManager storageManager = (StorageManager) getSystemService(Context.STORAGE_SERVICE);
StorageVolume storageVolume = storageManager.getStorageVolume(sdCard);
Intent intent = storageVolume.createAccessIntent(null);
try {
startActivityForResult(intent, 4010);
} catch (ActivityNotFoundException e) {
Log.e("TUNE-IN ANDROID", "takeCardUriPermission: "+e);
}
}
}
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == 4010) {
Uri uri = data.getData();
grantUriPermission(getPackageName(), uri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION |
Intent.FLAG_GRANT_READ_URI_PERMISSION);
final int takeFlags = data.getFlags() & (Intent.FLAG_GRANT_WRITE_URI_PERMISSION |
Intent.FLAG_GRANT_READ_URI_PERMISSION);
getContentResolver().takePersistableUriPermission(uri, takeFlags);
methodChannel.invokeMethod("resolveWithSDCardUri",getUri().toString());
}
}
public Uri getUri() {
List<UriPermission> persistedUriPermissions = getContentResolver().getPersistedUriPermissions();
if (persistedUriPermissions.size() > 0) {
UriPermission uriPermission = persistedUriPermissions.get(0);
return uriPermission.getUri();
}
return null;
}
因此,为了开始整个权限获取过程,您必须先调用 takeCardUriPermission
并传递 sdCard 路径的 URI。
注意:在我的 FlutterActivity 上,我可以直接使用 getExternalCacheDirs()[1].toString()
调用 takeCardUriPermission
后,一旦按下允许按钮(或拒绝),将调用 activity 结果事件并调用 onActivtyResult 方法。 requestCode
检查在您有多个事件并且需要过滤掉这个事件时很有用。
activity 结果代码将授予应用程序修改 sdCard 上文件的权限。
getUri
方法是我们稍后尝试将字节保存到文件时使用的方法,它 returns 我们选择的 SDCard 的 URI(您可以有多个 sdCard ).
保存文件
我用的保存文件的方法很直接。首先我们需要获取 sdCard 的 URI 并从中创建一个 Documentfile
,然后我们遍历该目录的层次结构(DocumentFile
可以引用文件和目录)以根据需要找到所需的文件这是 URI。
我们通过将文件 URI 分成多个部分来执行此搜索,然后通过测试每个部分是否存在来导航层次结构。一旦我们测试了所有部分,我们就会到达我们的文件,如果它存在,或者我们被困在我们到达的最后一个目录。
这次迭代的结果是 DocumentFile
我们可以对其执行操作。
以下是完整的文件保存代码:
String filepath = (String) arguments.get("filepath");
final byte[] bytes = methodCall.argument("bytes");
try{
if(filepath==null || bytes==null)throw new Exception("Arguments Not found");
DocumentFile documentFile = DocumentFile.fromTreeUri(getApplicationContext(), getUri());
String[] parts = filepath.split("/");
for (int i = 0; i < parts.length; i++) {
DocumentFile nextfile = documentFile.findFile(parts[i]);
if(nextfile!=null){
documentFile=nextfile;
}
}
if(documentFile!=null && documentFile.isFile()){
OutputStream out = getContentResolver().openOutputStream(documentFile.getUri());
out.write(bytes);
out.close();
}else{
throw new Exception("File Not Found");
}
}catch (Exception e){
result.error("400",e.getMessage(),e);
return;
}
result.success(true);
注意:在我的代码中,我在 MethodChannel
的 MethodCallHandler
下调用它,这将给我我需要的参数:filePath
这是我要写入的文件的字符串 URI 和代表我要保存的数据的 bytes
字节数组。对于 result.success
文件写入代码很简单:打开文件,写入数据,关闭文件。