如何在Android 11中获取文件夹列表

7

我想编写自己的简易文件浏览器。

现在,File API不能用于外部存储。

此版本还提供了对作用域存储的改进,使开发人员更容易迁移到使用这种存储模型。

我不明白如何使用作用域存储来访问/sdcard。


文件 API(无论您认为它是什么)在 Android 11 的外部存储中非常有效。只读。因此,获取目录文件列表与以往相同。看起来您甚至没有尝试过。 - blackapps
我自2012年以来编写了许多应用程序。我可以正确地使用文件API。但是当我使用Android 11时,我无法从外部存储获取文件列表。所有权限都已授予。 - Алексей Мальченко
当然可以!展示你的代码。 - blackapps
我最近用Java编写了一个开源的Android文件选择器库,旨在与Android API 29+兼容。您可以在此处查看它:https://github.com/maxieds/AndroidFilePickerLight - mds
4个回答

8

如果您正在寻找文件选择体验,Storage Access Framework现在是您唯一的选择。下面的代码让您选择多个文件。如果您想进行目录级别的选择,则可以使用ACTION_OPEN_DOCUMENT_TREE意图。

private fun openStorageAccess() {
    val intent = Intent(Intent.ACTION_OPEN_DOCUMENT).apply {
        type = "*/*"  
        addCategory(Intent.CATEGORY_OPENABLE)
        putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true)
    }
    startActivityForResult(intent, openDirectoryAccessCode)
}

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    super.onActivityResult(requestCode, resultCode, data)
    if (requestCode == openDirectoryAccessCode && resultCode == Activity.RESULT_OK) {
        val fileUris = data?.clipData ?: data?.data
    }
}

此外,您可以通过Google Play控制台向MediaStore.Files请求特殊的所有文件访问权限。有关Android 11存储更改的更多信息。
编辑:
如果您想在Android 29+中实现类似文件浏览器的体验,这里是一个我个人还没有尝试过但应该可行的提议。虽然不是最佳体验,但会非常接近文件浏览器。
  1. 如果API ==< 29,请使用常规的File API(如果API == 29,请使用requestLegacyExternalStorage =“true”)。
  2. 如果API > 29,请从Google Play控制台请求所有文件访问权限
    • 在清单中放置MANAGE_EXTERNAL_STORAGE标志
    • 通过使用ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION意图打开设置来提示用户允许所有文件访问。
    • MediaStore.Files查询所有文件以及RELATIVE_PATH
    • 相对路径+显示名称将为您提供类似DCIM/Vacation/IMG_1234.jpg的内容。
    • 创建一个由所有相对路径构成的树形结构,并在UI中显示它。

1
我想编写自己的文件浏览器。我不想使用ACTION_OPEN_DOCUMENT。 - Алексей Мальченко
我想到了一个想法,虽然有点繁琐,但可能会像文件浏览器一样的体验。 - Siddharth Kamaria
在Android 11中,requestLegacyExternalStorage="true"无法正常工作。 - Алексей Мальченко
3
请求从Google Play控制台获取所有文件的访问权限。你不必向谷歌公司请求,你可以为你的应用程序编写程序。当你获得了所有文件访问权限后,就可以像往常一样使用旧的文件API。 - blackapps
为了限制对共享存储的广泛访问,Google Play商店已更新其政策,以评估针对Android 11(API级别30)或更高版本并通过MANAGE_EXTERNAL_STORAGE权限请求所有文件访问权限的应用程序。@blackapps - Siddharth Kamaria
显示剩余2条评论

1
我最近用Java编写了一个Android文件/文件夹选择器库,目标API 29+(例如,Android OS 10/11更改)。它被称为Android File Picker Light。其想法是拥有一个简约的文件/目录选择器,显示关于本地文件系统的最少信息,而不会引入过多的多媒体处理来执行诸如可视化显示媒体文件和图像缩略图之类的操作。一些我用来回答最初发帖者问题的代码,即如何通过传统的Unix-V样式路径枚举本地磁盘(或SD卡)上的文件,可以在这里(例如,在其他地方)找到。截至2020年12月,它仍然在Android OS 10(API 29)上正常工作。
以上提供的链接可以帮助您入门。我的库项目源代码在GPL下免费提供。还有一些谷歌官方源代码,用于记录自定义文件存储提供程序的实现在他们的GitHub repos上。需要记住的一件事是,Android API有效地尝试将“文件内容”接口通用化,以便我们拥有一个在线索引的共同机制(如DropBox链接)和本地文件系统。这是很好的意图,直到人们看到从本地磁盘或集成SD卡执行简单的例行文件系统操作变得更加复杂。最终,我们热衷的开发者可能不得不联合请愿Android官方文档编写者提供更好的指针来处理这些以前常见的文件系统访问案例:)。

考虑到这一点,我想重申几个与新的作用域存储更改有关的区别问题,其他人在编写自己的自定义代码时可能会遇到。我希望这能为开发人员节省一些未来因某些在Android开发者文档的某些不充分记录部分中似乎是常见问题(对我而言)而导致的障碍。随着Android 11开始在野外设备上占据更多的生活,我的这些问题可能会被整合到官方文档中。目前,我建议参考以下几个参考点:

现在,使用更标准(甚至是可移植的)Java I/O或NIO调用获取文件系统数据(如POSIX样式权限)变得棘手,因为Android API的新限制。根据我从Android 10 OS开发设备中获取的信息,当您尝试通过创建DocumentsProvider的子类来访问MatrixCursor类型列数据时,系统会授予特殊权限。这就是说,新的更改将返回真正的System-V-Unix样式传统路径(例如/storage/0/self/primary/Pictures/Screenshots),但似乎不喜欢以此方式明确引用这些文件以外的特殊文件提供程序继承方案(叹息)。我找到的唯一从硬编码路径枚举的有效Java File实例中提取POSIX样式权限的方法在我的库代码中有所提及见此处的内联链接。你的体验可能会有所不同。
当Android 11成为设备上普遍存在时,转向作用域存储将对按路径选择文件引入一些额外的限制。特别地,我必须在我的库中创建的DocumentsProvider子类能够返回Java文件(对于本地文件系统情况)的Unix类型路径的句柄,否则返回不符合此规范的抽象文件类型引用的Uri对象。一般来说,随着新的API要求向前迈进,子类化的DocumentsProvider负责为实际文件数据提供服务(通常作为StringByte[]数组),并且当前用户可以通过熟悉的路径名称枚举这些文件以进行选择。不用说,对于希望在程序读取文件内容之前让用户按名称选择文件的开发人员来说,这会使使用模式变得复杂。
有一些遗留的AndroidManifest.xml选项可用于绕过当前Android 10设备上的作用域存储要求。请在我的编译链接中阅读列出的(库Markdown参考)。这些遗留行为启用器包括android:requestLegacyExternalStorageandroid:preserveLegacyExternalStorageapplication标签选项。请注意,这种类型的兼容性适用于11版操作系统之前的设备,具有奇怪的反直觉缺点,需要在本地应用程序build.gradle文件中设置新的MinSdkVersion
关于如何(哪个)引用硬编码文件系统路径引用,存在一些有趣的、再次未记录的行为。在我的库中(例如),使用这个语法。总的来说,我的直觉是,新的Android 11作用域存储更改使历史访问模式变得复杂,显然过时到被弃用的程度。我的意思是,appCtx.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS)可能会返回一个空的Java File处理程序,但如果我们正确配置用于与AndroidManifest文件一起使用的XML文件路径名称,则硬编码路径(例如new File("/storage/self/primary/Documents"))仍然可以正常工作。
 <provider
            android:name="com.maxieds.androidfilepickerlightlibrary.BasicFileProvider"
            android:authorities="com.maxieds.androidfilepickerlightlibrary.FileChooserActivity"
            android:exported="true"
            android:enabled="true"
            android:grantUriPermissions="true"
            android:permission="android.permission.MANAGE_DOCUMENTS"
            android:initOrder="100"
            >

            <intent-filter>
                <action android:name="android.content.action.DOCUMENTS_PROVIDER" />
            </intent-filter>

            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/file_provider_paths_base" />

        </provider>

对我刚才冗长的评论感到抱歉。希望这能为将来节省一些人的时间。-- M


0
我曾经使用第三方库在将targetSdkVersion更改为30之前选择图像/视频。 我认为在针对API 30时可能还有其他可以使用的Github库,但没有找到。 所以我决定自己构建一个。 项目仓库:https://github.com/ming-xi/MXMediaPicker 欢迎fork~如果您认为它有用,请给它点赞,让更多人看到,谢谢~


1
@Abdul 不是的。它只是一个支持选择图片和视频的媒体选择器。 - Michael Archangel

0

在 Android 10 及更高版本中,该 API 发生了很多变化, 您可以查看官方文档或关注此帖子


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接