Deeplinks mit übereinstimmenden URIs

Verwenden Sie UriDeepLinkMatcher, um hierarchische URIs mit Mustern abzugleichen und Argumente zu extrahieren. Es verwendet kotlinx.serialization, um übereinstimmende Argumente in Ihre Schlüsselklassen zu deserialisieren.

Wenn Sie einen UriDeepLinkMatcher erstellen möchten, geben Sie ein Muster DeepLinkUri und den Serializer für den entsprechenden Schlüssel an:

Informationen zu nicht hierarchischen URIs oder benutzerdefinierten Schemas (z. B. tel:) finden Sie unter Benutzerdefinierte Deeplink-Matcher erstellen.

Unterstützte Abgleichsmuster

UriDeepLinkMatcher gleicht URIs anhand ihrer fünf Komponenten ab: Schema, Authority, Pfad, Abfrage und Fragment. In den folgenden Abschnitten werden die unterstützte Mustersyntax, die Argumentplatzhalter und die Abgleichsregeln für die einzelnen Komponenten beschrieben.

Schemaabgleich

Wenn im URI-Muster kein Schema vorhanden ist, werden sowohl http als auch https abgeglichen. Wenn Sie ein bestimmtes Schema abgleichen möchten, fügen Sie es in das Muster ein. Als Ausnahme gilt, dass ein http-Schema in einem Muster sowohl mit http- als auch mit https-Anfrage-URIs übereinstimmt, während https in einem Muster nur mit https-Anfragen übereinstimmt.

Muster-URI Anfrage-URI Übereinstimmung
www.example.com https://www.example.com ✅
www.example.com http://www.example.com ✅
http://www.example.com http://www.example.com ✅
http://www.example.com https://www.example.com ✅
https://www.example.com http://www.example.com ❌
myapp://www.example.com myapp://www.example.com ✅

Abgleich der Zertifizierungsstelle

UriDeepLinkMatcher führt einen genauen Abgleich der URI-Autorität (Host und optionaler Port) ohne Berücksichtigung der Groß-/Kleinschreibung durch. Platzhalter werden in der Authority nicht unterstützt und es werden keine Argumente extrahiert:

Muster-URI Anfrage-URI Übereinstimmung
example.com https://example.com ✅
example.com https://EXAMPLE.COM ✅
example.com https://sub.example.com ❌
example.com https://www.example.com ❌
example.com https://example.com:8080 ❌
example.com:8080 https://example.com:8080 ✅
example.com:8080 https://example.com ❌

Pfadabgleich

Die folgenden Pfadmuster werden unterstützt:

Muster-URI Anfrage-URI Übereinstimmung Extrahierte Argumente
www.example.com/users https://www.example.com/users ✅ Keine
www.example.com/users/{id} https://www.example.com/users/123 ✅ id: "123"
www.example.com/users/{first}-{last} https://www.example.com/users/john-doe ✅ first: "john", last: "doe"
www.example.com/users/{id}/profile https://www.example.com/users//profile ✅ id: "" (leerer String)
www.example.com/users/user_{id} https://www.example.com/users/user_123 ✅ id: "123"
www.example.com/users/{userId}/posts/{postId} https://www.example.com/users/123/posts/456 ✅ userId: "123", postId: "456"
www.example.com/users/.* https://www.example.com/users/john-doe ✅ Keine
www.example.com/users https://www.example.com/users/ ❌ (Der abschließende Schrägstrich erstellt ein zusätzliches Segment) –

Query-Matching

Die Reihenfolge der Suchparameter im Anfrage-URI muss nicht mit der Reihenfolge im Muster-URI übereinstimmen. Außerdem werden Parameter ignoriert, die im Anfrage-URI, aber nicht im Muster-URI vorhanden sind.

Die folgenden Suchparametermuster werden unterstützt:

Muster-URI Anfrage-URI Extrahierte Argumente
www.example.com/users?name={name} https://www.example.com/users?name=john name: "john"
www.example.com/users?name={name} https://www.example.com/users?name= name: "" (leerer String)
www.example.com/users?{rawQuery} https://www.example.com/users?anything&else rawQuery: ["anything", "else"]
www.example.com/users?type=user_{id} https://www.example.com/users?type=user_123 id: "123"
www.example.com/users?name={first}_{last} https://www.example.com/users?name=john_doe first: "john", last: "doe"
www.example.com/users?list={list} https://www.example.com/users?list=10&list=20 list: ["10", "20"]
www.example.com/users?name={name}&{other} https://www.example.com/users?name=john&tab=info name: "john", other: ["tab=info"]
www.example.com/users?type=user_.* https://www.example.com/users?type=user_admin type: "admin"

Fragmentabgleich

Die folgenden Fragmentmustertypen werden unterstützt:

Muster-URI Anfrage-URI Extrahierte Argumente
www.example.com/#section1 https://www.example.com/#section1 Keine
www.example.com/#section_{id} https://www.example.com/#section_123 id: "123"
www.example.com/#section_.* https://www.example.com/#section_123 Keine

Unterstützte Datentypen

UriDeepLinkMatcher unterstützt die Deserialisierung von URI-Argumenten in primitive Typen, Enums, Sammlungen und benutzerdefinierte Objekte. Die Serialisierung lässt sich in zwei Kategorien unterteilen:

  • Standardserialisierung: Verwendet kotlinx.serialization für die Deserialisierung in:
    • Primitive Typen (Boolean, Int, Long, Float, Double, Char, Byte, Short) und String
    • Enums
    • Set, List oder Array von Primitiven, Strings oder Enums
    • Verschachtelte @Serializable-Klassen (deren Attribute in einzelne URI-Platzhalter vereinfacht werden)
  • Benutzerdefinierte Serialisierung mit DeepLinkSerializer: Konvertiert zwischen einem einzelnen String und benutzerdefinierten Objekten, externen Typen (z. B. java.time.LocalDate) oder benutzerdefinierten Sammlungen.

Standardserialisierung

UriDeepLinkMatcher funktioniert sofort für Standardtypen und vereinfachte Strukturen, ohne dass benutzerdefinierte Serializer-Implementierungen erforderlich sind.

Primitive und Strings

UriDeepLinkMatcher decodiert automatisch primitive Typen (Boolean, Int, Long, Float, Double, Char, Byte, Short) und String:

Enums

Enum-Werte werden unter Berücksichtigung der Groß-/Kleinschreibung mit den Namen der Enum-Elemente abgeglichen:

Wiederholte Abfragesammlungen

Suchparameter mit wiederholten Schlüsseln (z. B. ?id=10&id=20) werden automatisch in List<T>, Set<T> oder Array<T> deserialisiert, wobei T ein primitiver Typ, String oder ein Enum ist:

Verschachtelte @Serializable-Klassen

Wenn ein NavKey ein Attribut enthält, dessen Typ eine andere @Serializable-Klasse ist, werden die Attribute von UriDeepLinkMatcher vereinfacht, sodass jedes Attribut der verschachtelten Klasse direkt einem einzelnen URI-Parameter mit demselben Namen zugeordnet wird:

Wenn Sie benutzerdefinierte Objekte (z. B. Filter(key = "brand", value = "pixel")), externe Typen (z. B. java.time.LocalDate) oder benutzerdefinierte Strings mit Trennzeichen (z. B. CSV) deserialisieren möchten, erweitern Sie DeepLinkSerializer<T>.

DeepLinkSerializer<T> ist eine abstrakte KSerializer<T>, die zwischen String und T konvertiert:

abstract class DeepLinkSerializer<T : Any> : KSerializer<T> {
    abstract val serialName: String
    abstract fun deserialize(value: String): T
    abstract fun serialize(value: T): String
}

Sehen wir uns zum Beispiel die Definitionen von Filter und FilterSerializer an, die in den folgenden Snippets verwendet werden:

Einzelne benutzerdefinierte Objekte

Wenn Sie ein Objekt aus einem einzelnen URI-Parameterstring (z. B. ?filter=brand:google) decodieren möchten, annotieren Sie das Attribut mit @Serializable(with = ...):

Benutzerdefinierte Objekte in wiederholten Abfrageparametern

Wenn Sie wiederholte Suchparameter in eine Sammlung benutzerdefinierter Objekte (List<T>, Set<T> oder Array<T>) deserialisieren möchten, implementieren Sie DeepLinkSerializer<T> für den Elementtyp T und annotieren Sie das Typargument des Attributs mit @Serializable(with = ...):

Durch Trennzeichen getrennte Sammlungen in einzelnen Parametern

Wenn Sie kommagetrennte oder benutzerdefinierte Werte (z. B. ?ids=1,2,3) in eine Sammlung parsen möchten, implementieren Sie DeepLinkSerializer für den gesamten Sammlungstyp und annotieren Sie das Attribut mit @Serializable(with = ...):

Argumentvalidierung und Abgleichsergebnisse

UriDeepLinkMatcher unterscheidet zwischen Nichtübereinstimmungen (gibt null zurück, sodass andere Abgleiche versucht werden können) und nicht unterstützten Konfigurationen (löst eine Ausnahme aus).

Abweichungen

Eine Nichtübereinstimmung tritt auf, wenn ein eingehender Anfrage-URI die Muster- oder Typanforderungen nicht erfüllt:

  • Fehlende erforderliche Parameter: Nicht-nullable Schlüsselattribute ohne Standardwerte, deren entsprechende URI-Parameter in der Anfrage-URI fehlen.
  • Fehler beim Parsen von Typen: Extrahierte Argumentwerte, die nicht in den erwarteten Attributtyp geparst werden können (z. B. "abc" für ein Int-Attribut).

Wenn eine Abweichung auftritt, gibt UriDeepLinkMatcher.match den Wert null zurück, sodass nachfolgende Abgleiche ausgewertet werden können.

Betrachten Sie eine Schlüsselklasse und einen Matcher, die mit Standardwerten, verschachtelten Objekten und Enums konfiguriert sind:

In der folgenden Tabelle sind die Übereinstimmungsergebnisse für verschiedene Anfrage-URIs aufgeführt:

Anfrage-URI Decodierungsergebnis Spielergebnis
https://www.example.com/map/paris?zoom=15&style=dark&layer=SATELLITE Erfolg (alle Parameter angegeben) UriMatchResult(MapKey("paris", 15, LayerOptions("dark", MapLayer.SATELLITE)))
https://www.example.com/map/paris?style=dark Success (zoom ist standardmäßig 12, layer ist standardmäßig STANDARD) UriMatchResult(MapKey("paris", 12, LayerOptions("dark", MapLayer.STANDARD)))
https://www.example.com/map/paris?zoom=&style=dark Erfolg (Für den leeren optionalen Suchparameter wird der Standardwert 12 verwendet) UriMatchResult(MapKey("paris", 12, LayerOptions("dark", MapLayer.STANDARD)))
https://www.example.com/map?style=dark Abweichung (Erforderlicher Parameter location fehlt) null
https://www.example.com/map/paris?zoom=close&style=dark Abweichung ("close" ist kein Int) null
https://www.example.com/map/paris?style=dark&layer=HYBRID Keine Übereinstimmung ("HYBRID" ist nicht in der Aufzählung enthalten) null

Nicht unterstützte Konfigurationen

Wenn Ihre Schlüsselklasse nicht unterstützte Datentypen enthält, löst UriDeepLinkMatcher während des Abgleichs eine Ausnahme aus, anstatt null zurückzugeben.

  • Maps und mehrdimensionale Sammlungen: UriDeepLinkMatcher unterstützt nur eindimensionale Sammlungen von Primitiven, Strings, Enums oder benutzerdefinierten Typen, die mit einem DeepLinkSerializer annotiert sind. Map-Typen lösen einen IllegalArgumentException aus, während verschachtelte Sammlungen (z. B. List<List<String>>) einen SerializationException auslösen.
  • Nicht annotierte benutzerdefinierte Objektsammlungen: Sammlungen benutzerdefinierter Typen (z. B. List<Filter>) lösen eine SerializationException aus, es sei denn, der Elementtyp ist mit einer DeepLinkSerializer annotiert.
  • Nicht vereinfachte verschachtelte Klassen: Verschachtelte @Serializable-Klassen können ohne DeepLinkSerializer nicht einem einzelnen Platzhalter (z. B. ?user={user}) zugeordnet werden.

UriMatchResult – Vergleich

UriMatchResult-Instanzen werden anhand der folgenden Kriterien in der angegebenen Reihenfolge bewertet:

  1. MatchResult-Typ: UriMatchResult hat einen höheren Rang als andere MatchResult-Typen.
  2. Genauer Pfad: Literale Pfadübereinstimmungen werden höher eingestuft als Platzhalter- oder Platzhalterübereinstimmungen.
  3. Anzahl der Pfadargumente: Übereinstimmungen mit mehr Pfadargumenten werden höher eingestuft.
  4. Vorhandensein von Argumenten: Übereinstimmungen, die Argumente erfassen, werden höher eingestuft als solche, die dies nicht tun.
  5. Gesamtanzahl der Argumente: Die Gesamtzahl der Argumente (Pfad, Abfrage, Fragment) ist das letzte Kriterium.

UriDeepLinkMatcher anpassen

UriDeepLinkMatcher ist eine open-Klasse, die Sie als Unterklasse verwenden können, um das Verhalten für den URI-Abgleich und die Argumentextraktion anzupassen:

  • matchRequest: Übereinstimmender Einstiegspunkt auf oberster Ebene für eine eingehende DeepLinkRequest. Überschreiben Sie dies, um Anfrage-Extras zu prüfen oder benutzerdefinierte Vorbedingungen vor dem URI-Abgleich anzuwenden.
  • matchUri: Gleicht den DeepLinkUri mit dem konfigurierten Muster ab. Überschreiben Sie dies, um eingehende URIs abzufangen und zu normalisieren (z. B. dynamische Subdomains oder Legacy-Pfadformate neu zu schreiben), bevor Sie super.matchUri aufrufen.
  • matchArguments: Deserialisiert die extrahierten Pfad-, Abfrage- und Fragmentargumentzuordnungen mithilfe des angegebenen serializer in eine Navigationsschlüsselinstanz. Überschreiben Sie dies, um dynamische Werte einzufügen oder Argumente vor der Schlüsselinstanziierung zu transformieren.

Im folgenden Beispiel wird gezeigt, wie Sie eine abgeleitete Klasse von UriDeepLinkMatcher erstellen, um Legacy-URL-Pfadpräfixe vor dem Abgleich zu normalisieren: