Fix Xiaomi picker crash on non-persistable content Uri

This commit is contained in:
Piktowo
2026-02-25 11:24:53 +08:00
parent b0fc0c8649
commit 2cfbd91ad9
3 changed files with 44 additions and 12 deletions
@@ -1,7 +1,6 @@
package io.legado.app.ui.config.otherConfig
import android.Manifest
import android.content.Intent
import android.os.Build
import android.widget.Toast
import androidx.activity.compose.rememberLauncherForActivityResult
@@ -43,6 +42,7 @@ import io.legado.app.ui.widget.components.settingItem.InputSettingItem
import io.legado.app.ui.widget.components.settingItem.SliderSettingItem
import io.legado.app.ui.widget.components.settingItem.SwitchSettingItem
import io.legado.app.utils.restart
import io.legado.app.utils.takePersistablePermissionSafely
import org.koin.androidx.compose.koinViewModel
@OptIn(ExperimentalMaterial3Api::class)
@@ -75,9 +75,7 @@ fun OtherConfigScreen(
contract = ActivityResultContracts.OpenDocumentTree()
) { uri ->
uri?.let {
val modeFlags =
Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION
context.contentResolver.takePersistableUriPermission(it, modeFlags)
it.takePersistablePermissionSafely(context)
viewModel.updateLocalBookDir(it.toString())
}
}
@@ -509,4 +507,4 @@ fun ConfirmDialog(
}
}
)
}
}
@@ -23,6 +23,7 @@ import io.legado.app.utils.externalFiles
import io.legado.app.utils.getJsonArray
import io.legado.app.utils.isContentScheme
import io.legado.app.utils.launch
import io.legado.app.utils.takePersistablePermissionSafely
import io.legado.app.utils.toastOnUi
import io.legado.app.utils.viewbindingdelegate.viewBinding
import splitties.init.appCtx
@@ -40,9 +41,7 @@ class HandleFileActivity :
registerForActivityResult(ActivityResultContracts.OpenDocumentTree()) { uri ->
uri?.let {
if (uri.isContentScheme()) {
val modeFlags =
Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION
contentResolver.takePersistableUriPermission(uri, modeFlags)
uri.takePersistablePermissionSafely(this)
}
onResult(Intent().setData(uri))
} ?: finish()
@@ -51,9 +50,7 @@ class HandleFileActivity :
private val selectDoc = registerForActivityResult(ActivityResultContracts.OpenDocument()) {
it?.let {
if (it.isContentScheme()) {
val modeFlags =
Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION
contentResolver.takePersistableUriPermission(it, modeFlags)
it.takePersistablePermissionSafely(this)
}
onResult(Intent().setData(it))
} ?: finish()
@@ -307,4 +304,4 @@ class HandleFileActivity :
finish()
}
}
}
}
@@ -29,6 +29,43 @@ fun Uri.isContentScheme() = this.scheme == "content"
fun Uri.isFileScheme() = this.scheme == "file"
/**
* Some vendors return non-persistable content Uris even in system picker flows.
* Try to persist read/write grants separately and never throw.
*/
fun Uri.takePersistablePermissionSafely(
context: Context,
modeFlags: Int = Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION
): Boolean {
if (!isContentScheme()) return false
var granted = false
if (modeFlags and Intent.FLAG_GRANT_READ_URI_PERMISSION != 0) {
kotlin.runCatching {
context.contentResolver.takePersistableUriPermission(
this,
Intent.FLAG_GRANT_READ_URI_PERMISSION
)
}.onSuccess {
granted = true
}.onFailure {
AppLog.put("持久化读取权限失败: $this", it)
}
}
if (modeFlags and Intent.FLAG_GRANT_WRITE_URI_PERMISSION != 0) {
kotlin.runCatching {
context.contentResolver.takePersistableUriPermission(
this,
Intent.FLAG_GRANT_WRITE_URI_PERMISSION
)
}.onSuccess {
granted = true
}.onFailure {
AppLog.put("持久化写入权限失败: $this", it)
}
}
return granted
}
/**
* 读取URI
*/