DocumentProvider — 是一个抽象的 Android 类,实现了通过 Storage Access Framework 访问文件的内容提供程序。提供程序在 AndroidManifest.xml 中注册,并通过系统选择器向其他应用程序提供文件。根据 Android Developers (2026),DocumentsProvider 需要实现 queryRoots、queryDocument 和 queryChildDocuments 方法,以在文件选择对话框中显示文件结构。
要点
DocumentsProvider — 是一个基本的 Android 类,继承自 ContentProvider,允许应用程序通过 SAF 系统界面将其文件提供给其他应用程序。提供程序创建了一个虚拟文件系统,用户可以在文档选择对话框中看到它。
每个提供程序将文件组织到 根 (roots) — 顶级入口点。例如,Google Drive 有根 “我的磁盘” 和 “与我共享”。在根内部,提供程序返回一个文档树,其中每个文档都是具有特定 MIME 类型、大小和日期的文件或目录。
DocumentProvider 是 android.provider 包的一部分,自 Android 4.4 (API 19) 起可用。提供程序被云服务、密码管理器、笔记应用程序以及所有以自有格式存储文件的程序使用。
创建 您自己的 DocumentProvider 始于继承 DocumentsProvider 类并实现四个必需方法。提供程序定义了在选择文件时在 SAF 系统选择器中显示的文件结构。
第一个方法 — queryRoots,返回一个包含 Root.COLUMN_ROOT_ID、Root.COLUMN_TITLE、Root.COLUMN_SUMMARY 和 Root.COLUMN_FLAGS 列的光标。每个根可以支持标志:FLAG_SUPPORTS_CREATE、FLAG_SUPPORTS_SEARCH 和 FLAG_SUPPORTS_IS_CHILD。
第二个必需方法 — queryChildDocuments,返回指定 URI 的子文档。当用户在选择器中打开目录时,将调用此方法。每个文档包含列:Document.COLUMN_DOCUMENT_ID、COLUMN_DISPLAY_NAME、COLUMN_MIME_TYPE、COLUMN_SIZE 和 COLUMN_LAST_MODIFIED。
DocumentsProvider 需要实现四个方法,这些方法形成了选择器的文件结构。没有它们,提供程序将无法工作 — SAF 系统对话框将无法显示文件。
此外,还可以实现 createDocument 以创建新文件、deleteDocument 以删除和 renameDocument 以重命名。这些方法需要在根中使用 FLAG_SUPPORTS_CREATE 标志。
DocumentProvider 在 AndroidManifest.xml 中注册为普通的 ContentProvider,带有额外的 intent-filter 和标志。提供程序必须通过 permission 保护免受直接访问 — 建议使用 android:exported="true" 并带有显式 permission。
<provider
android:name=".provider.CustomDocumentProvider"
android:authorities="com.example.app.documents"
android:exported="true"
android:grantUriPermissions="true"
android:permission="android.permission.MANAGE_DOCUMENTS">
<intent-filter>
<action
android:name="android.content.action.DOCUMENTS_PROVIDER" />
</intent-filter>
<meta-data
android:name="android.content.documents.roots"
android:resource="@xml/file_paths" />
</provider>
grantUriPermissions 标志允许 SAF 临时将访问权限委托给调用应用程序。authorities 属性必须是唯一的 — 通常使用带有 .documents 后缀的包名。还建议指定带有 XML 资源的 meta-data 以配置根。
实现 DocumentsProvider 需要从 openDocument 方法返回 ParcelFileDescriptor。对于本地文件,使用 ParcelFileDescriptor.open;对于云文件 — 使用带有 Pipe 的 ParcelFileDescriptor.open 进行流式传输。代码必须处理访问错误和文件不存在的情况。
class CustomDocumentProvider : DocumentsProvider() {
override fun queryRoots(): Cursor {
val matrix = MatrixCursor(Root.COLUMNS)
matrix.newRow().add(Root.COLUMN_ROOT_ID, "local")
.add(Root.COLUMN_TITLE, "My Files")
.add(Root.COLUMN_SUMMARY, "Local documents")
.add(Root.COLUMN_FLAGS, Root.FLAG_SUPPORTS_CREATE)
return matrix
}
override fun openDocument(
documentId: String, flags: Int, cursor: CancellationSignal?
): ParcelFileDescriptor {
val file = File(context.filesDir, documentId)
val accessMode = ParcelFileDescriptor.parseMode(flags)
return ParcelFileDescriptor.open(file, accessMode)
}
}
DocumentProvider 可以返回 虚拟文件 — 在磁盘上不作为单独文件存在的文档。例如,数据库中的笔记可以表示为虚拟 PDF。为此,使用带有 FLAG_VIRTUAL_DOCUMENT 标志的 MIME 类型,openDocument 在发送前将数据转换为请求的格式。
iOS 有类似的机制 — UIDocumentPickerViewController,它也提供统一的文件选择界面。然而,在 iOS 中,文档提供程序通过 UIDocumentPickerDelegate 和 Document Provider 类型的应用程序扩展 (App Extensions) 来实现。
与 Android DocumentsProvider 不同,iOS UIDocumentPickerViewController 不需要为本地文件创建自定义提供程序 — 系统选择器默认支持 iCloud Drive 和本地存储。第三方云服务通过 Document Provider extension 注册,使用 Info.plist 键 NSExtensionFileProviderDocumentInterface。
主要区别:在 Android 中,DocumentProvider 通过 SAF Intent 被主动调用,必须自己实现导航。在 iOS 中,UIDocumentPickerViewController 使用内置的系统文件浏览器,提供程序扩展仅负责按需提供内容。
常见问题
DocumentsProvider — 是一个抽象的 Android 类,用于创建自定义文档提供程序。它允许应用程序通过 Storage Access Framework 系统对话框将其文件提供给其他应用程序。
四个方法是必需的:queryRoots(存储根)、queryDocument(一个文档)、queryChildDocuments(文件夹内容)和 openDocument(打开文件)。没有它们,提供程序将无法工作。
提供程序注册为 <provider>,带有类名、唯一的 authorities、带有 android.content.action.DOCUMENTS_PROVIDER 操作的 intent-filter 和 grantUriPermissions="true"。
FileProvider 为您的应用程序的特定文件生成内容 URI。DocumentsProvider 创建一个完整的文件系统,在 SAF 选择器中可见,支持导航和搜索。
在 COLUMN_FLAGS 列中使用 FLAG_VIRTUAL_DOCUMENT 标志,以及带有前缀 “vnd.android.document/” 的 MIME 类型。在 openDocument 中,通过带有 Pipe 的 ParcelFileDescriptor 将数据转换为请求的格式。
总结
我们将开发一款交钥匙移动应用程序
IT Sectr自2017年以来为初创企业和企业打造iOS和Android应用程序。我们将为您提供咨询并提出最佳解决方案。