Hiyerarşik URI'leri 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ızda seri durumundan çıkarma işlemi için kotlinx.serialization kullanılır.
UriDeepLinkMatcher oluşturmak için bir desen DeepLinkUri ve ilgili anahtarın seri hale getiricisini 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ştiricileri oluşturma başlıklı makaleyi inceleyin.
Desteklenen eşleşme kalıpları
UriDeepLinkMatcher, URI'leri beş bileşenine (şema, yetki, yol, sorgu ve parça) göre eşleştirir. 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 şemayla eşleşmek için şemayı kalıba dahil edin. Bir istisna olarak, bir kalıptaki http şeması hem http hem de https istek URI'leriyle eşleşirken bir kalıptaki https yalnızca https istekleriyle eşleşir.
| Kalıp 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 |
✅ |
Yetkili eşleştirme
UriDeepLinkMatcher, URI yetkilisi (ana makine ve isteğe bağlı bağlantı noktası) üzerinde büyük/küçük harfe duyarsız tam eşleşme gerçekleştirir. Yetkili alanında yer tutucular veya joker karakterler desteklenmez ve herhangi bir bağımsız değişken çıkarılmaz:
| Kalıp 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:
| Kalıp 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 ekstra bir segment oluşturur) | Yok |
Sorgu eşleme
İ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 de yoksayılır.
Aşağıdaki sorgu parametresi kalıpları desteklenir:
| Kalıp 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 kalıbı türleri desteklenir:
| Kalıp 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, numaralandırmalara, koleksiyonlara ve özel nesnelere seri durumdan çıkarma işlemini destekler. Serileştirme iki kategoriye ayrılır:
- Standart serileştirme: Aşağıdaki gibi seri durumdan çıkarma için
kotlinx.serializationkullanılır:- Temel öğeler (
Boolean,Int,Long,Float,Double,Char,Byte,Short) veString - Sıralamalar
Set,ListveyaArrayilkel, dize ya da enum- İç içe yerleştirilmiş
@Serializablesınıflar (özellikleri tek tek URI yer tutucularına düzleştirilmiş)
- Temel öğeler (
DeepLinkSerializerile özel serileştirme: Tek birStringile özel nesneler, harici türler (ör.java.time.LocalDate) veya özel sınırlı koleksiyonlar arasında dönüştürme yapar.
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 türler ve dizeler
UriDeepLinkMatcher, temel türleri (Boolean, Int, Long, Float, Double, Char, Byte, Short) ve String 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 öğe adlarıyla büyük/küçük harfe duyarlı şekilde 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ı
Tekrarlanan anahtarlara sahip sorgu parametreleri (ör. ?id=10&id=20), List<T>, Set<T> veya Array<T> olarak otomatik olarak seri hale getirilir. Burada T, temel bir 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 mülk 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şlenir:
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ırlı dizeleri (ör. virgülle ayrılmış değerler) seri durumundan çıkarmak için DeepLinkSerializer<T> öğesini genişletin.
DeepLinkSerializer<T>, String ile T arasında dönüşüm yapan soyut bir KSerializer<T>'dir:
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}" }
Tek özel nesneler
Tek bir URI parametresi dizesinden (ör. ?filter=brand:google) bir nesnenin kodunu çözmek için özelliği @Serializable(with = ...) ile 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"))
Tekrarlanan sorgu parametrelerindeki özel nesneler
Tekrarlanan sorgu parametrelerini özel nesne koleksiyonuna (List<T>, Set<T> veya Array<T>) seri durumdan çıkarmak için T öğe türü için DeepLinkSerializer<T>'ü uygulayın ve özelliğin tür bağımsız değişkenine @Serializable(with = ...) ile 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ırlı değerleri (ör. ?ids=1,2,3) bir koleksiyonda ayrıştırmak için koleksiyon türünün tamamı için DeepLinkSerializer değerini uygulayın ve özelliği @Serializable(with = ...) ile 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şme sonuçları
UriDeepLinkMatcher, eşleşmeme (null döndürür, böylece diğer eşleştiriciler denenebilir) ve desteklenmeyen yapılandırmalar (bir istisna oluşturur) arasında ayrım yapar.
Uyuşmazlıklar
Gelen istek URI'si, kalıp veya tür koşullarını karşılamadığında uyuşmazlık oluşur:
- Gerekli parametreler eksik: Varsayılan değerleri olmayan ve istek URI'sinde karşılık gelen URI parametreleri bulunmayan, boş bırakılamayan anahtar özellikleri.
- Tür ayrıştırma hataları: Beklenen özellik türüne (örneğin,
Intözelliği için"abc") ayrıştırılamayan çıkarılan bağımsız değişken değerleri.
Uyuşmazlık olduğunda UriDeepLinkMatcher.match döndürülür null. Böylece, sonraki eşleştiricilerin değerlendirilmesine izin verilir.
Varsayılan değerler, iç içe yerleştirilmiş nesneler ve numaralandırmalarla yapılandırılmış bir anahtar sınıfı ve eşleştiriciyi ele alalım:
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şme sonuçları gösterilmektedir:
| İstek URI'sı | Kod Çözme Sonucu | 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 olur) |
UriMatchResult(MapKey("paris", 12, LayerOptions("dark", MapLayer.STANDARD))) |
https://www.example.com/map/paris?zoom=&style=dark |
Başarı (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" numaralandırmada değil) |
null |
Desteklenmeyen yapılandırmalar
Anahtar sınıfınızda desteklenmeyen veri türleri varsa UriDeepLinkMatcher, null döndürmek yerine eşleştirme sırasında bir istisna oluşturur.
- Haritalar ve çok boyutlu koleksiyonlar:
UriDeepLinkMatcheryalnızcaDeepLinkSerializerile açıklama eklenmiş ilkel öğeler, dizeler, numaralandırmalar veya özel türlerden oluşan tek boyutlu koleksiyonları destekler.MaptürleriIllegalArgumentExceptionhatası verirken, iç içe yerleştirilmiş koleksiyonlar (ör.List<List<String>>)SerializationExceptionhatası verir. - Açıklama eklenmemiş özel nesne koleksiyonları: Özel türlerin (ör.
List<Filter>) koleksiyonları, öğe türüneDeepLinkSerializeraçıklaması eklenmediği süreceSerializationExceptionhatası verir. - Düzleştirilmemiş iç içe sınıflar: İç içe
@Serializablesınıflar,DeepLinkSerializerolmadan tek bir yer tutucuya (ö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çütlere göre sıralanır:
- MatchResult türü:
UriMatchResult, diğerMatchResulttürlerinden daha yüksek sıralanır. - 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şken 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, yakalamayanlara göre daha yüksek sıralanır.
- Toplam bağımsız değişken sayısı: Toplam bağımsız değişken sayısı (yol, sorgu, parça) son belirleyici faktördür.
UriDeepLinkMatcher eklentisini ö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: GelenDeepLinkRequestiçin üst düzey eşleşme giriş noktası. İstek ekstralarını incelemek veya URI eşlemesinden önce özel ön koşullar uygulamak için bunu geçersiz kılın.matchUri:DeepLinkUri, yapılandırılmış kalıpla eşleşir.super.matchUriçağrılmadan önce gelen URI'leri yakalamak ve normalleştirmek (örneğin, dinamik alt alan adlarını veya eski yol biçimlerini yeniden yazmak) için bu işlevi geçersiz kılın.matchArguments: Çıkarılan yol, sorgu ve parça bağımsız değişken haritalarını, sağlananserializerkullanılarak bir gezinme anahtarı örneğine seri durumdan çıkarır. Anahtar örneklendirilmeden önce dinamik değerler yerleştirmek veya bağımsız değişkenleri dönüştürmek için bu işlevi geçersiz kılın.
Aşağıdaki örnekte, eşleştirme işleminden önce eski URL yolu öneklerini normalleştirmek için alt sınıfların nasıl kullanıldığı UriDeepLinkMatcher 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) } }