Deep-Link-Architektur
Deep Links verbinden externe Einstiegspunkte sicher mit internen Navigationszielen. Du lernst, wie du Routen validierst und Destinations korrekt abbildest.
Deep Links sind mehr als nur URLs – sie sind Verträge zwischen deiner App und der Außenwelt. Wenn ein Nutzer auf einen Link in einer E-Mail, einer Push-Benachrichtigung oder einer anderen App tippt, erwartet er, direkt auf dem richtigen Bildschirm zu landen. Damit das zuverlässig und sicher funktioniert, brauchst du eine durchdachte Deep-Link-Architektur: eine klare Strategie, wie externe Einstiegspunkte auf interne Navigationsziele abgebildet, validiert und verarbeitet werden.
Was ist das?
Deep-Link-Architektur beschreibt das System, mit dem eine Android-App eingehende URIs empfängt, auswertet und den Nutzer an die richtige Destination weiterleitet. Im Android-Ökosystem gibt es drei Spielarten:
- Custom-Scheme-Links (
myapp://detail/42) werden ausschließlich von deiner App verarbeitet. Ihr Nachteil: Jede andere App kann dasselbe Schema registrieren und Intents abfangen – sogenanntes Schema-Hijacking. - HTTP/HTTPS App Links (
https://example.com/detail/42) sind verifiziert. Android prüft eineassetlinks.json-Datei auf deinem Server und leitet den Link nur dann ohne Rückfrage an deine App weiter, wenn die Signatur übereinstimmt. - Implizite Intents mit allgemeinen URI-Mustern sind am wenigsten restriktiv und eignen sich für interne Navigation zwischen Modulen.
Die Architektur legt fest, welche dieser Varianten du verwendest, wie die URIs in Argumente zerlegt werden und wer für die Validierung der eingehenden Daten zuständig ist. Im Sinne der offiziellen Android-Architekturempfehlungen gehört diese Logik nicht in die UI-Schicht, sondern wird so früh wie möglich an das ViewModel übergeben, das seinerseits das Repository befragt.
Wie funktioniert es?
Das Jetpack Navigation-Component ist der zentrale Baustein. Es bietet zwei Mechanismen, um Deep Links zu verarbeiten.
Deklarative Deep Links im NavGraph
Für jede Destination im NavGraph kannst du einen oder mehrere deepLink-Einträge registrieren. In Compose geschieht das direkt im composable-Builder:
composable(
route = "detail/{itemId}",
deepLinks = listOf(
navDeepLink {
uriPattern = "https://example.com/detail/{itemId}"
}
)
) { backStackEntry ->
val itemId = backStackEntry.arguments?.getString("itemId")
?: return@composable
DetailScreen(itemId = itemId)
}
Android extrahiert den itemId-Pfad-Parameter automatisch aus der URL und übergibt ihn als Navigation-Argument. Das System übernimmt das URI-Parsing – du musst die URL nicht manuell zerlegen.
Explizite Deep Links aus dem Code
Willst du einen Deep Link programmatisch auslösen – etwa aus einer Push-Notification –, nutzt du NavDeepLinkBuilder:
val pendingIntent = NavDeepLinkBuilder(context)
.setGraph(R.navigation.nav_graph)
.setDestination(R.id.detailFragment)
.setArguments(bundleOf("itemId" to "42"))
.createPendingIntent()
Der entscheidende Vorteil: NavDeepLinkBuilder konstruiert automatisch einen synthetischen Back-Stack. Der Nutzer kann nach dem Öffnen des Deep Links normal zurücknavigieren, ohne die App zu verlassen.
Validierung der Argumente
Navigation-Argumente sind Nutzereingaben von außen und müssen behandelt werden wie alle anderen externen Daten. Prüfe mindestens drei Dimensionen:
- Typ: Ist die ID tatsächlich ein Integer oder eine gültige UUID?
- Bereich: Liegt der Wert in einem plausiblen Bereich, oder handelt es sich um einen offensichtlich manipulierten Wert?
- Autorisierung: Hat der aktuell angemeldete Nutzer Zugriff auf die angeforderte Ressource?
In der Praxis
Typische Stolperfalle: Fehlender Back-Stack
Der häufigste Fehler bei Deep Links ist das direkte Navigieren ohne synthetischen Back-Stack. Öffnet ein Nutzer die App über einen Deep Link, landet er auf der Detailseite. Tippt er „Zurück”, verlässt er die App, anstatt zur Listenansicht zu gelangen. Das Ergebnis ist eine verwirrende UX, die Nutzerbewertungen kostet.
Lösung: Verwende immer NavDeepLinkBuilder für programmatische Deep Links oder stelle sicher, dass dein NavGraph eine startDestination definiert, die den Stack sinnvoll füllt, bevor die Ziel-Destination aufgerufen wird.
Validierung im ViewModel
class DetailViewModel(
savedStateHandle: SavedStateHandle
) : ViewModel() {
val itemId: String = checkNotNull(savedStateHandle["itemId"]) {
"itemId fehlt im SavedStateHandle"
}
init {
require(itemId.isNotBlank()) { "itemId darf nicht leer sein" }
}
}
SavedStateHandle ist die empfohlene Methode, um Navigation-Argumente ins ViewModel zu übergeben – sie überlebt Prozess-Neustarts und ist durch das Navigation-Component direkt befüllt. Greife niemals direkt über Intent.data auf URL-Parameter zu, wenn du Navigation-Component verwendest; das umgeht die Typ-Sicherheit des NavGraphs.
App-Link-Verifikation nicht vergessen
Für verifizierte HTTPS App Links sind zwei Schritte zwingend:
- Den
intent-filterin derAndroidManifest.xmlmitandroid:autoVerify="true"konfigurieren. - Eine gültige
assetlinks.json-Datei unterhttps://example.com/.well-known/assetlinks.jsonbereitstellen, die den SHA-256-Fingerabdruck deines Signing-Zertifikats enthält.
Fehlt die Verifikation oder stimmt der Fingerabdruck nicht, zeigt Android einen Auswahldialog. Nutzer können dann eine andere App wählen oder den Link im Browser öffnen – die nahtlose Navigation in deine App ist damit gebrochen.
Fazit
Deep-Link-Architektur ist der Brückenbau zwischen der Außenwelt und deiner internen Navigationslogik. Du hast gesehen, wie der NavGraph Destinations mit URI-Mustern verknüpft, wie NavDeepLinkBuilder einen korrekten Back-Stack aufbaut und warum Validierung kein optionaler Schritt ist. Um dein Verständnis zu festigen, öffne ein bestehendes Projekt und prüfe: Welche Destinations haben Deep Links registriert? Werden die URL-Parameter im ViewModel validiert, bevor sie das Repository erreichen? Schreibe anschließend einen Instrumented Test, der einen Deep-Link-Intent feuert und überprüft, dass die richtige Destination mit den korrekten Argumenten geladen wird – das ist der verlässlichste Weg, Regressions frühzeitig zu erkennen.