【问题标题】:takePersistableUriPermission via ACTION_OPEN_DOCUMENT fails when trying to get many documents尝试获取许多文档时,通过 ACTION_OPEN_DOCUMENT 的 takePersistableUriPermission 失败
【发布时间】:2021-11-17 22:02:43
【问题描述】:

一个多星期以来,我都在尝试解决奇怪的问题。当我尝试使用 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$1.onActivityResult(PlaylistActivity.kt:123)
    at com.example.weddkit20.view.songbook.PlaylistActivity$setResultLaunchers$1.onActivityResult(PlaylistActivity.kt:41)
    at androidx.activity.result.ActivityResultRegistry$1.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 获取文件内容没有问题(在另一个活动 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
        )
    }

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

【问题讨论】:

  • addFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION) addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) } 这没有意义。你不能自己授予任何东西。最好删除这些行。
  • context.grantUriPermission( context.packageName, uri, Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION ) 这也没有意义,因为你不能自己授予任何东西。只有在授予您许可的情况下,您才能获得许可。删除 slso。
  • 是的,你是对的,我将删除这些行。我离开了那些因为我想尝试一切以防我错过了什么。

标签: android kotlin uri


【解决方案1】:

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

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

【讨论】:

  • 这似乎是答案!我使用 SDK 29 在物理设备上测试了我的代码,并在加载 130 个文件时遇到了这些问题。然后我在带有 SDK 30 的模拟器上运行相同的代码并且没有任何问题。我只是对堆栈跟踪中的信息感到生气,因为它完全具有误导性。无论如何感谢您的回答:)。我会为这种情况找到另一种解决方案。
【解决方案2】:

我正在使用它来打开我项目中的 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)

【讨论】:

    猜你喜欢
    • 2016-03-23
    • 2021-08-20
    • 2020-07-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-05-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多