Link diretti URI corrispondenti

Per la corrispondenza degli URI gerarchici con i pattern e l'estrazione degli argomenti, utilizza UriDeepLinkMatcher. Si basa su kotlinx.serialization per deserializzare gli argomenti corrispondenti nelle classi chiave.

Per creare un UriDeepLinkMatcher, fornisci un pattern DeepLinkUri e il serializzatore per la chiave corrispondente:

Per gli URI non gerarchici o gli schemi personalizzati (ad esempio tel:), consulta Creare matcher di link diretti personalizzati.

Pattern di corrispondenza supportati

UriDeepLinkMatcher mette in corrispondenza gli URI in base ai cinque componenti: schema, autorità, percorso, query e frammento. Le sezioni seguenti descrivono la sintassi dei pattern supportata, i segnaposto degli argomenti e le regole di corrispondenza per ogni componente.

Corrispondenza dello schema

Se nel pattern URI non è presente alcuno schema, vengono messi in corrispondenza sia http sia https. Per mettere in corrispondenza uno schema specifico, includilo nel pattern. Come eccezione, uno schema http in un pattern mette in corrispondenza gli URI delle richieste http e https, mentre https in un pattern mette in corrispondenza solo le richieste https.

URI del pattern URI della richiesta Corrispondenza
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

Corrispondenza dell'autorità

UriDeepLinkMatcher esegue una corrispondenza esatta senza distinzione tra maiuscole e minuscole sull'autorità URI (host e porta facoltativa). I segnaposto o i caratteri jolly non sono supportati nell'autorità e non vengono estratti argomenti:

URI del pattern URI della richiesta Corrispondenza
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

Corrispondenza del percorso

Sono supportati i seguenti pattern di percorso:

URI del pattern URI della richiesta Corrispondenza Argomenti estratti
www.example.com/users https://www.example.com/users Nessuno
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: "" (stringa vuota)
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 Nessuno
www.example.com/users https://www.example.com/users/ ❌ (la barra finale crea un segmento aggiuntivo) N/D

Corrispondenza della query

L'ordine dei parametri di query nell'URI della richiesta non deve corrispondere all'ordine nell'URI del pattern. Inoltre, i parametri presenti nell'URI della richiesta ma non nell'URI del pattern vengono ignorati.

Sono supportati i seguenti pattern di parametri di query:

URI del pattern URI della richiesta Argomenti estratti
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: "" (stringa vuota)
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"

Corrispondenza del frammento

Sono supportati i seguenti tipi di pattern di frammenti:

URI del pattern URI della richiesta Argomenti estratti
www.example.com/#section1 https://www.example.com/#section1 Nessuno
www.example.com/#section_{id} https://www.example.com/#section_123 id: "123"
www.example.com/#section_.* https://www.example.com/#section_123 Nessuno

Tipi di dati supportati

UriDeepLinkMatcher supporta la deserializzazione degli argomenti URI in tipi primitivi, enum, raccolte e oggetti personalizzati. La serializzazione rientra in due categorie:

  • Serializzazione standard: utilizza kotlinx.serialization per la deserializzazione in:
    • Primitivi (Boolean, Int, Long, Float, Double, Char, Byte, Short) e String
    • Enum
    • Set, List o Array di primitivi, stringhe o enum
    • Classi @Serializable nidificate (le cui proprietà vengono appiattite in singoli segnaposto URI)
  • Serializzazione personalizzata con DeepLinkSerializer: converte tra una singola String e oggetti personalizzati, tipi esterni (ad esempio java.time.LocalDate) o raccolte con delimitatori personalizzati.

Serializzazione standard

UriDeepLinkMatcher funziona immediatamente per i tipi standard e le strutture appiattite senza richiedere implementazioni di serializzatori personalizzati.

Primitivi e stringhe

UriDeepLinkMatcher decodifica automaticamente i tipi primitivi (Boolean, Int, Long, Float, Double, Char, Byte, Short) e String:

Enum

I valori enum vengono messi in corrispondenza con distinzione tra maiuscole e minuscole con i nomi degli elementi enum:

Raccolte di query ripetute

I parametri di query con chiavi ripetute (ad esempio ?id=10&id=20) vengono deserializzati automaticamente in List<T>, Set<T>, o Array<T>, dove T è un tipo primitivo, String, o enum:

Classi @Serializable nidificate

Quando un NavKey contiene una proprietà il cui tipo è un'altra classe @Serializable, UriDeepLinkMatcher ne appiattisce le proprietà in modo che ogni proprietà della classe nidificata venga mappata direttamente a un singolo parametro URI con lo stesso nome:

Per deserializzare oggetti personalizzati (ad esempio Filter(key = "brand", value = "pixel")), tipi esterni (ad esempio java.time.LocalDate) o stringhe con delimitatori personalizzati (ad esempio valori separati da virgole), estendi DeepLinkSerializer<T>.

DeepLinkSerializer<T> è un KSerializer<T> astratto che converte tra una String e T:

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

Ad esempio, considera le definizioni Filter e FilterSerializer utilizzate negli snippet seguenti:

Singoli oggetti personalizzati

Per decodificare un oggetto da una singola stringa di parametri URI (ad esempio ?filter=brand:google), annota la proprietà con @Serializable(with = ...):

Oggetti personalizzati nei parametri di query ripetuti

Per deserializzare i parametri di query ripetuti in una raccolta di oggetti personalizzati (List<T>, Set<T>, o Array<T>), implementa DeepLinkSerializer<T> per il tipo di elemento T e annota l'argomento di tipo della proprietà con @Serializable(with = ...):

Raccolte con delimitatori in singoli parametri

Per analizzare i valori separati da virgole o con delimitatori personalizzati (ad esempio ?ids=1,2,3) in una raccolta, implementa DeepLinkSerializer per l'intero tipo di raccolta e annota la proprietà con @Serializable(with = ...):

Convalida degli argomenti e risultati della corrispondenza

UriDeepLinkMatcher distingue tra mancate corrispondenze (restituisce null in modo che possano essere tentati altri matcher) e configurazioni non supportate (genera un'eccezione).

Mancate corrispondenze

Si verifica una mancata corrispondenza quando un URI della richiesta in entrata non soddisfa i requisiti di pattern o tipo:

  • Parametri obbligatori mancanti: proprietà chiave non nullable senza valori predefiniti i cui parametri URI corrispondenti non sono presenti nell'URI della richiesta.
  • Errori di analisi dei tipi: valori degli argomenti estratti che non possono essere analizzati nel tipo di proprietà previsto (ad esempio, "abc" per una proprietà Int ).

Quando si verifica una mancata corrispondenza, UriDeepLinkMatcher.match restituisce null, consentendo la valutazione dei matcher successivi.

Considera una classe chiave e un matcher configurati con valori predefiniti, oggetti nidificati ed enum:

La tabella seguente mostra i risultati della corrispondenza per vari URI delle richieste:

URI della richiesta Risultato della decodifica Risultato della corrispondenza
https://www.example.com/map/paris?zoom=15&style=dark&layer=SATELLITE Riuscita (tutti i parametri forniti) UriMatchResult(MapKey("paris", 15, LayerOptions("dark", MapLayer.SATELLITE)))
https://www.example.com/map/paris?style=dark Riuscita (zoom ha come valore predefinito 12, layer ha come valore predefinito STANDARD) UriMatchResult(MapKey("paris", 12, LayerOptions("dark", MapLayer.STANDARD)))
https://www.example.com/map/paris?zoom=&style=dark Riuscita (il parametro di query facoltativo vuoto utilizza il valore predefinito 12) UriMatchResult(MapKey("paris", 12, LayerOptions("dark", MapLayer.STANDARD)))
https://www.example.com/map?style=dark Mancata corrispondenza (parametro location obbligatorio mancante) null
https://www.example.com/map/paris?zoom=close&style=dark Mancata corrispondenza ("close" non è un Int) null
https://www.example.com/map/paris?style=dark&layer=HYBRID Mancata corrispondenza ("HYBRID" non è nell'enum) null

Configurazioni non supportate

Se la classe chiave contiene tipi di dati non supportati, UriDeepLinkMatcher genera un'eccezione durante la corrispondenza anziché restituire null.

  • Mappe e raccolte multidimensionali: UriDeepLinkMatcher supporta solo raccolte monodimensionali di primitivi, stringhe, enum o tipi personalizzati annotati con un DeepLinkSerializer. I tipi Map generano un IllegalArgumentException, mentre le raccolte nidificate (ad esempio List<List<String>>) generano un SerializationException.
  • Raccolte di oggetti personalizzati non annotati: le raccolte di tipi personalizzati (ad esempio List<Filter>) generano un SerializationException a meno che il tipo di elemento non sia annotato con un DeepLinkSerializer.
  • Classi nidificate non appiattite: le classi @Serializable non possono essere mappate a un singolo segnaposto (ad esempio ?user={user}) senza un DeepLinkSerializer.

Confronto di UriMatchResult

Le istanze UriMatchResult vengono classificate utilizzando i seguenti criteri in ordine:

  1. Tipo di MatchResult: UriMatchResult ha una classificazione più alta rispetto ad altri MatchResult tipi.
  2. Percorso esatto: le corrispondenze di percorsi letterali hanno una classificazione più alta rispetto alle corrispondenze di segnaposto o caratteri jolly.
  3. Numero di argomenti del percorso: le corrispondenze con più argomenti del percorso hanno una classificazione più alta.
  4. Presenza di argomenti: le corrispondenze che acquisiscono argomenti hanno una classificazione più alta rispetto a quelle che non lo fanno.
  5. Numero totale di argomenti: il numero totale di argomenti (percorso, query, frammento) è l'ultimo criterio di spareggio.

Personalizzare UriDeepLinkMatcher

UriDeepLinkMatcher è una classe open di cui puoi creare una sottoclasse per personalizzare il comportamento di corrispondenza degli URI e di estrazione degli argomenti:

  • matchRequest: punto di ingresso di corrispondenza di primo livello per un DeepLinkRequest in entrata. Esegui l'override di questo metodo per esaminare gli extra della richiesta o applicare precondizioni personalizzate prima della corrispondenza degli URI.
  • matchUri: Mette in corrispondenza DeepLinkUri con il pattern configurato. Esegui l'override di questo metodo per intercettare e normalizzare gli URI in entrata (ad esempio, riscrivendo i sottodomini dinamici o i formati di percorso legacy) prima di chiamare super.matchUri.
  • matchArguments: deserializza le mappe degli argomenti di percorso, query e frammento estratti in un'istanza di chiave di navigazione utilizzando il serializer fornito. Esegui l'override di questo metodo per inserire valori dinamici o trasformare gli argomenti prima dell'istanza della chiave.

L'esempio seguente mostra la creazione di una sottoclasse di UriDeepLinkMatcher per normalizzare i prefissi dei percorsi URL legacy prima della corrispondenza: