Notei a seguinte exceção (Firebase Crashlytics):
Fatal Exception: java.lang.RuntimeException
Failure delivering result ResultInfo{who=null, request=1915322883, result=-1, data=Intent { dat=content:/... flg=0xc3 }} to activity {com..../com....Activity}: java.lang.SecurityException: No persistable permission grants found for UID 10571 and Uri content:/...
Fatal Exception: java.lang.SecurityException
No persistable permission grants found for UID 10434 and Uri content:/...
android.content.ContentResolver.takePersistableUriPermission (ContentResolver.java:2952)
Caused by android.os.RemoteException
Remote stack trace: at com.android.server.uri.UriGrantsManagerService.takePersistableUriPermission(UriGrantsManagerService.java:385) at android.app.IUriGrantsManager$Stub.onTransact(IUriGrantsManager.java:139) at android.os.Binder.execTransactInternal(Binder.java:1375) at android.os.Binder.execTransact(Binder.java:1311)
Quando o aplicativo chama ContentResolver.takePersistableUriPermission
:
val safResultLauncher = rememberLauncherForActivityResult(
contract = ActivityResultContracts.StartActivityForResult()
) { activityResult ->
coroutineScope.launch {
if (activityResult.resultCode == Activity.RESULT_OK) {
val treeUri = activityResult.data?.data
if (treeUri != null) {
context.contentResolver.takePersistableUriPermission(
treeUri,
Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION
)
}
}
}
}
// select a folder
try {
safResultLauncher.launch(Intent.ACTION_OPEN_DOCUMENT_TREE)
} catch (e: Throwable) {
// ...
}
Acontece apenas para dispositivos Samsung (Android 13-14):
- Galaxy S24 Ultra
- Galáxia S24+
- Galaxy S21+ 5G
- Galaxy S20FE 5G
- Galaxy Z Fold5
- Galáxia Z Flip4
- Galáxia Z Flip4
- Galáxia A24
- Galáxia A15 5G
- Galáxia A15
- Galáxia A14 5G
Atualizar
Então, acho que podemos tentar limpar as concessões de uri persistentes atuais (quando você não precisa delas) por causa da limitação e também lidar com a exceção caso não seja possível obter uri persistente para alguns armazenamentos:
fun grantPermissionForFolderSaf(
context: Context,
activityResult: ActivityResult,
): Uri? {
if (activityResult.resultCode == Activity.RESULT_OK) {
val treeUri = activityResult.data?.data
if (treeUri != null) {
clearAllPersistedUriPermissions(context)
try {
context.contentResolver.takePersistableUriPermission(
/* uri = */ treeUri,
/* modeFlags = */ Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION
)
return treeUri
} catch (e: Throwable) {
// ... explanation for a user to try to select a different storage
}
}
}
return null
}
private fun clearAllPersistedUriPermissions(context: Context) {
try {
val contentResolver = context.contentResolver
for (uriPermission in contentResolver.persistedUriPermissions) {
contentResolver.releasePersistableUriPermission(
/* uri = */ uriPermission.uri,
/* modeFlags = */ Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION
)
}
} catch (e: Throwable) {
// just to be safe...
e.printStackTrace()
}
}
Não há garantia de que você obterá uma permissão persistente ao solicitá-la. Existem tantos que seu aplicativo pode solicitar ( o limite costumava ser 128, mas deveria ser 512 para seus dispositivos ). Além disso, o fabricante ou
DocumentsProvider
desenvolvedor pode não oferecer permissões persistentes para alguma escolha feita pelo usuário.Você precisa lidar normalmente com o caso em que
takePersistableUriPermission()
lança uma exceção.