MWCodebymw.de ↗
Kotlin

Berechtigungen und Foto-Auswahl in Compose – rememberLauncherForActivityResult

Kamera-Erlaubnis abfragen, ein Bild aus der Galerie holen, ein Dokument öffnen: Dafür gibt es in Compose genau einen Weg, und er ist erfreulich kurz. onActivityResult und startActivityForResult brauchst du nie wieder.

Fast jede App braucht das irgendwann: „Darf ich auf die Kamera?", „Such dir ein Bild aus", „Öffne diese PDF". Früher war das ein Ritual aus startActivityForResult, magischen Request-Codes und einem onActivityResult, in dem irgendwann alles zusammenlief. In Compose ist es ein Einzeiler pro Anliegen.

Eine Berechtigung anfragen

@Composable
fun KameraButton(onErlaubt: () -> Unit) {
    val ctx = LocalContext.current
    var abgelehnt by remember { mutableStateOf(false) }

    val launcher = rememberLauncherForActivityResult(
        ActivityResultContracts.RequestPermission()
    ) { erlaubt ->
        if (erlaubt) onErlaubt() else abgelehnt = true
    }

    Column {
        Button(onClick = {
            val schon = ContextCompat.checkSelfPermission(ctx, Manifest.permission.CAMERA)
            if (schon == PackageManager.PERMISSION_GRANTED) onErlaubt()
            else launcher.launch(Manifest.permission.CAMERA)
        }) { Text("Foto aufnehmen") }

        if (abgelehnt) {
            Text("Ohne Kamera-Erlaubnis geht das leider nicht.")
        }
    }
}

Zwei Dinge sind hier wichtig:

  • Erst prüfen, dann fragen. checkSelfPermission kostet nichts und erspart dem Nutzer einen Dialog, den er schon einmal beantwortet hat.
  • Der Launcher lebt an der Composition. rememberLauncherForActivityResult registriert sich beim Aufbau und meldet sich beim Verschwinden wieder ab. Genau deshalb darfst du ihn nicht in einem if-Zweig oder einer Schleife erzeugen — er muss bei jeder Recomposition an derselben Stelle stehen.

Ein Bild auswählen – ohne jede Berechtigung

Das ist der Teil, den viele übersehen: Für den Photo Picker brauchst du gar keine Speicher-Berechtigung. Das System zeigt die Auswahl, deine App bekommt nur das eine Bild.

var bild by remember { mutableStateOf<Uri?>(null) }

val picker = rememberLauncherForActivityResult(
    ActivityResultContracts.PickVisualMedia()
) { uri -> bild = uri }   // uri ist null, wenn abgebrochen wurde

Button(onClick = {
    picker.launch(PickVisualMediaRequest(ActivityResultContracts.PickVisualMedia.ImageOnly))
}) { Text("Bild wählen") }

bild?.let { AsyncImage(model = it, contentDescription = null) }

Weniger Code und weniger Berechtigungen — die einzige Kombination, bei der man nichts abwägen muss. Wer noch READ_EXTERNAL_STORAGE anfragt, nur um ein Profilbild auszuwählen, sollte hier umsteigen.

Mehrere Berechtigungen auf einmal

val launcher = rememberLauncherForActivityResult(
    ActivityResultContracts.RequestMultiplePermissions()
) { ergebnis: Map<String, Boolean> ->
    val alleDa = ergebnis.values.all { it }
    // …
}

launcher.launch(arrayOf(Manifest.permission.CAMERA, Manifest.permission.RECORD_AUDIO))

Was ich dabei gelernt habe

Frag erst, wenn es einen sichtbaren Grund gibt. Ein Berechtigungsdialog beim ersten App-Start, ohne dass der Nutzer irgendetwas angetippt hat, wird sehr oft weggeklickt — und beim zweiten „Nein" ist die Tür bei Android dauerhaft zu. Frage stattdessen genau in dem Moment, in dem jemand auf „Foto aufnehmen" tippt. Dann ist der Zusammenhang klar und die Zustimmungsrate deutlich höher.

Und plane den Fall ein, dass jemand ablehnt. Eine App, die danach nur noch eine leere Fläche zeigt, wirkt kaputt. Ein Satz reicht: was fehlt, und wie man es in den Einstellungen nachholen kann.

Du baust gerade eine Android-App und bist dir bei so einer Stelle unsicher? Schreib mir — ich schaue mir das gerne an.

Quellen

#Jetpack Compose#Berechtigungen#ActivityResult#Android#Foto

Du brauchst mehr als ein Snippet?

Ich entwickle Android-Apps in Kotlin und moderne Websites für Selbstständige und kleine Unternehmen — von der ersten Idee bis zum Release.

Projekt anfragen →