我正在尝试写入SDCard中的文件,发现我需要可移动存储的特殊权限,这在任何已知的Flutter权限处理程序插件中都找不到(我尝试了simple_permission和Permissions_handler,没有使用)。
我试图使用Android的东西来获取那些权限,所以我写了一个简单的函数来显示对话框,并且用户允许应用程序修改SDCard的内容。
即使获得了SDCARD的权利,使用File.writeAsStringSync方法尝试将文件保存到SDCard时,仍然出现相同的拒绝权限错误。
我想知道是否有任何已知的方法/破解/解决方法来快速地将SDCard中的文件保存起来。
我使用的android代码与此答案相同:https://stackoverflow.com/a/55024683/6641693
注意::我的目标是android 7及更高版本,但不是android 11。
答案 0 :(得分:0)
我通过放弃保存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
后,一旦按下允许按钮(或拒绝按钮),就会调用活动结果事件,并调用onActivtyResult方法。当您有多个事件并且需要将其过滤掉时,requestCode
检查很有用。
活动结果代码将为应用授予修改sdCard上文件的权限。
getUri
方法是我们稍后尝试将字节保存到文件时使用的方法,它返回我们选择的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
的{{1}}下调用它,这将给我我需要的参数:MethodCallHandler
,它是字符串URI我要写入的文件和代表我要保存的数据的filePath
字节数组。 bytes
文件写入代码很简单:打开文件,写入数据并关闭文件。