Permission Handler ist eine Android-Anwendungskomponente, die für die Überprüfung, Anforderung und Verarbeitung von Ergebnissen von Laufzeitberechtigungen zuständig ist. Laut dem Android Developer Guide, 2024 zentralisiert ein Berechtigungs-Handler die Logik von checkSelfPermission, requestPermissions und shouldShowRequestPermissionRationale in einer einzigen Klasse oder ViewModel. Dies vereinfacht die Code-Wartung und verbessert das Testen.
Wichtige Punkte
Permission Handler ist ein Architekturmuster für die zentrale Verwaltung von Android-Laufzeitberechtigungen. Anstatt verstreuter Aufrufe von ContextCompat.checkSelfPermission und ActivityCompat.requestPermissions im gesamten Anwendungscode wird die gesamte Logik der Anfragen und Ergebnisverarbeitung in einer einzigen Klasse konzentriert. Dies reduziert Duplikate, vereinfacht die Wartung und macht den Code vorhersagbarer.
Die Notwendigkeit eines Permission Handler entstand mit der Einführung von Laufzeitberechtigungen in Android 6.0. Zuvor wurden alle Berechtigungen bei der Installation angefordert, und der Anwendungscode konnte ohne Überprüfungen beliebige APIs verwenden. Nach dem Wechsel zum Laufzeitmodell erfordert jede Verwendung einer gefährlichen Berechtigung eine dreistufige Überprüfung: checkSelfPermission, requestPermissions, onRequestPermissionsResult. Die Verteilung dieser Logik über Activity und Fragment führt zu Inline-Duplikaten und Fehlern. Laut Google I/O 2019 reduziert die Zentralisierung der Berechtigungsverarbeitung die Anzahl der Permission-Denial-bezogenen Fehler um durchschnittlich 60 Prozent.
Ein guter Permission Handler bietet eine saubere Schnittstelle für den aufrufenden Code. Activity oder Fragment müssen die Details der Anfrage nicht kennen — sie rufen eine Methode wie requestCamera(callback) auf, und der Handler selbst verwaltet die Statusprüfung, Rationale-Anzeige, den Systemdialog-Aufruf und die Übergabe des Ergebnisses an den Callback. Dies implementiert das Prinzip der einzigen Verantwortung und trennt die Geschäftslogik vom Plattform-Berechtigungscode.
Ein Permission Handler wird notwendig, wenn eine Anwendung 3 oder mehr gefährliche Berechtigungen verwendet. Für einfache Anwendungen mit einer Berechtigung (z. B. Kamera für einen QR-Code-Scanner) kann ein direkter Aufruf ausreichen. Aber für eine typische mobile Anwendung mit Kamera, Geolokalisierung, Benachrichtigungen und Speicher ist ein zentralisierter Handler für die Wartbarkeit unerlässlich.
Ein typischer Permission Handler besteht aus drei Schichten: einem Schnittstellenvertrag, einer Implementierung mit ActivityResultLauncher und einer ViewModel-Schicht. Die Schnittstelle definiert Anforderungsmethoden für jede Berechtigung — requestCamera, requestLocation, requestStorage. Die Implementierung bindet diese Methoden an die entsprechenden ActivityResultContracts.RequestPermission-Verträge.
Wichtige Architekturkomponenten:
Diese Architektur ermöglicht einen einfachen Austausch der Implementierungen in Tests: Anstelle eines echten ActivityResultLauncher wird ein Mock verwendet, der ein vordefiniertes Ergebnis ohne Systeminteraktion zurückgibt. Dies ist entscheidend für Unit-Tests der UI-Logik, bei denen das Starten einer Activity für einen Berechtigungsdialog unmöglich ist.
Der Permission Handler muss den Lebenszyklus von Activity und Fragment berücksichtigen. Launcher werden im ActivityResultRegistry registriert, das den Zustand bei Bildschirmdrehung und Neuerstellung der Activity automatisch speichert und wiederherstellt. Der Handler sollte keine direkten Referenzen auf Activity oder Fragment speichern — verwenden Sie stattdessen WeakReference oder übergeben Sie das Registry über den Konstruktor. Dies verhindert Speicherlecks und Abstürze bei Konfigurationsänderungen.
Eine grundlegende Implementierung eines Permission Handler basiert auf ActivityResultContracts.RequestPermission. Der Handler empfängt das ActivityResultRegistry von ComponentActivity oder Fragment und registriert Launcher für jede Berechtigung. Jeder Launcher akzeptiert einen Callback-Lambda, der nach der Antwort des Benutzers aufgerufen wird.
sealed class PermissionResult {
object GRANTED : PermissionResult()
data class DENIED(
val shouldShowRationale: Boolean
) : PermissionResult()
}
interface PermissionHandler {
fun requestCamera(
callback: (PermissionResult) -> Unit
)
fun requestLocation(
callback: (PermissionResult) -> Unit
)
fun isPermissionGranted(
permission: String
): Boolean
}
class AndroidPermissionHandler(
private val registry: ActivityResultRegistry,
private val context: Context
) : PermissionHandler {
private var cameraLauncher: ActivityResultLauncher<String>? = null
fun initialize() {
cameraLauncher = registry.register(
"camera_permission",
ActivityResultContracts.RequestPermission()
) { isGranted ->
if (isGranted) {
pendingCameraCallback?.invoke(
PermissionResult.GRANTED
)
} else {
val rationale = ActivityCompat.shouldShowRequestPermissionRationale(
context as Activity,
Manifest.permission.CAMERA
)
pendingCameraCallback?.invoke(
PermissionResult.DENIED(rationale)
)
}
}
}
private var pendingCameraCallback:
((PermissionResult) -> Unit)? = null
override fun requestCamera(
callback: (PermissionResult) -> Unit
) {
if (isPermissionGranted(
Manifest.permission.CAMERA
)) {
callback.invoke(PermissionResult.GRANTED)
return
}
pendingCameraCallback = callback
cameraLauncher?.launch(
Manifest.permission.CAMERA
)
}
override fun isPermissionGranted(
permission: String
): Boolean {
return ContextCompat.checkSelfPermission(
context, permission
) == PackageManager.PERMISSION_GRANTED
}
}
Der Handler wird im onCreate der Activity über registerForActivityResult initialisiert, das Zugriff auf das ActivityResultRegistry bietet. Nach der Initialisierung ist der Handler bereit, Anfragen während des gesamten Activity-Lebenszyklus zu verarbeiten. Es ist wichtig, initialize vor der ersten Anfrage aufzurufen, sonst wird der Launcher nicht registriert.
Integration eines Permission Handler mit ViewModel ist der fortschrittlichste Ansatz. Das ViewModel verwaltet den Zustand der Anfragen, während der Handler nur Plattformaufrufe durchführt. Das ViewModel enthält StateFlow<PermissionUiState>, wobei UiState beschreibt, welche Berechtigung angefordert wird und welches Ergebnis empfangen wurde. Die Activity abonniert dieses StateFlow und delegiert die Anfrage an den Handler.
class PermissionsViewModel : ViewModel() {
private val _uiState =
MutableStateFlow<PermissionUiState>(
PermissionUiState.Idle
)
val uiState: StateFlow<PermissionUiState> = _uiState.asStateFlow()
fun onCameraRequested() {
_uiState.value = PermissionUiState.RequestingCamera
}
fun onPermissionResult(
permission: String,
result: PermissionResult
) {
when (result) {
PermissionResult.GRANTED -> {
_uiState.value = PermissionUiState.Granted(permission)
}
is PermissionResult.DENIED -> {
_uiState.value = PermissionUiState.Denied(
permission,
result.shouldShowRationale
)
}
}
}
}
sealed class PermissionUiState {
object Idle : PermissionUiState()
object RequestingCamera : PermissionUiState()
data class Granted(val permission: String) : PermissionUiState()
data class Denied(
val permission: String,
val shouldShowRationale: Boolean
) : PermissionUiState()
}
In diesem Modell prüft die Activity isPermissionGranted über den Handler beim Start, während das ViewModel nur den Zustand verwaltet. Wenn die Berechtigung nicht erteilt wurde — abonniert die Activity uiState, ruft requestCamera vom Handler auf und übergibt das Ergebnis über onPermissionResult zurück an das ViewModel. Die Trennung von Plattformcode und Geschäftslogik ermöglicht das Testen des ViewModel ohne Android-Abhängigkeiten.
Unit-Tests eines Permission Handler sind dank der PermissionHandler-Schnittstelle möglich. In Tests wird ein FakePermissionHandler erstellt, der verschiedene Szenarien simuliert: Berechtigung erteilt, verweigert, Never Ask Again. Jedes Szenario wird unabhängig getestet. Dies ist besonders wichtig für das Testen der UI-Logik, die auf alle drei Ergebnisse korrekt reagieren muss.
class FakePermissionHandler : PermissionHandler {
var cameraResult: PermissionResult =
PermissionResult.GRANTED
var grantedPermissions: Set<String> =
setOf(Manifest.permission.CAMERA)
override fun requestCamera(
callback: (PermissionResult) -> Unit
) {
callback.invoke(cameraResult)
}
override fun isPermissionGranted(
permission: String
): Boolean {
return permission in grantedPermissions
}
}
Die Fake-Implementierung ermöglicht das Testen des ViewModel ohne Emulator. Setzen Sie einfach cameraResult auf den gewünschten Wert und überprüfen Sie, ob das ViewModel seinen UiState korrekt aktualisiert. Integrationstests überprüfen den echten PermissionHandler mit ActivityScenario, aber normalerweise gibt es nur 2-3 solcher Tests pro Anwendung — die restlichen Szenarien werden durch Unit-Tests mit Fakes abgedeckt.
Typische Fehler bei der Arbeit mit Permission Handler umfassen: fehlende Überprüfung von checkSelfPermission vor jedem API-Aufruf, Ignorieren von shouldShowRequestPermissionRationale, erneutes Aufrufen von requestPermissions nach Never Ask Again und Speichern von Launchern ohne Berücksichtigung des Activity-Lebenszyklus. Betrachten wir jedes Problem und seine Lösung.
Der häufigste Fehler ist das Aufrufen einer API ohne Überprüfung des Berechtigungsstatus. Entwickler gehen davon aus, dass eine einmal erteilte Berechtigung für immer bestehen bleibt. Der Benutzer kann sie jedoch jederzeit über die Einstellungen widerrufen. Ein Permission Handler sollte immer isPermissionGranted aufrufen, bevor er eine sensible Operation durchführt. Der zweite häufige Fehler ist das Ignorieren von shouldShowRequestPermissionRationale und das Wiederholen der Anfrage, was im Never-Ask-Again-Modus zu einer sofortigen Verweigerung ohne Dialog führt.
Bewährte Verfahren umfassen: Erstellen einer einzigen Handler-Instanz für den gesamten Activity-Lebenszyklus, Verwenden von SharedFlow zur Übergabe von Ergebnissen an das ViewModel, Protokollieren aller Anfragen und Verweigerungen für Analysen sowie Anzeigen eines benutzerdefinierten Rationale-Dialogs vor dem Systemdialog bei der ersten Verweigerung. Die Befolgung dieser Regeln garantiert eine stabile Berechtigungsverwaltung auf allen Android-Versionen.
Häufig gestellte Fragen
Permission Handler ist eine Komponente zur zentralen Verwaltung von Laufzeitberechtigungen, die checkSelfPermission, requestPermissions und shouldShowRequestPermissionRationale kapselt. Es vereinfacht die Code-Wartung und verbessert das Testen.
Es wird empfohlen, ActivityResultContracts.RequestPermission aus der Bibliothek androidx.activity zu verwenden. Es ersetzt den veralteten onRequestPermissionsResult und bietet eine saubere Callback-API mit einem Boolean-Ergebnis.
Für eine einzelne Berechtigung ist ein Handler nicht zwingend erforderlich — Sie können einen direkten RequestPermission-Launcher-Aufruf in der Activity verwenden. Ein Handler wird bei 3 oder mehr Berechtigungen notwendig, um Code-Duplikate zu vermeiden.
Erstellen Sie eine PermissionHandler-Schnittstelle und deren Fake-Implementierung für Unit-Tests. Der Fake gibt vordefinierte Ergebnisse ohne Systemaufrufe zurück. Dies ermöglicht das Testen von ViewModel und UI-Logik ohne Emulator.
Überprüfen Sie nach der Verweigerung shouldShowRequestPermissionRationale. Wenn die Methode false zurückgibt — ist der Never-Ask-Again-Modus aktiv. Der Handler sollte PermissionResult.DENIED(false) zurückgeben, und die UI sollte eine Schaltfläche zum Öffnen der Einstellungen anzeigen.
Zusammenfassung
Wir entwickeln eine mobile Applikation schlüsselfertig
IT Sectr entwickelt seit 2017 iOS- und Android-Apps für Startups und Unternehmen. Wir beraten Sie und schlagen die beste Lösung vor.
Lesen Sie auch