Android 11-访问Android/data目录

Android 11-访问Android/data目录,android,Android,除了根目录之外,还有什么方法可以访问android 11上SD卡的android/data目录吗?我的(非游戏商店)应用程序需要访问另一个应用程序的公共Android/data/com.appname文件夹。我没有针对Android 11测试此应用程序,但它针对Android 10工作,在AndroidManifest.xml应用程序标记中使用Android:requestLegacyExternalStorage=“true”。如果适用于targetSdkVersion 30或更高版本,请发表

除了根目录之外,还有什么方法可以访问android 11上SD卡的android/data目录吗?我的(非游戏商店)应用程序需要访问另一个应用程序的公共Android/data/com.appname文件夹。

我没有针对Android 11测试此应用程序,但它针对Android 10工作,在AndroidManifest.xml应用程序标记中使用
Android:requestLegacyExternalStorage=“true”
。如果适用于targetSdkVersion 30或更高版本,请发表评论

代码是Xamarin,但Java/Kotlin将类似:

启动
ActionOpenDocumentTree
intent

var documentIntent=newintent(Intent.ActionOpenDocumentTree);
var externalStorageUrl=Environment.ExternalStorageDirectory.AbsolutePath;
documentIntent.PutExtra(“android.provider.extra.INITIAL_URI”,externalStorageUrl);
documentIntent.AddFlags(ActivityFlags.GrantReadUriPermission | ActivityFlags.GrantWriteUriPermission|
ActivityFlags.GrantPrefixUsermission|
ActivityFlags.GrantPersistablePermission);
activity.StartActivityForResult(documentIntent,(int)MainActivity.RequestCodes.FolderIntentRequestCode);
让用户选择内部存储器或SD卡上的
Android/
目录

当他们选择它时,您需要在您的活动中处理OnActivityResult中的持久化(我建议通过在Android/data/上执行目录列表并查找应用程序的com.publisher.appname来验证他们是否选择了正确的文件夹,或者只需检查选定的文件夹名为“Android”):

activityresult上的受保护重写异步void(int-requestCode、Result-resultCode、Intent-Intent)
{
base.OnActivityResult(请求代码、结果代码、意图);
if(resultCode==Result.Ok&&requestCode==(int)RequestCodes.FolderIntentRequestCode)
{
this.ContentResolver.TakePersistableUriPermission(uri、intent.Flags&(ActivityFlags.GrantReadUriPermission | ActivityFlags.GrantWriteUriPermission));
Preferences.Set(“StorageType”,(int)ContentType.StorageFramework);
Preferences.Set(“StorageLocation”,uri?.ToString());
}
}
既然您已经持久化了所选的Uri(
Android/
),您就可以通过storage access framework的ContentManager/DocumentsContract/etc API访问Android 11上的
Android/obb
Android/data
中的所有文件

存储访问框架很难使用。但是使用您持久化的uri,您可以使用此函数执行数据文件夹的基本目录列表(将持久化的uri作为uri传递,将“data/”作为路径传递):

公共列表GetFolderChildren(Uri,字符串路径) { 字符串[]投影={ DocumentsContract.Document.ColumnDocumentId, 文档contract.Document.ColumnLastModified }; var newPath=DocumentsContract.GetTreeDocumentId(uri)+$“/{path}”; var children=DocumentsContract.BuildChildDocumentsUriUsingTree(uri,newPath); List folderChildren=新列表(); 尝试 { var c=AppContentResolver.Query(子项、投影、null、null、null); if(c==null)return new List();//如果无法访问文件夹,则返回空 while(c.MoveToNext())//如果您失去访问权限(即重新安装的应用程序),这可能会引发异常 { var fPath=c.GetString(0); var lastModified=c.GetString(1); 添加(新的folderChildren() { 路径=fPath, LastModified=long.Parse(LastModified) }); } } 捕获(例外情况除外) { Log.Warn(“GetFolderChildren:{ex}上的应用程序“,$”异常); 返回新列表(); } 返回folderChildren; } 此函数仅返回目录/文件名和上次修改时间,您必须向
投影添加更多参数
有关详细信息,这有点像文件夹上的SELECT SQL查询

AppContentResolver.OpenAssetFileDescriptor
是您读取和写入现有文件的朋友,要创建或删除新文件/文件夹,您需要使用
DocumentFile.FromTreeUri
创建一个新的DocumentFile,使用从
documentscocontract.BuildDocumentUriUsingTree
生成的树uri。我强烈建议您阅读Android API文档,因为其中有很多内容需要阅读。可能是您的目标语言已经有了一些库来处理所有这些低级文件访问活动


有关如何使用storage access framework读取/写入/删除文件的更多示例,请参阅。

请阅读以下内容:Android 11(也可能是以前的版本)不允许在“Android/data”上显示意图(Intent.ACTION\u OPEN\u DOCUMENT\u TREE)。请参阅(请参阅本节底部),我也测试了它,但它不起作用。您必须打开根目录(或Android/或任何地方)的意图,并指示用户导航到Android/。他们可以访问整个Android/系统,其中包括Android/数据。在许多11台设备上,对我和成千上万的用户都很好。