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)
一个多星期以来,我一直在尝试解决奇怪的问题。当我尝试使用 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)