如何在没有系统确认对话框的情况下删除 Android 11 (API 30) 上的文件?

use*_*r25 5 android android-file android-storage android-11

我有一个将视频录制到共享 MOVIES 文件夹的应用程序。

我可以使用contentResolver.delete(uri, null, null)我录制的视频活动中的方法删除 Android 11 (API 30) 上的这些文件。

但是,如果我重新安装该应用程序,那么它就会失去对这些文件的权限......(如此糟糕),在这种情况下,我需要做这样的事情:

try {
    context.contentResolver.delete(uri, null, null)
} catch (exception: Exception) {
    if (exception is RecoverableSecurityException) {
        val intentSender = exception.userAction.actionIntent.intentSender
        intentSender?.let {
            callback?.startIntentSenderForResult(
                intentSender,
                requestCode
            )
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

因此它无法删除文件,ContentResolver因为应用程序已重新安装,并且有一个例外,我们可以捕获并打开下一个烦人的对话框以供用户确认删除(并且对于每个文件删除,它应该是一个不同的对话框,多次删除 - 否道路)

在此处输入图片说明

然后我在这个 Android 11 设备(模拟器)上安装了来自 Google Play 的 Explorer 应用程序,当我打开它时,该应用程序只要求存储写入权限(我的应用程序也这样做)并且这个 Explorer 应用程序可以轻松删除任何文件(包括我录制的视频)文件)没有任何确认对话框。

那么他们是如何做到的呢?这是一个黑客还是什么?

链接到应用程序https://play.google.com/store/apps/details?id=com.speedsoftware.explorer

更新

VLC for Android 也可以删除任何媒体文件https://play.google.com/store/apps/details?id=org.videolan.vlc

他们也使用内容提供程序,所以它是一样的,但它返回的true不像我的应用程序,为什么?

fun deleteFile(file: File): Boolean {
    var deleted: Boolean
    //Delete from Android Medialib, for consistency with device MTP storing and other apps listing content:// media
    if (file.isDirectory) {
        deleted = true
        for (child in file.listFiles()) deleted = deleted and deleteFile(child)
        if (deleted) deleted = deleted and file.delete()
    } else {
        val cr = AppContextProvider.appContext.contentResolver
        try {
            deleted = cr.delete(MediaStore.Files.getContentUri("external"),
                    MediaStore.Files.FileColumns.DATA + "=?", arrayOf(file.path)) > 0
        } catch (ignored: IllegalArgumentException) {
            deleted = false
        } catch (ignored: SecurityException) {
            deleted = false
        }
        // Can happen on some devices...
        if (file.exists()) deleted = deleted or file.delete()
    }
    return deleted
}
Run Code Online (Sandbox Code Playgroud)

https://github.com/videolan/vlc-android/blob/master/application/vlc-android/src/org/videolan/vlc/util/FileUtils.kt#L240

Jat*_*iya 5

Android 11 (API 30) 没有系统确认对话框,您可以执行此操作,但需要获得manage_external_storage许可。该权限只允许某些特定类别的应用程序使用。

  • 文件管理器
  • 备份和恢复应用程序
  • 防病毒应用程序
  • 文档管理应用程序
  • 设备上的文件搜索
  • 磁盘和文件加密
  • 设备到设备的数据迁移

管理存储设备上的所有文件

如果您的应用程序不遵循上述类别,那么您不允许使用manage_external_storage权限进行发布。

如果您的应用程序是图库、视频和音频播放器,那么您不需要许可manage_external_storage,可以通过系统确认对话框直接删除它。
在这里您可以获取删除媒体文件的示例

在 android 11 之前,您可以直接使用 file.delete() 方法并删除文件。

在 android 11 中,file.delete()方法仅在您创建自己的内容时才有效。例如,您的应用程序下载一张图像,在此案例file.delete()方法中,位置是外部存储。

如果您想删除相机或屏幕截图等媒体文件,则该时间file.delete()方法在 Android 11 中不起作用,因为您未创建媒体内容。这种情况下会出现系统确认对话框。


bla*_*pps 0

我认为只会ContentResolver.applyBatch()询问用户一次。

看看这里:

https://developer.android.com/guide/topics/providers/content-provider-basics.html#Batch