我将文件添加到 Documents/MyExcelsFolder
通过使用 ContentResolver.insert
然后还将新文件添加到 Documents/MyExcelsFolder
另一个应用程序的文件夹(例如 FileManager )
然后我尝试从 MyExcelsFolder
获取所有文件文件夹
fun getAppFiles(context: Context): List<AppFile> {
val appFiles = mutableListOf<AppFile>()
val contentResolver = context.contentResolver
val columns = mutableListOf(
MediaStore.Images.Media._ID,
MediaStore.Images.Media.DATA,
MediaStore.Images.Media.DATE_ADDED,
MediaStore.Images.Media.DISPLAY_NAME,
MediaStore.Images.Media.MIME_TYPE
).apply {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
add(
MediaStore.MediaColumns.RELATIVE_PATH
)
}
}.toTypedArray()
val extensions = listOf("xls", "xlsx")
val mimes = extensions.map { MimeTypeMap.getSingleton().getMimeTypeFromExtension(it) }
val selection = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
"${MediaStore.MediaColumns.RELATIVE_PATH} LIKE ?"
} else {
"${MediaStore.Images.Media.DATA} LIKE ?"
}
val selectionArgs = arrayOf(
"%${Environment.DIRECTORY_DOCUMENTS}/MyExcelsFolder%"
)
contentResolver.query(
MediaStore.Files.getContentUri("external"),
columns,
selection,
selectionArgs,
MediaStore.Files.FileColumns.DATE_ADDED + " DESC"
)?.use { cursor ->
while (cursor.moveToNext()) {
val pathColumnIndex = cursor.getColumnIndex(MediaStore.Images.Media.DATA)
val mimeColumnIndex = cursor.getColumnIndex(MediaStore.Images.Media.MIME_TYPE)
val filePath = cursor.getString(pathColumnIndex)
val mimeType = cursor.getString(mimeColumnIndex)
if (mimeType != null && mimes.contains(mimeType)) {
// handle cursor
appFiles.add(cursor.toAppFile())
} else {
// need to check extension, because the Mime Type is null
val extension = File(filePath).extension
if (extensions.contains(extension)) {
// handle cursor
appFiles.add(cursor.toAppFile())
}
}
}
}
return appFiles
}
fun Cursor.toAppFile(): AppFile {
val cursor = this
val idColumnIndex = cursor.getColumnIndex(MediaStore.Images.ImageColumns._ID)
val nameColumnIndex = cursor.getColumnIndex(MediaStore.Images.Media.DISPLAY_NAME)
val mimeColumnIndex = cursor.getColumnIndex(MediaStore.Images.Media.MIME_TYPE)
val pathColumnIndex = cursor.getColumnIndex(MediaStore.Images.Media.DATA)
val id = cursor.getLong(idColumnIndex)
val uri = ContentUris.withAppendedId(MediaStore.Files.getContentUri("external"), id)
val fileDisplayName = cursor.getString(nameColumnIndex)
val filePath = cursor.getString(pathColumnIndex)
var mimeType = cursor.getString(mimeColumnIndex)
val relativePath = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
cursor.getString(cursor.getColumnIndex(MediaStore.MediaColumns.RELATIVE_PATH))
} else {
null
}
var type = MimeTypeMap.getSingleton().getExtensionFromMimeType(mimeType)
if (type == null) {
type = File(filePath).extension
mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(type)
}
return AppFile(
id = id,
uri = uri,
absolutePath = filePath,
name = fileDisplayName,
mimeType = mimeType,
extension = type,
relativePath = relativePath
)
}
结果只有 ContentResolver
中的文件添加者 insert
命令,并且文件管理器没有复制任何文件。如何查看 cursor
中的所有文件?操作系统:Android 10 (Q) (API level 29)
目标 API 版本:api 29
最佳答案
从 Android 10 开始,有一个新的存储访问模型正在运行,称为 Scoped Storage而且限制性更强。简而言之:
ContentResolver.insert
的帮助下)到 the shared media收藏和只能读取您的应用程序创建的文件 从他们。您可以通过请求 READ_EXTERNAL_STORAGE
访问这些集合中的其他应用程序文件。允许。 这有点奇怪,看起来像一个你可以访问的错误
xls
文件通过 MediaStore.Files
收藏。 The documentation说The media store also includes a collection called
MediaStore.Files
. Its contents depend on whether your app uses scoped storage, available on apps that target Android 10 or higher:If scoped storage is enabled, the collection shows only the photos, videos, and audio files that your app has created.
If scoped storage is unavailable or not being used, the collection shows all types of media files.
但无论如何,您仍然无法访问上述其他应用程序创建的文件。
因此,根据您的用例,有几个选项可供选择:
MediaStore.Files
访问文件现在为你工作,你可以尝试请求READ_EXTERNAL_STORAGE
权限如this table获得对媒体收藏的非过滤访问。但我希望这种方式在不同的设备上不可靠地工作和/或希望停止它与新的更新一起工作,因为媒体集合应该只用于媒体文件。 ACTION_OPEN_DOCUMENT
或 ACTION_OPEN_DOCUMENT_TREE
向用户显示文件/目录选择器并访问文件或整个目录树。请查看the restrictions此法之也。我会说这是最好的方法。 android:requestLegacyExternalStorage
从作用域存储旗帜。但是 Android 11 已经发布了,这个标志在其中没有任何作用。 MANAGE_EXTERNAL_STORAGE
许可,然后由用户向 access all files 请求特殊的白名单.这就是文件管理器现在的工作方式。此功能从 Android 11 开始可用,因此您可能会为 Android 10 使用选择退出标志。如果您要在那里发布您的应用,请务必检查使用此功能的限制和 Google Play 政策。 关于android - 为什么 ContentResolver 看不到其他应用添加的文件?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64276816/