【问题标题】:How to get dir file list in Android 11如何在 Android 11 中获取 dir 文件列表
【发布时间】:2020-12-28 02:25:15
【问题描述】:

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

文件 API 现在不适用于外部存储。

该版本还改进了范围存储,使开发人员更容易迁移到使用此存储模型。

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

【问题讨论】:

  • File api(无论您认为是什么)在 Android 11 下的外部存储上都非常有效。只读。所以获取 dir 文件列表和往常一样。看来你甚至没有尝试过。
  • 自 2012 年以来,我编写了许多应用程序。我可以正确使用文件 api。但是当我使用 android 11 时,我无法从外部存储中获取列表文件。授予所有权限。
  • 是的,你可以!显示您的代码。
  • 我最近用 Java 编写了一个开源的 Android 文件选择器库,旨在与 Android API 29+ 兼容。你可以在这里查看:github.com/maxieds/AndroidFilePickerLight

标签: android


【解决方案1】:

在将 targetSdkVersion 更改为 30 之前,我曾经使用 3rd 方库来挑选图像/视频。 我认为 Github 上可能还有其他库在针对 API 30 时仍然可以使用,但没有找到。 所以我决定建一个。 项目回购:https://github.com/ming-xi/MXMediaPicker 随意fork~如果觉得有用的话点个star让更多人看到,谢谢~

【讨论】:

  • @Abdul 没有。它只是一个媒体选择器,支持选择图像和视频。
【解决方案2】:

我最近用 Java 编写了一个针对 API 29+ 的 Android 文件/文件夹选择器库(例如,Android OS 10/11 更改)。它被称为Android File Picker Light。这个想法是有一个准系统文件/目录选择器,它显示有关本地文件系统的简约信息,而不需要过多的多媒体处理来执行视觉显示媒体文件和图像缩略图之类的事情。在最初的发帖者关于如何通过传统的 Unix-V 样式路径枚举本地磁盘(或 SD 卡)上的文件时,我得到的一些代码是 seen here (for example, and elsewhere there)。它在截至 2020 年 12 月有效的 Android OS 10 (API 29) 上仍然运行良好。

上面提供的链接应该可以帮助您入门。我的库项目的源代码在 GPL 下免费提供。还有一些 Google 认可的官方源代码记录了自定义文件存储提供程序 on their GitHub repos 的实现。要记住的一件事是,Android API 正在有效地尝试将接口泛化为“文件内容”,以便我们拥有用于在线索引(如 DropBox 链接)和本地文件系统的通用机制。这是出于好意,直到人们看到从本地磁盘或集成 SD 卡执行简单的常规文件系统操作变得多么复杂。最终,我们这些狂热的开发人员可能不得不集体向 Android 官方文档编写者请愿,以寻求更好的指导来处理这些以前常见的文件系统访问案例:)。

考虑到这一点,我想针对其他人在编写自己的自定义代码时可能遇到的新范围存储更改的几个区别问题进行迭代。我希望这可以为开发人员节省一些未来的绊脚石,这些问题(对我来说)似乎是常见的问题,但在 Android 开发人员文档中关于范围存储的一些未充分记录的部分中没有得到充分解决。随着 Android 11 开始在野外占用更多实时设备,我遇到的这些问题可能会被整合到办公文档中。目前,我建议以下几个参考点:

  • 现在使用更标准的(甚至是可移植的)Java I/O 或 NIO 调用从新限制的 Android API 更改中获取文件系统数据(如 POSIX 样式权限)变得很棘手。根据我能够从我的 Android 10 OS 开发设备中获得的信息,当您尝试通过创建 DocumentsProvider 的子类来访问 MatrixCursor 类型的列数据时,系统似乎提供了特殊权限。这就是说新的更改将返回合法的 System-V-Unix 风格的传统路径(如/storage/0/self/primary/Pictures/Screenshots),但似乎不喜欢将它们作为一种在特殊之外明确引用这些文件的方式文件提供者继承方案(叹气)。我发现从硬编码路径枚举的有效 Java File 实例中提取 POSIX 样式权限的唯一方法是在我的库代码 seen inline here 中引用。您的里程可能会有所不同。
  • 每当 Android 11 在设备上变得普遍使用时,就会向范围存储迁移,这将对按路径选择文件引入一些额外的限制。特别是,我必须在我的库中创建的 DocumentsProvider 子类能够将句柄返回到 Java 文件的 Unix 类型路径(对于本地文件系统情况),或者返回到 Uri 对象的抽象文件类型引用不符合本规范。一般来说,随着新的 API 要求向前发展,子类 DocumentsProvider 负责为实际文件数据提供服务(通常作为 StringByte[] 数组),目前同时用户可以枚举这些文件以通过它们熟悉的路径名进行选择。不用说,对于希望用户在文件内容被程序读取以进行处理之前很长一段时间按文件名选择文件的开发人员来说,这会使使用模式变得复杂。
  • 有一些旧式AndroidManifest.xml 选项可用于当前的 Android 10 设备,以绕过范围存储要求。在我的编译链接listed here (library Markdown reference) 中阅读它们。这些遗留行为促成因素包括 android:requestLegacyExternalStorageandroid:preserveLegacyExternalStorage application 标签选项。请注意,对于 11 之前操作系统设备的这种类型的兼容性有一个奇怪的违反直觉的缺点,即需要在本地应用程序 build.gradle 文件(使用 Android Studio)中进行新的 MinSdkVersion 设置。
  • 在如何(使用哪个)引用硬编码的文件系统路径引用方面,有一些有趣的行为,同样在文档中。在我的图书馆(例如)中,this syntax is used。总的来说,我的直觉是,新的 Android 11 范围存储更改使历史访问模式变得复杂,并且明显过时了。我的意思是appCtx.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS) 可能会返回NULL Java File 处理程序,但是如果我们正确配置XML 文件路径名以与AndroidManifest 一起使用,像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>

对于我刚才的冗长评论,我深表歉意。我希望这可以为人们节省一些时间。 -- 中号

【讨论】:

    【解决方案3】:

    如果您正在寻找文件选择器体验,Storage Access Framework 是您现在唯一的选择。下面的代码让你拿起多个文件。如果要选择目录级别,可以使用ACTION_OPEN_DOCUMENT_TREEintent。

    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 管理中心申请特殊的 all files accessMediaStore.Files。更多关于Android 11 storage changes

    编辑:

    如果您想在 Android 29+ 中实现类似体验的文件浏览器,这里有一个我个人没有尝试过但应该可行的建议想法。这不是最佳体验,但与文件浏览器非常相似。

    1. 如果 API =requestLegacyExternalStorage="true")。
    2. 如果 API > 29,请从 Google Play 控制台请求 all files access
      • MANAGE_EXTERNAL_STORAGE 标志放入清单中
      • 使用ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION 意图打开设置,提示用户允许所有文件访问。
      • MediaStore.FilesRELATIVE_PATH 查询所有文件
      • 相对路径 + 显示名称将为您提供类似 DCIM/Vacation/IMG_1234.jpg 的信息。
      • 从所有相对路径中创建一棵树(更像是一片森林)并在 UI 中显示。

    【讨论】:

    • 我想编写自己的文件浏览器。我不想使用 ACTION_OPEN_DOCUMENT
    • 添加了我的一个想法,乏味但可能类似于文件浏览器之类的体验。
    • requestLegacyExternalStorage="true" 在 android 11 中不起作用。
    • ask for all files access from Google Play Console 你不必问谷歌。您可以为您的应用程序进行编程。当您拥有所有文件访问权限时,您可以照常使用旧的 File api。
    • `requestLegacyExternalStorage="true" 在 android 11 中不起作用.. 正确。仅适用于 Android 10 设备。
    【解决方案4】:

    在 Android 10 及更高版本上,该 API 发生了很大变化, 你可以看到official documentation或者关注这个post

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-11-15
      • 1970-01-01
      • 1970-01-01
      • 2019-11-08
      • 1970-01-01
      • 2023-03-08
      • 1970-01-01
      • 2021-07-15
      相关资源
      最近更新 更多