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

Posted

技术标签:

【中文标题】如何在没有系统确认对话框的情况下删除 Android 11 (API 30) 上的文件?【英文标题】:How can I delete file on Android 11 (API 30) without system confirmation dialog? 【发布时间】:2021-02-11 08:59:40 【问题描述】:

我有一个将视频录制到共享 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
            )
        
    

所以它无法使用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

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

【问题讨论】:

请求所有文件访问的应用程序 - 就像文件管理器一样 - 可以使用标准 File 类删除所有文件。无需使用内容解析器或媒体存储。无需询问用户。 @blackapps 他们如何请求此类访问权限? VLC for Android 也可以轻松删除文件(它不是文件管理器) Android 11 会出现批量删除,不是已经有了吗? "可以使用 MANAGE_EXTERNAL_STORAGE 权限并在 Google Play 上发布更新吗?" ——我没有办法回答这个问题。 “但我仍然想在没有任何对话框的情况下删除视频文件”——你已经在这样做了。您的问题是,如果用户卸载您的应用,然后重新安装您的应用,您无法从应用中删除任何旧录音。恕我直言,你想多了一个不常见的事件。只需告诉用户“嘿,您已卸载并重新安装,因此我们需要您的帮助来清理旧录音”,然后使用存储访问框架。 @CommonsWare 据说有 ContentResolver#checkUriPermission(Uri, int, int) 但我在 ContentResolver...developer.android.com/reference/android/provider/… 找不到这个方法 【参考方案1】:

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

看看这里:

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

【讨论】:

这是developer.android.com/reference/android/provider/…【参考方案2】:

Android 11 (API 30) 没有系统确认对话框你可以做,但你需要manage_external_storage 权限。某些特定类别的应用程序允许该权限。

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

Manage all files on a storage device

如果您的应用不属于上述类别,则不允许以 manage_external_storage 权限发布。

如果您的应用是图库、视频和音频播放器,那么您不需要manage_external_storage 权限,您可以直接通过系统确认对话框将其删除。Here you can get the example to delete media file

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

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

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

【讨论】:

【参考方案3】:

这是一个适用于 Android Q 和 R 的很好的解决方案, 您可以在 Android R 中重命名、复制或删除文件。 查看这个类:https://gist.github.com/fiftyonemoon/433b563f652039e32c07d1d629f913fb

【讨论】:

以上是关于如何在没有系统确认对话框的情况下删除 Android 11 (API 30) 上的文件?的主要内容,如果未能解决你的问题,请参考以下文章

如何在没有确认的情况下使用 django migrate

在没有确认对话框的情况下取消下拉列表的更改事件

laravel modal 删除确认不会去破坏路由

如何让 PhpMyAdmin 在不要求确认的情况下删除/截断

删除文件时没有弹出确认提示框

MUI中有没有confirm确认的对话框