nder(),requestCode,null,0,0,0,null); } else if(Build.VERSION.SDK_INT==Build.VERSION_code.Q) { 尝试 { //在Android==Q中,如果未被拥有,则会引发可恢复

nder(),requestCode,null,0,0,0,null); } else if(Build.VERSION.SDK_INT==Build.VERSION_code.Q) { 尝试 { //在Android==Q中,如果未被拥有,则会引发可恢复,android,delete-file,saf,Android,Delete File,Saf,nder(),requestCode,null,0,0,0,null); } else if(Build.VERSION.SDK_INT==Build.VERSION_code.Q) { 尝试 { //在Android==Q中,如果未被拥有,则会引发可恢复安全性异常。 //对于批处理请求,删除将在失败的“未拥有”位置停止 //文件,所以您可能希望将Android Q中的删除限制为 //一次1个文件,让体验不那么难看。 //幸运的是,这在Android R中得到了解决。 for(最终Uri:uri

nder(),requestCode,null,0,0,0,null); } else if(Build.VERSION.SDK_INT==Build.VERSION_code.Q) { 尝试 { //在Android==Q中,如果未被拥有,则会引发可恢复安全性异常。 //对于批处理请求,删除将在失败的“未拥有”位置停止 //文件,所以您可能希望将Android Q中的删除限制为 //一次1个文件,让体验不那么难看。 //幸运的是,这在Android R中得到了解决。 for(最终Uri:uriList) { delete(uri,null,null); } } 捕获(可恢复安全性异常ex) { 最终意图发布者意图=ex.getUserAction() .getActionIntent() .getIntentSender(); //重要提示:仍然需要执行实际删除 //像往常一样,再次使用getContentResolver().delete(…), //在“onActivityResult”回调中,就像在Android Q中一样 //所有这些额外代码都是获得许可所必需的, //因为系统根本不执行任何实际的删除。 //onActivityResult没有目标Uri,因此 //我需要在某处抓住它。 activity.startinentsenderforresult(intent、requestCode、null、0、0、null); } } 其他的 { //与旧API一样 for(最终Uri:uriList) { delete(uri,null,null); } } }
“那么这个应用程序就失去了以前创建的所有公共文件的所有权”——你是如何创建它们的?苏丹武装部队<代码>媒体商店?还有什么?这些文件是使用MediaStore创建的,通过使用ContentResolver插入一条新记录。卸载应用程序后,Android会将字段MediaStore.MediaColumns.OWNER\u PACKAGE\u NAME设置为Null,因此在重新安装应用程序时,从逻辑上讲,此字段不再具有所有权。好的,但是如何拥有“一组已知的特定文件”?应用程序的安装2如何区分应用程序安装1创建的内容与其他应用程序创建的内容或用户复制到设备上的内容?您无法可靠地派生这些文件的SAF
Uri
值,而且您也没有权限。但是,如果它们是
MediaStore
条目,如果您按住
WRITE\u EXTERNAL\u STORAGE
,则可以使用
MediaStore
本身删除它们。文档引用能够使用
read_EXTERNAL_STORAGE
读取内容。我们在所有Android版本中删除文件的方式都是通过MediaStore,使用ContentResolver.delete(uri,…),但在Android Q中,对于未拥有的文件,这种操作失败,不考虑写入/读取权限。这些文件是用我们的产品名称保存到特定文件夹中的图像。通过检查BUCKET\u DISPLAY\u NAME字段是否具有应用程序名称,我们可以知道这些文件以前拥有并可以查询它们。我们还打算在Android Q中检查相对_路径是否也包含名称。当然,这不是防弹的,但由于应用程序名称不常见,甚至带有商标,那么另一个应用程序具有相同名称的可能性实际上是零,而没有考虑到用户可能会使用该名称创建另一个文件夹,但我们想不出任何原因。谢谢回答,安卓Q变得越来越复杂。在我看来,就像Android有一个公共共享面板,一个公共权限提示等等一样,那么在Android Q中有了所有新的文件限制,至少Android团队在系统级实现了某种新的删除提示面板是件好事,这可以使删除文件的操作更加安全、一致,并且在应用程序之间保持一致,因此保持安全性并使开发人员的生活更轻松。如何使用
DocumentFile.fromsingeluri
我也设法使用
Uri documentUri=MediaStore.getDocumentUri(getActivity(),mediaUri)删除单个文件DocumentFile=DocumentFile.fromSingleUri(getActivity(),documentUri)
然后我就对文档文件调用delete。@VinceVD:如果这样可以删除底层内容,那太好了!在这种情况下,OP有一个内容目录(“文件是用我们的产品名保存到特定文件夹中的图像”),我专注于从目录角度工作。这不会删除文件,只是从MediaStore中删除条目。
    val uri: String? = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI.toString()
    val where = MediaStore.Audio.Media._ID + "=?"
    val selectionArgs = arrayOf(mId)

    try {
        val deleted = mActivity.contentResolver.delete(Uri.parse(uri), where, selectionArgs)

        return deleted >= 0

    } catch (securityException: SecurityException) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
            val recoverableSecurityException =
                    securityException as? RecoverableSecurityException
                            ?: throw SecurityException()

            val intentSender = recoverableSecurityException.userAction.actionIntent.intentSender

            intentSender?.let {
                mActivity.startIntentSenderForResult(intentSender, 0, null, 0, 0, 0, null)
            }
        } else {
            throw SecurityException()
        }
    }
val values = ContentValues().apply {
                put(MediaStore.Audio.Media.TITLE, song?.title)
                put(MediaStore.MediaColumns.DISPLAY_NAME, song?.title)
                put(MediaStore.Audio.Media.DATE_ADDED, System.currentTimeMillis())
                put(MediaStore.Audio.Media.MIME_TYPE, song?.mimeType)
            }

            val resolver = mContext.contentResolver

            val uri = resolver.insert(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, values)

            // Download file to Media Store
            uri?.let { mUri ->
                resolver.openOutputStream(mUri).use { mOutputStream ->
                    mOutputStream?.let {
                        // Download to output stream using the url we just created
                    }
                }
            }
public static void delete(final Activity activity, final Uri[] uriList, final int requestCode)
        throws SecurityException, IntentSender.SendIntentException, IllegalArgumentException
{
    final ContentResolver resolver = activity.getContentResolver();

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R)
    {
        // WARNING: if the URI isn't a MediaStore Uri and specifically
        // only for media files (images, videos, audio), the request
        // will throw an IllegalArgumentException, with the message:
        // 'All requested items must be referenced by specific ID'

        // No need to handle 'onActivityResult' callback, when the system returns
        // from the user permission prompt the files will be already deleted.
        // Multiple 'owned' and 'not-owned' files can be combined in the 
        // same batch request. The system will automatically delete them using the 
        // using the same prompt dialog, making the experience homogeneous.

        final List<Uri> list = new ArrayList<>();
        Collections.addAll(list, uriList);

        final PendingIntent pendingIntent = MediaStore.createDeleteRequest(resolver, list);
        activity.startIntentSenderForResult(pendingIntent.getIntentSender(), requestCode, null, 0, 0, 0, null);
    }
    else if (Build.VERSION.SDK_INT == Build.VERSION_CODES.Q)
    {
        try
        {
            // In Android == Q a RecoverableSecurityException is thrown if not-owned.
            // For a batch request the deletion will stop at the failed not-owned
            // file, so you may want to restrict deletion in Android Q to only
            // 1 file at a time, to make the experience less ugly.
            // Fortunately this gets solved in Android R.

            for (final Uri uri : uriList)
            {
                resolver.delete(uri, null, null);
            }
        }
        catch (RecoverableSecurityException ex)
        {
            final IntentSender intent = ex.getUserAction()
                    .getActionIntent()
                    .getIntentSender();

            // IMPORTANT: still need to perform the actual deletion
            // as usual, so again getContentResolver().delete(...),
            // in your 'onActivityResult' callback, as in Android Q
            // all this extra code is necessary 'only' to get the permission,
            // as the system doesn't perform any actual deletion at all.
            // The onActivityResult doesn't have the target Uri, so you
            // need to catch it somewhere.
            activity.startIntentSenderForResult(intent, requestCode, null, 0, 0, 0, null);
        }
    }
    else
    {
        // As usual for older APIs
        
        for (final Uri uri : uriList)
        {
            resolver.delete(uri, null, null);
        }
    }
}