Hiyerarşik URI'ları kalıplarla eşleştirmek ve bağımsız değişkenleri ayıklamak için UriDeepLinkMatcher kullanın. Eşleşen bağımsız değişkenleri anahtar sınıflarınıza seri durumdan çıkarmak için kotlinx.serialization kullanılır.
UriDeepLinkMatcher oluşturmak için bir kalıp DeepLinkUri ve ilgili anahtar için serileştirici sağlayın:
@Serializable data class UserProfileKey(val id: String) : NavKey val userProfilePattern = DeepLinkUri("www.example.com/users/{id}") val userProfileMatcher = UriDeepLinkMatcher(userProfilePattern, serializer<UserProfileKey>()) val request = DeepLinkRequest(uri = "https://www.example.com/users/123") val matchResult = userProfileMatcher.match(request) val key = matchResult?.key // UserProfileKey(id = "123")
Hiyerarşik olmayan URI'ler veya özel şemalar (ör. tel:) için Özel derin bağlantı eşleştiriciler oluşturma başlıklı makaleyi inceleyin.
Desteklenen eşleşme kalıpları
UriDeepLinkMatcher, URI'ları beş bileşenine göre eşleştirir: şema, yetki, yol, sorgu ve parça. Aşağıdaki bölümlerde, her bileşen için desteklenen kalıp söz dizimi, bağımsız değişken yer tutucuları ve eşleşme kuralları açıklanmaktadır.
Şema eşleştirme
URI kalıbında şema yoksa hem http hem de https eşleştirilir.
Belirli bir şemayı eşleştirmek için şemayı kalıba dahil edin. İstisna olarak, bir kalıptaki http şeması hem http hem de https istek URI'leriyle eşleşirken kalıptaki https yalnızca https istekleriyle eşleşir.
| Desen URI'si | İstek URI'sı | Eşleşme |
|---|---|---|
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 |
✅ |
Yetki eşleştirme
UriDeepLinkMatcher, URI yetkilisi (ana makine ve isteğe bağlı bağlantı noktası) üzerinde büyük/küçük harfe duyarlı olmayan tam eşleme gerçekleştirir. Yetki bölümünde yer tutucular veya joker karakterler desteklenmez ve bağımsız değişkenler ayıklanmaz:
| Desen URI'si | İstek URI'sı | Eşleşme |
|---|---|---|
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 |
❌ |
Yol eşleştirme
Aşağıdaki yol kalıpları desteklenir:
| Desen URI'si | İstek URI'sı | Eşleşme | Ayıklanan Bağımsız Değişkenler |
|---|---|---|---|
www.example.com/users |
https://www.example.com/users |
✅ | Yok |
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: "" (Boş dize) |
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 |
✅ | Yok |
www.example.com/users |
https://www.example.com/users/ |
❌ (Sondaki eğik çizgi fazladan bir segment oluşturur) | Yok |
Sorgu eşleştirme
İstek URI'sindeki sorgu parametresi sırasının, kalıp URI'sindeki sırayla eşleşmesi gerekmez. Ayrıca, istek URI'sinde bulunan ancak kalıp URI'sinde bulunmayan parametreler yoksayılır.
Aşağıdaki sorgu parametresi kalıpları desteklenir:
| Desen URI'si | İstek URI'sı | Ayıklanan Bağımsız Değişkenler |
|---|---|---|
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: "" (Boş dize) |
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" |
Parça eşleştirme
Aşağıdaki parça deseni türleri desteklenir:
| Desen URI'si | İstek URI'sı | Ayıklanan Bağımsız Değişkenler |
|---|---|---|
www.example.com/#section1 |
https://www.example.com/#section1 |
Yok |
www.example.com/#section_{id} |
https://www.example.com/#section_123 |
id: "123" |
www.example.com/#section_.* |
https://www.example.com/#section_123 |
Yok |
Desteklenen veri türleri
UriDeepLinkMatcher, URI bağımsız değişkenlerinin temel türlere, enum'lara, koleksiyonlara ve özel nesnelere dönüştürülmesini destekler. Serileştirme iki kategoriye ayrılır:
- Standart serileştirme: Şuna seri hale getirmek için
kotlinx.serializationkullanır:- Temel öğeler (
Boolean,Int,Long,Float,Double,Char,Byte,Short) veString - Sıralamalar
- Temel öğeler, dizeler veya enum'lardan oluşan
Set,ListveyaArray - İç içe yerleştirilmiş
@Serializablesınıfları (özellikleri ayrı URI yer tutucularına düzleştirilir)
- Temel öğeler (
DeepLinkSerializerile özel serileştirme: Tek birStringile özel nesneler, harici türler (ör.java.time.LocalDate) veya özel olarak sınırlandırılmış koleksiyonlar arasında dönüşüm gerçekleştirir.
Standart serileştirme
UriDeepLinkMatcher, özel serileştirici uygulamaları gerektirmeden standart türler ve düzleştirilmiş yapılar için kullanıma hazırdır.
Temel öğeler ve dizeler
UriDeepLinkMatcher, temel türlerin (Boolean, Int, Long, Float, Double, Char, Byte, Short) ve String kodunu otomatik olarak çözer:
@Serializable data class UserProfileKey(val id: Int) : NavKey val matcher = UriDeepLinkMatcher( DeepLinkUri("www.example.com/users/{id}"), serializer<UserProfileKey>() ) val request = DeepLinkRequest(uri = "https://www.example.com/users/123") val key = matcher.match(request)?.key // UserProfileKey(id = 123)
Sıralamalar
Enum değerleri, enum öğesi adlarıyla büyük/küçük harfe duyarlı olarak eşleştirilir:
enum class SortOrder { RELEVANCE, DATE, POPULARITY } @Serializable data class ProductsKey(val sort: SortOrder) : NavKey val matcher = UriDeepLinkMatcher( DeepLinkUri("www.example.com/products?sort={sort}"), serializer<ProductsKey>() ) val request = DeepLinkRequest(uri = "https://www.example.com/products?sort=DATE") val key = matcher.match(request)?.key // ProductsKey(sort = SortOrder.DATE)
Tekrarlanan sorgu koleksiyonları
Yinelenen anahtarlar (ör. ?id=10&id=20) içeren sorgu parametreleri otomatik olarak List<T>, Set<T> veya Array<T> şeklinde seri durumdan çıkarılır. Burada T, temel tür, String veya enum'dur:
@Serializable data class FilteredItemsKey(val ids: List<Int>) : NavKey val matcher = UriDeepLinkMatcher( DeepLinkUri("www.example.com/items?id={ids}"), serializer<FilteredItemsKey>() ) val request = DeepLinkRequest(uri = "https://www.example.com/items?id=10&id=20") val key = matcher.match(request)?.key // FilteredItemsKey(ids = listOf(10, 20))
İç içe yerleştirilmiş @Serializable sınıfları
Bir NavKey, türü başka bir @Serializable sınıfı olan bir özellik içerdiğinde UriDeepLinkMatcher, özelliklerini düzleştirir. Böylece iç içe yerleştirilmiş sınıfın her özelliği, aynı ada sahip ayrı bir URI parametresiyle doğrudan eşleşir:
enum class SortOrder { RELEVANCE, DATE, POPULARITY } @Serializable data class SearchFilters( val category: String, val sortBy: SortOrder = SortOrder.RELEVANCE ) @Serializable data class SearchKey( val query: String, val page: Int = 1, // Flattened into {category} and {sortBy} val filters: SearchFilters ) : NavKey val matcher = UriDeepLinkMatcher( DeepLinkUri("www.example.com/search?q={query}&page={page}&category={category}&sortBy={sortBy}"), serializer<SearchKey>() ) val request = DeepLinkRequest(uri = "https://www.example.com/search?q=kotlin&category=books&sortBy=DATE") val key = matcher.match(request)?.key // SearchKey(query = "kotlin", page = 1, filters = SearchFilters(category = "books", sortBy = SortOrder.DATE))
DeepLinkSerializer ile özel serileştirme
Özel nesneleri (ör. Filter(key = "brand", value =
"pixel")), harici türleri (ör. java.time.LocalDate) veya özel sınırlanmış dizeleri (ör. virgülle ayrılmış değerler) seri durumdan çıkarmak için DeepLinkSerializer<T> sınıfını genişletin.
DeepLinkSerializer<T>, String ve T arasında dönüşüm yapan soyut bir KSerializer<T> sınıfıdır:
abstract class DeepLinkSerializer<T : Any> : KSerializer<T> {
abstract val serialName: String
abstract fun deserialize(value: String): T
abstract fun serialize(value: T): String
}
Örneğin, aşağıdaki snippet'lerde kullanılan Filter ve FilterSerializer tanımlarını ele alalım:
@Serializable data class Filter(val key: String, val value: String) object FilterSerializer : DeepLinkSerializer<Filter>() { override val serialName: String = "com.example.Filter" override fun deserialize(value: String): Filter { val parts = value.split(":", limit = 2) if (parts.size < 2) { throw SerializationException("Invalid filter: $value. Expected key:value.") } return Filter(key = parts[0], value = parts[1]) } override fun serialize(value: Filter): String = "${value.key}:${value.value}" }
Tekli özel nesneler
Bir nesnenin kodunu tek bir URI parametre dizesinden (ör. ?filter=brand:google) çözmek için mülke @Serializable(with = ...) ile ek açıklama ekleyin:
@Serializable data class CatalogKey( @Serializable(with = FilterSerializer::class) val filter: Filter ) : NavKey val matcher = UriDeepLinkMatcher( DeepLinkUri("www.example.com/catalog?filter={filter}"), serializer<CatalogKey>() ) val request = DeepLinkRequest(uri = "https://www.example.com/catalog?filter=brand:google") val key = matcher.match(request)?.key // CatalogKey(filter = Filter("brand", "google"))
Yinelenen sorgu parametrelerindeki özel nesneler
Yinelenen sorgu parametrelerini özel nesne koleksiyonu (List<T>, Set<T> veya Array<T>) olarak seri durumdan çıkarmak için öğe türü T için DeepLinkSerializer<T> uygulayın ve özelliğin tür bağımsız değişkenine @Serializable(with = ...) ile ek açıklama ekleyin:
@Serializable data class SearchResultsKey( val query: String, val filters: List<@Serializable(with = FilterSerializer::class) Filter> = emptyList() ) : NavKey val searchResultsPattern = DeepLinkUri("www.example.com/search?q={query}&filter={filters}") val searchResultsMatcher = UriDeepLinkMatcher(searchResultsPattern, serializer<SearchResultsKey>()) val request = DeepLinkRequest(uri = "https://www.example.com/search?q=phone&filter=brand:google&filter=color:hazel") val matchResult = searchResultsMatcher.match(request) val key = matchResult?.key // SearchResultsKey(query = "phone", filters = listOf(Filter("brand", "google"), Filter("color", "hazel")))
Tek parametrelerde sınırlanmış koleksiyonlar
Virgülle ayrılmış veya özel sınırlayıcılarla ayrılmış değerleri (ör. ?ids=1,2,3) bir koleksiyona ayrıştırmak için tüm koleksiyon türü için DeepLinkSerializer uygulayın ve özelliği @Serializable(with = ...) ile ek açıklama ekleyin:
object IntListCsvSerializer : DeepLinkSerializer<List<Int>>() { override val serialName: String = "com.example.IntListCsv" override fun deserialize(value: String): List<Int> { if (value.isEmpty()) return emptyList() return value.split(",").map { it.trim().toInt() } } override fun serialize(value: List<Int>): String = value.joinToString(",") } @Serializable data class ItemListKey( @Serializable(with = IntListCsvSerializer::class) val ids: List<Int> ) : NavKey val itemListPattern = DeepLinkUri("www.example.com/items/{ids}") val itemListMatcher = UriDeepLinkMatcher(itemListPattern, serializer<ItemListKey>()) val request = DeepLinkRequest(uri = "https://www.example.com/items/10,20,30") val key = itemListMatcher.match(request)?.key // ItemListKey(ids = listOf(10, 20, 30))
Bağımsız değişken doğrulama ve eşleşen sonuçlar
UriDeepLinkMatcher, uyumsuzluklar (diğer eşleştiricilerin denenebilmesi için null döndürür) ve desteklenmeyen yapılandırmalar (istisna oluşturur) arasında ayrım yapar.
Uyuşmazlıklar
Gelen bir istek URI'si, kalıp veya tür şartlarını karşılamadığında uyuşmazlık oluşur:
- Gerekli parametreler eksik: Varsayılan değerleri olmayan ve karşılık gelen URI parametreleri istek URI'sinde bulunmayan, null değer alabilen anahtar özellikler.
- Tür ayrıştırma hataları: Beklenen özellik türüne (ör.
Intözelliği için"abc") ayrıştırılamayan, ayıklanmış bağımsız değişken değerleri.
Uyuşmazlık olduğunda UriDeepLinkMatcher.match, null değerini döndürür ve sonraki eşleştiricilerin değerlendirilmesine olanak tanır.
Varsayılan değerler, iç içe yerleştirilmiş nesneler ve enum'larla yapılandırılmış bir anahtar sınıfı ve eşleştirici düşünün:
enum class MapLayer { STANDARD, SATELLITE, TERRAIN } @Serializable data class LayerOptions( val style: String, val layer: MapLayer = MapLayer.STANDARD ) @Serializable data class MapKey( val location: String, val zoom: Int = 12, val options: LayerOptions ) : NavKey val matcher = UriDeepLinkMatcher( DeepLinkUri("www.example.com/map/{location}?zoom={zoom}&style={style}&layer={layer}"), serializer<MapKey>() )
Aşağıdaki tabloda, çeşitli istek URI'leri için eşleşen sonuçlar gösterilmektedir:
| İstek URI'sı | Sonuçları Yorumlama | Maç Sonucu |
|---|---|---|
https://www.example.com/map/paris?zoom=15&style=dark&layer=SATELLITE |
Başarılı (Tüm parametreler sağlandı) | UriMatchResult(MapKey("paris", 15, LayerOptions("dark", MapLayer.SATELLITE))) |
https://www.example.com/map/paris?style=dark |
Başarılı (zoom varsayılan olarak 12, layer ise STANDARD değerine ayarlanır) |
UriMatchResult(MapKey("paris", 12, LayerOptions("dark", MapLayer.STANDARD))) |
https://www.example.com/map/paris?zoom=&style=dark |
Başarılı (Boş isteğe bağlı sorgu parametresi varsayılan 12 değerini kullanır) |
UriMatchResult(MapKey("paris", 12, LayerOptions("dark", MapLayer.STANDARD))) |
https://www.example.com/map?style=dark |
Uyuşmazlık (Gerekli location parametresi eksik) |
null |
https://www.example.com/map/paris?zoom=close&style=dark |
Uyuşmazlık ("close", Int değil) |
null |
https://www.example.com/map/paris?style=dark&layer=HYBRID |
Uyuşmazlık ("HYBRID", enum'da yok) |
null |
Desteklenmeyen yapılandırmalar
Anahtar sınıfınız desteklenmeyen veri türleri içeriyorsa UriDeepLinkMatcher, eşleştirme sırasında null döndürmek yerine bir istisna oluşturur.
- Haritalar ve çok boyutlu koleksiyonlar:
UriDeepLinkMatcheryalnızca temel öğeler, dizeler, enum'lar veyaDeepLinkSerializerile ek açıklama eklenmiş özel türlerin tek boyutlu koleksiyonlarını destekler.MaptürleriIllegalArgumentExceptionhatası verirken iç içe yerleştirilmiş koleksiyonlar (ör.List<List<String>>)SerializationExceptionhatası verir. - Ek açıklama eklenmemiş özel nesne koleksiyonları: Özel türlerin koleksiyonları (ör.
List<Filter>), öğe türüneDeepLinkSerializerile ek açıklama eklenmediği süreceSerializationExceptionhatası verir. - Düzleştirilmemiş iç içe yerleştirilmiş sınıflar: İç içe yerleştirilmiş
@Serializablesınıflar,DeepLinkSerializerolmadan tek bir yer tutucuyla (ör.?user={user}) eşlenemez.
// Throws IllegalArgumentException: Map decoding is not supported. @Serializable data class InvalidKey(val tags: Map<String, String>) : NavKey // Throws SerializationException: Only collections of primitives are supported. @Serializable data class InvalidKey(val filters: List<Filter>) : NavKey
UriMatchResult karşılaştırma
UriMatchResult örnekleri, aşağıdaki ölçütler kullanılarak sıralanır:
- MatchResult türü:
UriMatchResult, diğerMatchResulttürlerinden daha yüksek sıralamaya sahiptir. - Tam yol: Tam yol eşleşmeleri, yer tutucu veya joker karakter eşleşmelerinden daha üst sıralarda yer alır.
- Yol bağımsız değişkeni sayısı: Daha fazla yol bağımsız değişkeni içeren eşleşmeler daha üst sıralarda yer alır.
- Bağımsız değişkenlerin varlığı: Bağımsız değişkenleri yakalayan eşleşmeler, yakalamayanlardan daha yüksek sıralamaya sahiptir.
- Toplam bağımsız değişken sayısı: Toplam bağımsız değişken sayısı (yol, sorgu, parça) son eşitlik bozucudur.
UriDeepLinkMatcher kadranını özelleştir
UriDeepLinkMatcher, URI eşleştirme ve bağımsız değişken çıkarma davranışını özelleştirmek için alt sınıf oluşturabileceğiniz bir open sınıfıdır:
matchRequest: Gelen birDeepLinkRequestiçin üst düzey eşleşen giriş noktası. İstek eklerini incelemek veya URI eşleşmesinden önce özel ön koşullar uygulamak için bunu geçersiz kılın.matchUri:DeepLinkUrideğerini yapılandırılmış kalıpla eşleştirir.super.matchUriçağrılmadan önce gelen URI'ları yakalamak ve normalleştirmek (ör. dinamik alt alan adlarını veya eski yol biçimlerini yeniden yazmak) için bu yöntemi geçersiz kılın.matchArguments: Sağlananserializerdeğerini kullanarak ayıklanan yol, sorgu ve parça bağımsız değişken eşlemelerini bir gezinme anahtarı örneğine dönüştürür. Anahtar örneklendirmeden önce dinamik değerler eklemek veya bağımsız değişkenleri dönüştürmek için bu ayarı geçersiz kılın.
Aşağıdaki örnekte, eşleştirmeden önce eski URL yolu ön eklerini normalleştirmek için UriDeepLinkMatcher alt sınıfının nasıl oluşturulacağı gösterilmektedir:
class LegacyPrefixUriDeepLinkMatcher<T : Any>( uriPattern: DeepLinkUri, serializer: KSerializer<T> ) : UriDeepLinkMatcher<T>(uriPattern, serializer) { override fun matchUri(uri: DeepLinkUri): UriMatchResult<T>? { val path = uri.path val normalizedUri = if (path != null && path.startsWith("/legacy/")) { DeepLinkUri(uri.toString().replaceFirst("/legacy", "")) } else { uri } return super.matchUri(normalizedUri) } }