正确查询 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
权限,我有以下问题:
- 在 Android 11 的运行时请求
READ_EXTERNAL_STORAGE
是否可以被 Google 接受(当我在他们的商店上发布我的应用程序时)?
- 我可以为所有 API 请求
WRITE_EXTERNAL_STORAGE
运行时权限而不是 READ_EXTERNAL_STORAGE
并且 Android 11 设备上的系统会用它代替 READ_EXTERNAL_STORAGE
还是我会需要在 Android 11 台设备上要求 READ_EXTERNAL_STORAGE
添加条件。
- 在 Android 11 的运行时要求
WRITE_EXTERNAL_STORAGE
是否可以被 Google 接受(当我在他们的商店上发布我的应用程序时)?
您可以使用所有这些权限而不受 Google 的任何禁止。你不能t/shouldn不能使用MANAGE_EXTERNAL_STORAGE
,专用于分区存储和文件管理应用程序、杀毒软件和其他“特权”软件的新权限
这是获取所有视频列表的函数
有趣的 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 视频播放器项目
我正在努力为我的 audio/video 播放器应用程序提供 Android 11 支持。我主要关心的实际上是不要激怒 Google 部落,因为他们没有 All files access
允许播放器应用程序的权限。我不希望我的应用程序在 Google 商店上发布时被拒绝。
在以前的 API 中,我使用的是 WRITE_EXTERNAL_STORAGE
权限,包括 Android 10(我选择退出分区存储)。虽然,我不知道如何处理 Android 11 而不会让我的应用程序在 Google 商店上发布时被拒绝。我了解到查询 MediaStore
记录需要 READ_EXTERNAL_STORAGE
权限,我有以下问题:
- 在 Android 11 的运行时请求
READ_EXTERNAL_STORAGE
是否可以被 Google 接受(当我在他们的商店上发布我的应用程序时)? - 我可以为所有 API 请求
WRITE_EXTERNAL_STORAGE
运行时权限而不是READ_EXTERNAL_STORAGE
并且 Android 11 设备上的系统会用它代替READ_EXTERNAL_STORAGE
还是我会需要在 Android 11 台设备上要求READ_EXTERNAL_STORAGE
添加条件。 - 在 Android 11 的运行时要求
WRITE_EXTERNAL_STORAGE
是否可以被 Google 接受(当我在他们的商店上发布我的应用程序时)?
您可以使用所有这些权限而不受 Google 的任何禁止。你不能t/shouldn不能使用MANAGE_EXTERNAL_STORAGE
,专用于分区存储和文件管理应用程序、杀毒软件和其他“特权”软件的新权限
这是获取所有视频列表的函数
有趣的 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 视频播放器项目