takePersistableUriPermission via ACTION_OPEN_DOCUMENT 尝试获取许多文档时失败

takePersistableUriPermission via ACTION_OPEN_DOCUMENT fails when trying to get many documents

一个多星期以来,我一直在尝试解决奇怪的问题。当我尝试使用 SAF 和 ACTION_OPEN_DOCUMENT 获取文件 uri 并对它们使用 takePersistableUriPermission() 方法时,我得到 SecurityException :

java.lang.SecurityException: UID 10384 does not have permission to content://com.android.externalstorage.documents/document/primary%3Abig%20mock%20playlist%2FB%C4%85d%C5%BA%20moj%C4%85%20kr%C3%B3low%C4%85.pdf [user 0]; you could obtain access using ACTION_OPEN_DOCUMENT or related APIs
    at android.os.Parcel.createException(Parcel.java:1953)
    at android.os.Parcel.readException(Parcel.java:1921)
    at android.os.Parcel.readException(Parcel.java:1871)
    at android.app.IActivityManager$Stub$Proxy.grantUriPermission(IActivityManager.java:4757)
    at android.app.ContextImpl.grantUriPermission(ContextImpl.java:2084)
    at android.content.ContextWrapper.grantUriPermission(ContextWrapper.java:781)
    at android.content.ContextWrapper.grantUriPermission(ContextWrapper.java:781)
    at com.example.weddkit20.util.UriHelper$Companion.grantReadPermissionToUri(UriHelper.kt:27)
    at com.example.weddkit20.view.songbook.PlaylistActivity$setResultLaunchers.onActivityResult(PlaylistActivity.kt:123)
    at com.example.weddkit20.view.songbook.PlaylistActivity$setResultLaunchers.onActivityResult(PlaylistActivity.kt:41)
    at androidx.activity.result.ActivityResultRegistry.onStateChanged(ActivityResultRegistry.java:148)
    at androidx.lifecycle.LifecycleRegistry$ObserverWithState.dispatchEvent(LifecycleRegistry.java:354)
    at androidx.lifecycle.LifecycleRegistry.forwardPass(LifecycleRegistry.java:265)
    at androidx.lifecycle.LifecycleRegistry.sync(LifecycleRegistry.java:307)
    at androidx.lifecycle.LifecycleRegistry.moveToState(LifecycleRegistry.java:148)
    at androidx.lifecycle.LifecycleRegistry.handleLifecycleEvent(LifecycleRegistry.java:134)
    at androidx.lifecycle.ReportFragment.dispatch(ReportFragment.java:68)
    at androidx.lifecycle.ReportFragment.dispatch(ReportFragment.java:144)
    at androidx.lifecycle.ReportFragment.onStart(ReportFragment.java:109)
    at android.app.Fragment.performStart(Fragment.java:2568)
    at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:1339)
    at android.app.FragmentManagerImpl.moveFragmentToExpectedState(FragmentManager.java:1581)
    at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:1643)
    at android.app.FragmentManagerImpl.dispatchMoveToState(FragmentManager.java:3054)
    at android.app.FragmentManagerImpl.dispatchStart(FragmentManager.java:3011)
    at android.app.FragmentController.dispatchStart(FragmentController.java:193)
    at android.app.Activity.performStart(Activity.java:7487)
    at android.app.ActivityThread.handleStartActivity(ActivityThread.java:3454)
    at android.app.servertransaction.TransactionExecutor.performLifecycleSequence(TransactionExecutor.java:180)
    at android.app.servertransaction.TransactionExecutor.cycleToPath(TransactionExecutor.java:165)
    at android.app.servertransaction.TransactionExecutor.executeLifecycleState(TransactionExecutor.java:142)
    at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:70)
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2199)
    at android.os.Handler.dispatchMessage(Handler.java:112)
    at android.os.Looper.loop(Looper.java:216)
    at android.app.ActivityThread.main(ActivityThread.java:7625)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:524)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:987)
 Caused by: android.os.RemoteException: Remote stack trace:
    at com.android.server.am.ActivityManagerService.checkGrantUriPermissionLocked(ActivityManagerService.java:10930)
    at com.android.server.am.ActivityManagerService.grantUriPermissionLocked(ActivityManagerService.java:11001)
    at com.android.server.am.ActivityManagerService.grantUriPermission(ActivityManagerService.java:11178)
    at android.app.IActivityManager$Stub.onTransact(IActivityManager.java:691)
    at com.android.server.am.ActivityManagerService.onTransact(ActivityManagerService.java:3648)

奇怪的是,只有当我尝试加载大量文件(100 个或更多)时才会出现此错误。如果我加载的文件数量较少,则授予所有权限,uri 将保存在本地数据库中,使用这些 uri 获取文件内容没有问题(在另一个 activity UI 中显示 PDF 文件的内容)。错误清楚地表明我应该使用我实际使用的 ACTION_OPEN_DOCUMENT。

用于从文件浏览器加载文件的代码:

播放列表活动:

private fun showFileBrowser() {

    val intent = Intent(Intent.ACTION_OPEN_DOCUMENT).apply {
        type = "application/pdf"
        addCategory(Intent.CATEGORY_OPENABLE)
        putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true)
        addFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION)
        addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
    }
    fileResultLauncher.launch(intent)
}

private fun setResultLaunchers() {
    fileResultLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
        if (result.resultCode == Activity.RESULT_OK) {
            Log.d(TAG, "Success callback from file browser fired off!")
            val uriList : MutableList<Uri>  = arrayListOf()
            val uriClipData = result.data!!.clipData
            if(uriClipData != null) {
                //if user picked multiple files
                for(i in 0 until uriClipData.itemCount) { uriList.add(uriClipData.getItemAt(i).uri!!) }
            } else {
                //if user picked one file
                uriList.add(result.data!!.data!!)
            }

            //granting permissions
            uriList.forEach { uri ->
                UriHelper.grantReadPermissionToUri(this, uri)
            }

            //business logic
            val songList : List<Song> = uriList.map {
                val fullFilename = UriHelper.getFileName(contentResolver, it)
                val filename = StringHelper.stripExtensionFromFilename(fullFilename)
                val extension = StringHelper.getExtensionFromFilename(fullFilename)
                val song = Song(it, filename, extension)
                song.isOnPlaylist = false
                song
            }
            availableSongsAdapter.submitList(songList)
            createPlaylistAdapter.submitList(arrayListOf())
            createPlaylistViewModel.getStoredCloudSongs(this)
        }
    }
}

UriHelper :

    @Throws(Exception::class)
    fun grantReadPermissionToUri(context: Context, uri: Uri) {
        context.grantUriPermission(
            context.packageName,
            uri,
            Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION
        )
        context.contentResolver.takePersistableUriPermission(
            uri,
            Intent.FLAG_GRANT_READ_URI_PERMISSION
        )
    }

任何可能出错的提示都将不胜感激。请帮助我,因为这个问题让我发疯:/

在 Android 10 及更低版本上,有 128 个持久权限授予的限制:https://issuetracker.google.com/issues/149315521

对于 Android 11,该限制提高到 512;我不知道Android 12 是否进一步提出。

我正在使用它打开我的项目中的 PDF 文件,没有任何问题,试一试。

val uri: Uri = Uri.parse(url)
val typeFile = "application/pdf"

val intent = Intent()
intent.action = Intent.ACTION_VIEW
intent.setDataAndType(uri, typeFile)
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
startActivity(intent)