Android 14中图库视频删除功能失效问题求助
问题分析
你遇到的删除失败问题,核心原因是Android 13+的媒体权限模型变化:添加READ_MEDIA_VISUAL_USER_SELECTED后,该权限仅允许访问用户手动选择的媒体,不具备删除权限;同时WRITE_EXTERNAL_STORAGE在Android 13+对媒体文件已失效,无法提供删除所需的写入权限。之前代码能正常运行是因为旧权限模型下WRITE_EXTERNAL_STORAGE拥有全存储访问权限。
解决方案
1. 调整Manifest权限
针对不同系统版本配置对应权限,确保删除操作的权限合法性:
<!-- Android 12及以下保留WRITE_EXTERNAL_STORAGE --> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="32"/> <!-- Android 13+添加专门的视频写入/删除权限 --> <uses-permission android:name="android.permission.WRITE_MEDIA_VIDEO" android:minSdkVersion="33"/>
2. 动态申请删除权限
在删除操作前,需先检查并申请对应权限:
private const val REQUEST_DELETE_PERMISSION = 1001 private fun checkDeletePermission(): Boolean { return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_MEDIA_VIDEO) == PackageManager.PERMISSION_GRANTED } else { ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED } } private fun requestDeletePermissions() { val permissions = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { arrayOf(Manifest.permission.WRITE_MEDIA_VIDEO) } else { arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE) } ActivityCompat.requestPermissions(this, permissions, REQUEST_DELETE_PERMISSION) } override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) { super.onRequestPermissionsResult(requestCode, permissions, grantResults) if (requestCode == REQUEST_DELETE_PERMISSION) { if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) { binding.deleteVideoButton.performClick() } else { Toast.makeText(this, getString(R.string.permission_required_for_deletion), Toast.LENGTH_SHORT).show() } } }
3. 修改删除逻辑(通过ContentResolver操作MediaStore)
Android 13+推荐通过MediaStore操作媒体文件,避免直接File操作的权限问题:
首先添加工具函数获取视频在MediaStore中的Uri:
fun getVideoUriByFileName(context: Context, fileName: String): Uri? { val projection = arrayOf(MediaStore.Video.Media._ID) val selection = "${MediaStore.Video.Media.DISPLAY_NAME} = ?" val selectionArgs = arrayOf(fileName) context.contentResolver.query( MediaStore.Video.Media.EXTERNAL_CONTENT_URI, projection, selection, selectionArgs, null )?.use { cursor -> if (cursor.moveToFirst()) { val id = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.Video.Media._ID)) return ContentUris.withAppendedId(MediaStore.Video.Media.EXTERNAL_CONTENT_URI, id) } } return null }
然后替换原删除逻辑中的协程代码:
CoroutineScope(Dispatchers.IO).launch { val videoFileName = file.name val videoUri = getVideoUriByFileName(applicationContext, videoFileName) val deletedCount = if (videoUri != null) { try { applicationContext.contentResolver.delete(videoUri, null, null) } catch (e: SecurityException) { 0 } } else { // 兼容找不到MediaStore条目的情况,尝试直接删除文件 if (file.delete()) 1 else 0 } withContext(Dispatchers.Main) { binding.progressBar.visibility = View.GONE if (deletedCount > 0) { val tempoVideos = Utilities.listVideos(applicationContext) val tempoThumbnails = Utilities.convertFilesToBitmaps(tempoVideos.take(5)) val tempoUris = tempoVideos.map { Uri.fromFile(it) } if (tempoUris.isNotEmpty()) { currentVideoUri = tempoUris[0] preparePlayer(currentVideoUri) } adapter.updateThumbnails(tempoThumbnails, tempoUris) loadRemainingBitmaps(tempoVideos.drop(5)) } else { Toast.makeText(this@PreviewActivity, getString(R.string.failed_to_delete_video), Toast.LENGTH_SHORT).show() } } }
4. 更新删除按钮点击事件
在原点击逻辑开头添加权限检查:
binding.deleteVideoButton.setOnClickListener { if (!checkDeletePermission()) { requestDeletePermissions() return@setOnClickListener } // 原有的文件检查、弹窗逻辑... }
内容的提问来源于stack exchange,提问作者NeroVero
相关产品推荐
相关产品推荐

