Precyzyjne linki do pasujących identyfikatorów URI

Aby dopasować hierarchiczne identyfikatory URI do wzorców i wyodrębnić argumenty, użyj UriDeepLinkMatcher. Do deserializacji dopasowanych argumentów do klas kluczy używa ona biblioteki kotlinx.serialization.

Aby utworzyć klasę UriDeepLinkMatcher, podaj wzorzec DeepLinkUri i serializator dla odpowiedniego klucza:

W przypadku niehierarchicznych identyfikatorów URI lub schematów niestandardowych (np. tel:) zapoznaj się z artykułem Tworzenie niestandardowych dopasowań precyzyjnych linków.

Obsługiwane wzorce dopasowania

Klasa UriDeepLinkMatcher dopasowuje identyfikatory URI na podstawie 5 komponentów: schematu, autorytetu, ścieżki, zapytania i fragmentu. W sekcjach poniżej znajdziesz opis obsługiwanej składni wzorca, symboli zastępczych argumentów i reguł dopasowania dla każdego komponentu.

Dopasowanie schematu

Jeśli we wzorcu identyfikatora URI nie ma schematu, dopasowywane są zarówno schematy http, jak i https. Aby dopasować konkretny schemat, uwzględnij go we wzorcu. Wyjątkiem jest schemat http we wzorcu, który dopasowuje zarówno identyfikatory URI żądań http, jak i https, natomiast https we wzorcu dopasowuje tylko żądania https.

Wzorzec URI Identyfikator URI żądania Dopasowanie
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

Dopasowanie autorytetu

Klasa UriDeepLinkMatcher wykonuje dokładne dopasowanie autorytetu identyfikatora URI (hosta i opcjonalnego portu) bez uwzględniania wielkości liter. Symbole zastępcze ani symbole wieloznaczne nie są obsługiwane w autorytecie, a argumenty nie są wyodrębniane:

Wzorzec URI Identyfikator URI żądania Dopasowanie
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

Dopasowanie ścieżki

Obsługiwane są te wzorce ścieżek:

Wzorzec URI Identyfikator URI żądania Dopasowanie Wyodrębnione argumenty
www.example.com/users https://www.example.com/users Brak
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: "" (pusty ciąg znaków)
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 Brak
www.example.com/users https://www.example.com/users/ ❌ (ukośnik na końcu tworzy dodatkowy segment) Nie dotyczy

Dopasowanie zapytania

Kolejność parametrów zapytania w identyfikatorze URI żądania nie musi być zgodna z kolejnością w identyfikatorze URI wzorca. Dodatkowo parametry występujące w identyfikatorze URI żądania, ale nie w identyfikatorze URI wzorca, są ignorowane.

Obsługiwane są te wzorce parametrów zapytania:

Wzorzec URI Identyfikator URI żądania Wyodrębnione argumenty
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: "" (pusty ciąg znaków)
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"

Dopasowanie fragmentu

Obsługiwane są te typy wzorców fragmentów:

Wzorzec URI Identyfikator URI żądania Wyodrębnione argumenty
www.example.com/#section1 https://www.example.com/#section1 Brak
www.example.com/#section_{id} https://www.example.com/#section_123 id: "123"
www.example.com/#section_.* https://www.example.com/#section_123 Brak

Obsługiwane typy danych

Klasa UriDeepLinkMatcher obsługuje deserializację argumentów identyfikatora URI do typów prostych, wyliczeń, kolekcji i obiektów niestandardowych. Serializacja dzieli się na 2 kategorie:

  • Serializacja standardowa: używa kotlinx.serialization do deserializacji do:
    • typów prostych (Boolean, Int, Long, Float, Double, Char, Byte, Short) i typu String
    • wyliczeń
    • Set, List lub Array typów prostych, ciągów znaków lub wyliczeń
    • zagnieżdżonych klas @Serializable (których właściwości są spłaszczane do poszczególnych symboli zastępczych identyfikatora URI)
  • Serializacja niestandardowa za pomocą klasy DeepLinkSerializer: konwertuje między pojedynczym typem String a obiektami niestandardowymi, typami zewnętrznymi (np. java.time.LocalDate) lub kolekcjami zdefiniowanymi przez użytkownika.

Serializacja standardowa

Klasa UriDeepLinkMatcher działa od razu w przypadku typów standardowych i spłaszczonych struktur bez konieczności implementowania serializatorów niestandardowych.

Typy proste i ciągi znaków

Klasa UriDeepLinkMatcher automatycznie dekoduje typy proste (Boolean, Int, Long, Float, Double, Char, Byte, Short) i typ String:

Wyliczenia

Wartości wyliczeń są dopasowywane z uwzględnieniem wielkości liter do nazw elementów wyliczenia:

Powtarzające się kolekcje zapytań

Parametry zapytania z powtarzającymi się kluczami (np. ?id=10&id=20) są automatycznie deserializowane do List<T>, Set<T>, lub Array<T>, gdzie T jest typem prostym typem String lub wyliczeniem:

Zagnieżdżone klasy @Serializable

Gdy klasa NavKey zawiera właściwość, której typem jest inna klasa @Serializable, klasa UriDeepLinkMatcher spłaszcza jej właściwości, tak aby każda właściwość klasy zagnieżdżonej była bezpośrednio mapowana na poszczególny parametr identyfikatora URI o tej samej nazwie:

Aby deserializować obiekty niestandardowe (np. Filter(key = "brand", value = "pixel")), typy zewnętrzne (np. java.time.LocalDate) lub ciągi znaków zdefiniowane przez użytkownika (np. wartości rozdzielone przecinkami), rozszerz klasę DeepLinkSerializer<T>.

DeepLinkSerializer<T> jest abstrakcyjną klasą KSerializer<T>, która konwertuje między typem String a typem T:

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

Na przykład rozważ definicje klas Filter i FilterSerializer, które są używane w tych fragmentach kodu:

Pojedyncze obiekty niestandardowe

Aby zdekodować obiekt z pojedynczego ciągu znaków parametru identyfikatora URI (np. ?filter=brand:google), dodaj do właściwości adnotację @Serializable(with = ...):

Obiekty niestandardowe w powtarzających się parametrach zapytania

Aby deserializować powtarzające się parametry zapytania do kolekcji obiektów niestandardowych (List<T>, Set<T>, lub Array<T>), zaimplementuj DeepLinkSerializer<T> dla typu elementu T i dodaj do argumentu typu właściwości adnotację @Serializable(with = ...):

Kolekcje rozdzielone w pojedynczych parametrach

Aby przeanalizować wartości rozdzielone przecinkami lub zdefiniowane przez użytkownika (np. ?ids=1,2,3) do kolekcji, zaimplementuj klasę DeepLinkSerializer dla całego typu kolekcji i dodaj do właściwości adnotację @Serializable(with = ...):

Weryfikacja argumentów i wyniki dopasowania

Klasa UriDeepLinkMatcher rozróżnia niezgodności (zwraca wartość null, aby można było wypróbować inne dopasowania) i nieobsługiwane konfiguracje (zgłasza wyjątek).

Niezgodności

Niezgodność występuje, gdy przychodzący identyfikator URI żądania nie spełnia wymagań wzorca lub typu:

  • Brak wymaganych parametrów: właściwości klucza, które nie dopuszczają wartości null i nie mają wartości domyślnych , a odpowiadające im parametry identyfikatora URI nie występują w identyfikatorze URI żądania.
  • Błędy analizowania typu: wyodrębnione wartości argumentów, których nie można przeanalizować do oczekiwanego typu właściwości (np. "abc" dla właściwości Int ).

Gdy wystąpi niezgodność, metoda UriDeepLinkMatcher.match zwraca wartość null, co umożliwia ocenę kolejnych dopasowań.

Rozważ klasę klucza i dopasowanie skonfigurowane z wartościami domyślnymi, obiektami zagnieżdżonymi i wyliczeniami:

W tabeli poniżej przedstawiono wyniki dopasowania dla różnych identyfikatorów URI żądań:

Identyfikator URI żądania Wynik dekodowania Wynik dopasowania
https://www.example.com/map/paris?zoom=15&style=dark&layer=SATELLITE Sukces (podano wszystkie parametry) UriMatchResult(MapKey("paris", 15, LayerOptions("dark", MapLayer.SATELLITE)))
https://www.example.com/map/paris?style=dark Sukces (zoom ma domyślną wartość 12, a layerSTANDARD) UriMatchResult(MapKey("paris", 12, LayerOptions("dark", MapLayer.STANDARD)))
https://www.example.com/map/paris?zoom=&style=dark Sukces (pusty opcjonalny parametr zapytania używa domyślnej wartości 12) UriMatchResult(MapKey("paris", 12, LayerOptions("dark", MapLayer.STANDARD)))
https://www.example.com/map?style=dark Niezgodność (brak wymaganego parametru location) null
https://www.example.com/map/paris?zoom=close&style=dark Niezgodność ("close" nie jest typem Int) null
https://www.example.com/map/paris?style=dark&layer=HYBRID Niezgodność ("HYBRID" nie występuje w wyliczeniu) null

Nieobsługiwane konfiguracje

Jeśli klasa klucza zawiera nieobsługiwane typy danych, klasa UriDeepLinkMatcher zgłasza wyjątek podczas dopasowywania zamiast zwracać wartość null.

  • Mapy i kolekcje wielowymiarowe: UriDeepLinkMatcher obsługuje tylko kolekcje jednowymiarowe typów prostych, ciągów znaków, wyliczeń lub typów niestandardowych z adnotacją DeepLinkSerializer. Typy Map zgłaszają wyjątek IllegalArgumentException, a kolekcje zagnieżdżone (np. List<List<String>>) zgłaszają wyjątek SerializationException.
  • Kolekcje obiektów niestandardowych bez adnotacji: kolekcje typów niestandardowych (np. takich jak List<Filter>) zgłaszają wyjątek SerializationException, chyba że typ elementu ma adnotację DeepLinkSerializer.
  • Niespłaszczone klasy zagnieżdżone: klasy zagnieżdżone @Serializable nie mogą być mapowane na pojedynczy symbol zastępczy (np. ?user={user}) bez klasy DeepLinkSerializer.

Porównanie klasy UriMatchResult

UriMatchResult instancje są klasyfikowane według tych kryteriów w podanej kolejności:

  1. Typ MatchResult: UriMatchResult ma wyższą rangę niż inne MatchResult typy.
  2. Dokładna ścieżka: dopasowania literalne ścieżki mają wyższą rangę niż dopasowania symboli zastępczych lub symboli wieloznacznych.
  3. Liczba argumentów ścieżki: dopasowania z większą liczbą argumentów ścieżki mają wyższą rangę.
  4. Obecność argumentów: dopasowania, które przechwytują argumenty, mają wyższą rangę niż te, które tego nie robią.
  5. Łączna liczba argumentów: łączna liczba argumentów (ścieżki, zapytania, fragmentu) jest ostatecznym kryterium rozstrzygającym.

Dostosowywanie klasy UriDeepLinkMatcher

Klasa UriDeepLinkMatcher jest klasą open, której podklasę możesz utworzyć, aby dostosować dopasowywanie identyfikatorów URI i wyodrębnianie argumentów:

  • matchRequest: najwyższy poziom punktu wejścia dopasowania dla przychodzącego DeepLinkRequest. Zastąp tę metodę, aby sprawdzić dodatkowe informacje o żądaniu lub zastosować niestandardowe warunki wstępne przed dopasowaniem identyfikatora URI.
  • matchUri: dopasowuje klasę DeepLinkUri do skonfigurowanego wzorca. Zastąp tę metodę, aby przechwytywać i normalizować przychodzące identyfikatory URI (np. przepisywać dynamiczne subdomeny lub formaty ścieżek starszego typu) przed wywołaniem metody super.matchUri.
  • matchArguments: deserializuje wyodrębnione mapy argumentów ścieżki, zapytania i fragmentu do instancji klucza nawigacji za pomocą podanego serializer. Zastąp tę metodę, aby wstrzykiwać wartości dynamiczne lub przekształcić argumenty przed utworzeniem instancji klucza.

Ten przykład pokazuje, jak utworzyć podklasę klasy UriDeepLinkMatcher, aby normalizować prefiksy ścieżek adresów URL starszego typu przed dopasowaniem: