Android 为什么ContentResolver看不到其他应用添加的文件?

Android 为什么ContentResolver看不到其他应用添加的文件?,android,file,uri,android-contentresolver,file-manager,Android,File,Uri,Android Contentresolver,File Manager,我使用ContentResolver.insert将文件添加到Documents/MyExcelsFolder,然后还通过另一个应用程序将新文件添加到Documents/MyExcelsFolder文件夹(例如FileManager) 然后我尝试从MyExcelsFolder文件夹中获取所有文件 fun getAppFiles(context: Context): List<AppFile> { val appFiles = mutableListOf<AppF

我使用
ContentResolver.insert将文件添加到
Documents/MyExcelsFolder
,然后还通过另一个应用程序将新文件添加到
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
    )
}
fun getAppFiles(context:context):列表{
val appFiles=mutableListOf()
val contentResolver=context.contentResolver
val columns=mutableListOf(
MediaStore.Images.Media.\u ID,
MediaStore.Images.Media.DATA,
MediaStore.Images.Media.DATE_已添加,
MediaStore.Images.Media.DISPLAY\u名称,
MediaStore.Images.Media.MIME_类型
).申请{
if(Build.VERSION.SDK\u INT>=Build.VERSION\u code.Q){
加(
MediaStore.MediaColumns.RELATIVE_路径
)
}
}.toTypedArray()
val扩展=列表(“xls”、“xlsx”)
val mimes=extensions.map{MimeTypeMap.getSingleton().getMimeTypeFromExtension(it)}
val selection=if(Build.VERSION.SDK\u INT>=Build.VERSION\u code.Q){
“${MediaStore.MediaColumns.RELATIVE_PATH}类似吗?”
}否则{
“${MediaStore.Images.Media.DATA}类似吗?”
}
val selectionArgs=arrayOf(
“%${Environment.DIRECTORY_DOCUMENTS}/MyExcelsFolder%”
)
contentResolver.query(
MediaStore.Files.getContentUri(“外部”),
柱,
选择,
精选,
MediaStore.Files.FileColumns.DATE_添加+“DESC”
)?使用{游标->
while(cursor.moveToNext()){
val pathColumnIndex=cursor.getColumnIndex(MediaStore.Images.Media.DATA)
val mimeColumnIndex=cursor.getColumnIndex(MediaStore.Images.Media.MIME_类型)
val filePath=cursor.getString(pathColumnIndex)
val mimeType=cursor.getString(mimeColumnIndex)
if(mimeType!=null&&mimes.contains(mimeType)){
//手柄光标
appFiles.add(cursor.toAppFile())
}否则{
//需要检查扩展名,因为Mime类型为空
val扩展名=文件(filePath).extension
if(extensions.contains(extension)){
//手柄光标
appFiles.add(cursor.toAppFile())
}
}
}
}
返回应用程序文件
}
fun Cursor.toAppFile():AppFile{
val cursor=这个
val idColumnIndex=cursor.getColumnIndex(MediaStore.Images.ImageColumns.\u ID)
val nameColumnIndex=cursor.getColumnIndex(MediaStore.Images.Media.DISPLAY_NAME)
val mimeColumnIndex=cursor.getColumnIndex(MediaStore.Images.Media.MIME_类型)
val pathColumnIndex=cursor.getColumnIndex(MediaStore.Images.Media.DATA)
val id=cursor.getLong(idColumnIndex)
val uri=ContentUris.withAppendedId(MediaStore.Files.getContentUri(“外部”),id)
val fileDisplayName=cursor.getString(nameColumnIndex)
val filePath=cursor.getString(pathColumnIndex)
var mimeType=cursor.getString(mimeColumnIndex)
val relativePath=if(Build.VERSION.SDK\u INT>=Build.VERSION\u code.Q){
cursor.getString(cursor.getColumnIndex(MediaStore.MediaColumns.RELATIVE_PATH))
}否则{
无效的
}
var type=MimeTypeMap.getSingleton().getExtensionFromMimeType(mimeType)
if(type==null){
类型=文件(filePath).extension
mimeType=MimeTypeMap.getSingleton().getMimeTypeFromExtension(类型)
}
返回应用文件(
id=id,
uri=uri,
绝对路径=文件路径,
name=fileDisplayName,
mimeType=mimeType,
扩展=类型,
相对路径=相对路径
)
}
结果,只有来自
ContentResolver
的文件是通过
insert
命令添加的,并且没有文件管理器复制的文件。如何在
光标中查看所有文件

操作系统:安卓10(Q)(API级别29)


目标API版本:API 29

从Android 10开始,有一个新的存储访问模型正在运行,它被调用,限制性更强。简言之:

  • 您的应用程序始终可以访问自己的目录
  • 您的应用程序可以(借助
    ContentResolver.insert
    )写入集合,并且可以从集合中读取应用程序创建的文件。通过请求
    READ\u EXTERNAL\u STORAGE
    权限,您可以访问这些集合中的其他应用程序文件
  • 您的应用程序可以使用访问其他文件和目录
  • 这有点奇怪,看起来像是一个bug,您可以通过
    MediaStore.files
    集合访问
    xls
    文件。说

    媒体存储还包括一个名为
    MediaStore.Files
    的集合。 其内容取决于您的应用程序是否使用范围存储(可用) 在针对Android 10或更高版本的应用程序上:

    如果启用了作用域存储,则集合仅显示照片, 应用程序创建的视频和音频文件

    If作用域存储 不可用或未使用,集合显示所有类型的 媒体文件

    但无论如何,您仍然无法访问由上述其他应用程序创建的文件。 因此,根据您的用例,有几个选项可供选择:

  • 由于通过
    MediaStore.files
    访问文件现在对您有效,您可以尝试请求
    READ\u EXTERNAL\u STORAGE
    权限,如中所示,以获得对媒体收藏的非筛选访问权限。但我希望这种方式在不同的设备上不可靠地工作,并且/或者在新的更新中停止工作,因为媒体收藏应该只用于媒体文件