正确查询 Android 11 上的 MediaStore 记录

Properly querying MediaStore records on Android 11

我正在努力为我的 audio/video 播放器应用程序提供 Android 11 支持。我主要关心的实际上是不要激怒 Google 部落,因为他们没有 All files access 允许播放器应用程序的权限。我不希望我的应用程序在 Google 商店上发布时被拒绝。

在以前的 API 中,我使用的是 WRITE_EXTERNAL_STORAGE 权限,包括 Android 10(我选择退出分区存储)。虽然,我不知道如何处理 Android 11 而不会让我的应用程序在 Google 商店上发布时被拒绝。我了解到查询 MediaStore 记录需要 READ_EXTERNAL_STORAGE 权限,我有以下问题:

  1. 在 Android 11 的运行时请求 READ_EXTERNAL_STORAGE 是否可以被 Google 接受(当我在他们的商店上发布我的应用程序时)?
  2. 我可以为所有 API 请求 WRITE_EXTERNAL_STORAGE 运行时权限而不是 READ_EXTERNAL_STORAGE 并且 Android 11 设备上的系统会用它代替 READ_EXTERNAL_STORAGE 还是我会需要在 Android 11 台设备上要求 READ_EXTERNAL_STORAGE 添加条件。
  3. 在 Android 11 的运行时要求 WRITE_EXTERNAL_STORAGE 是否可以被 Google 接受(当我在他们的商店上发布我的应用程序时)?

您可以使用所有这些权限而不受 Google 的任何禁止。你不能t/shouldn不能使用MANAGE_EXTERNAL_STORAGE,专用于分区存储和文件管理应用程序、杀毒软件和其他“特权”软件的新权限

  1. 这是获取所有视频列表的函数

    有趣的 getVideo():ArrayList {

         val   marrayList = ArrayList<Video>()
         val contentResolver =context?.contentResolver
         val uri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI
         val selection = "${MediaStore.Video.Media.DURATION} >= ?"
         val selectionArgs = arrayOf(
             TimeUnit.MILLISECONDS.convert(2, TimeUnit.SECONDS).toString()
         )
         val sortOrder = "${MediaStore.Video.Media.DISPLAY_NAME} ASC"
         val collection =
             if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
                 MediaStore.Video.Media.getContentUri(
                     MediaStore.VOLUME_EXTERNAL
                 )
             } else {
                 MediaStore.Video.Media.EXTERNAL_CONTENT_URI
             }
    
         val cursor = contentResolver?.query(collection, null, selection, selectionArgs, sortOrder)
         if (cursor != null && cursor.getCount() > 0 && cursor.moveToFirst()) {
    
             val idColumn = cursor.getColumnIndexOrThrow(MediaStore.Video.Media._ID)
             val nameColumn =
                 cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DISPLAY_NAME)
             val titleCol =cursor.getColumnIndexOrThrow(MediaStore.Video.Media.TITLE)
             val date=cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DATE_ADDED)
             val durationColumn =
                 cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DURATION)
             val sizeColumn = cursor.getColumnIndexOrThrow(MediaStore.Video.Media.SIZE)
    
             while (cursor.moveToNext()) {
    
                 val videoPath = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DATA))
                 val id = cursor.getLong(idColumn)
                 val title=cursor.getString(titleCol)
                 val name = cursor.getString(nameColumn)
                 val duration = cursor.getInt(durationColumn)
                 val mdate=cursor.getString(date)
                 val size = cursor.getString(sizeColumn)
                 val thumb =
                     ContentUris.withAppendedId(MediaStore.Video.Media.EXTERNAL_CONTENT_URI, id)
    
                 var duration_formatted: String
                 val sec: Int = duration / 1000 % 60
                 val min: Int = duration / (1000 * 60) % 60
                 val hrs: Int = duration / (1000 * 60 * 60)
    
                 duration_formatted = if (hrs == 0) {
                     min.toString() + ":" + String.format(Locale.UK, "%02d", sec)
                 } else {
                     hrs.toString() + ":" + String.format(
                         Locale.UK,
                         "%02d",
                         min
                     ) + ":" + String.format(
                         Locale.UK, "%02d", sec
                     )
                 }
    
                 val folder = Video(thumb.toString(),id,title,name,size, duration_formatted, videoPath, mdate)
                 marrayList.add(folder)
    
             }
             cursor.close()
         }
         return marrayList
    

    }

2.Here 是全部 [source code]1 视频播放器项目