Link diretti URI corrispondenti

Per confrontare gli URI gerarchici con i pattern ed estrarre gli 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 (come tel:), consulta Crea matcher di deep link personalizzati.

Pattern di corrispondenza supportati

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

Corrispondenza dello schema

Se nel pattern URI non è presente alcuno schema, vengono trovate corrispondenze sia per http sia per https. Per trovare una corrispondenza con uno schema specifico, includilo nel pattern. In via eccezionale, uno schema http in un pattern corrisponde sia agli URI della richiesta http sia a quelli https, mentre https in un pattern corrisponde solo alle richieste https.

Pattern URI 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 con l'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:

Pattern URI 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 percorso

Sono supportati i seguenti pattern di percorso:

Pattern URI 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/ ❌ (lo slash 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:

Pattern URI 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 dei frammenti

Sono supportati i seguenti tipi di pattern di frammenti:

Pattern URI 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 si divide in due categorie:

  • Serializzazione standard: utilizza kotlinx.serialization per la deserializzazione in:
    • Primitive (Boolean, Int, Long, Float, Double, Char, Byte, Short) e String
    • Enum
    • Set, List o Array di primitive, stringhe o enum
    • Classi @Serializable nidificate (le cui proprietà sono appiattite in singoli segnaposto URI)
  • Serializzazione personalizzata con DeepLinkSerializer: esegue la conversione tra un singolo String e oggetti personalizzati, tipi esterni (come java.time.LocalDate) o raccolte delimitate personalizzate.

Serializzazione standard

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

Primitive e stringhe

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

Enum

I valori enum vengono confrontati con i nomi degli elementi enum facendo distinzione tra maiuscole e minuscole:

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 appiattisce le sue 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 (come Filter(key = "brand", value = "pixel")), tipi esterni (come java.time.LocalDate) o stringhe delimitate personalizzate (come valori separati da virgole), estendi DeepLinkSerializer<T>.

DeepLinkSerializer<T> è un KSerializer<T> astratto che esegue la conversione tra 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 nei seguenti snippet:

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 del tipo della proprietà con @Serializable(with = ...):

Raccolte delimitate in singoli parametri

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

Risultati della convalida e della corrispondenza degli argomenti

UriDeepLinkMatcher distingue tra mancate corrispondenze (restituisce null in modo che sia possibile provare altri matcher) e configurazioni non supportate (genera un'eccezione).

Mancate corrispondenze

Si verifica una mancata corrispondenza quando l'URI di una richiesta in entrata non soddisfa i requisiti del pattern o del tipo:

  • Mancano parametri obbligatori: proprietà chiave non nullable senza valori predefiniti i cui parametri URI corrispondenti sono assenti dall'URI della richiesta.
  • Errori di analisi del tipo: 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 di chiavi e un matcher configurati con valori predefiniti, oggetti nidificati ed enum:

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

URI della richiesta Risultato della decodifica Risultato della corrispondenza
https://www.example.com/map/paris?zoom=15&style=dark&layer=SATELLITE Success (tutti i parametri forniti) UriMatchResult(MapKey("paris", 15, LayerOptions("dark", MapLayer.SATELLITE)))
https://www.example.com/map/paris?style=dark Success (zoom il valore predefinito è 12, layer è STANDARD) UriMatchResult(MapKey("paris", 12, LayerOptions("dark", MapLayer.STANDARD)))
https://www.example.com/map/paris?zoom=&style=dark Successo (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 della 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 primitive, stringhe, enum o tipi personalizzati annotati con un DeepLinkSerializer. Map generano un IllegalArgumentException, mentre le raccolte nidificate (come List<List<String>>) generano un SerializationException.
  • Raccolte di oggetti personalizzati non annotati: le raccolte di tipi personalizzati (come 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 nidificate non possono essere mappate a un singolo segnaposto (come ?user={user}) senza un DeepLinkSerializer.

Confronto UriMatchResult

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

  1. Tipo MatchResult: UriMatchResult ha un ranking più alto rispetto ad altri tipi di MatchResult.
  2. Percorso esatto: le corrispondenze dei percorsi letterali hanno un ranking più alto rispetto alle corrispondenze dei segnaposto o dei caratteri jolly.
  3. Numero di argomenti del percorso: le corrispondenze con più argomenti del percorso hanno un ranking più elevato.
  4. Presenza di argomenti: le corrispondenze che acquisiscono argomenti hanno un ranking più elevato 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.

Personalizza UriDeepLinkMatcher

UriDeepLinkMatcher è una classe open che puoi sottoclassare per personalizzare il comportamento di corrispondenza degli URI e di estrazione degli argomenti:

  • matchRequest: entry point di corrispondenza di primo livello per un DeepLinkRequest in entrata. Esegui l'override di questo metodo per ispezionare gli extra della richiesta o applicare precondizioni personalizzate prima della corrispondenza dell'URI.
  • matchUri: confronta 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 dei percorsi legacy) prima di chiamare super.matchUri.
  • matchArguments: deserializza le mappe degli argomenti di percorso, query e frammento estratti in un'istanza della chiave di navigazione utilizzando l'oggetto serializer fornito. Esegui l'override di questo metodo per inserire valori dinamici o trasformare gli argomenti prima della creazione dell'istanza della chiave.

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