हायरारकी वाले यूआरआई को पैटर्न से मैच करने और आर्ग्युमेंट निकालने के लिए, UriDeepLinkMatcher का इस्तेमाल करें. यह kotlinx.serialization पर निर्भर करता है, ताकि मैच होने वाले आर्ग्युमेंट को आपकी मुख्य क्लास में डीसीरियलाइज़ किया जा सके.
UriDeepLinkMatcher बनाने के लिए, पैटर्न DeepLinkUri और उससे जुड़ी कुंजी के लिए सीरियलाइज़र दें:
@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")
नॉन-हैरारकी वाले यूआरआई या कस्टम स्कीम (जैसे कि tel:) के लिए, कस्टम डीप लिंक मैचर बनाएं देखें.
मैच करने वाले ऐसे पैटर्न जो इस्तेमाल किए जा सकते हैं
UriDeepLinkMatcher, यूआरआई को उनके पांच कॉम्पोनेंट के आधार पर मैच करता है: स्कीम, अथॉरिटी, पाथ, क्वेरी, और फ़्रैगमेंट. यहां दिए गए सेक्शन में, हर कॉम्पोनेंट के लिए इस्तेमाल किए जा सकने वाले पैटर्न सिंटैक्स, आर्ग्युमेंट प्लेसहोल्डर, और मैच करने के नियमों के बारे में बताया गया है.
स्कीम मैचिंग
अगर यूआरआई पैटर्न में कोई स्कीम मौजूद नहीं है, तो http और https, दोनों मैच किए जाते हैं.
किसी खास स्कीम से मैच करने के लिए, उसे पैटर्न में शामिल करें. अपवाद के तौर पर, किसी पैटर्न में http स्कीम, http और https, दोनों अनुरोध यूआरआई से मैच करती है. हालांकि, किसी पैटर्न में https सिर्फ़ https अनुरोधों से मैच करता है.
| पैटर्न यूआरआई | अनुरोध यूआरआई | मिलते-जुलते वीडियो |
|---|---|---|
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 |
✅ |
अथॉरिटी मैचिंग
UriDeepLinkMatcher, यूआरआई अथॉरिटी (होस्ट और वैकल्पिक पोर्ट) पर केस-इनसेंसिटिव एग्ज़ैक्ट मैच करता है. अथॉरिटी में प्लेसहोल्डर या वाइल्डकार्ड का इस्तेमाल नहीं किया जा सकता. साथ ही, कोई आर्ग्युमेंट नहीं निकाला जाता:
| पैटर्न यूआरआई | अनुरोध यूआरआई | मिलते-जुलते वीडियो |
|---|---|---|
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 |
❌ |
पाथ मैचिंग
ये पाथ पैटर्न इस्तेमाल किए जा सकते हैं:
| पैटर्न यूआरआई | अनुरोध यूआरआई | मिलते-जुलते वीडियो | एक्सट्रैक्ट किए गए आर्ग्युमेंट |
|---|---|---|---|
www.example.com/users |
https://www.example.com/users |
✅ | कोई नहीं |
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: "" (खाली स्ट्रिंग) |
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 |
✅ | कोई नहीं |
www.example.com/users |
https://www.example.com/users/ |
❌ (ट्रेलिंग स्लैश से एक अतिरिक्त सेगमेंट बनता है) | लागू नहीं |
क्वेरी मैचिंग
अनुरोध यूआरआई में क्वेरी पैरामीटर का क्रम, पैटर्न यूआरआई में दिए गए क्रम से मेल खाना ज़रूरी नहीं है. इसके अलावा, अनुरोध यूआरआई में मौजूद उन पैरामीटर को अनदेखा कर दिया जाता है जो पैटर्न यूआरआई में मौजूद नहीं होते.
क्वेरी पैरामीटर के ये पैटर्न इस्तेमाल किए जा सकते हैं:
| पैटर्न यूआरआई | अनुरोध यूआरआई | एक्सट्रैक्ट किए गए आर्ग्युमेंट |
|---|---|---|
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: "" (खाली स्ट्रिंग) |
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" |
फ़्रैगमेंट मैचिंग
फ़्रैगमेंट पैटर्न के ये टाइप इस्तेमाल किए जा सकते हैं:
| पैटर्न यूआरआई | अनुरोध यूआरआई | एक्सट्रैक्ट किए गए आर्ग्युमेंट |
|---|---|---|
www.example.com/#section1 |
https://www.example.com/#section1 |
कोई नहीं |
www.example.com/#section_{id} |
https://www.example.com/#section_123 |
id: "123" |
www.example.com/#section_.* |
https://www.example.com/#section_123 |
कोई नहीं |
किस तरह के डेटा को ट्रांसफ़र किया जा सकता है
UriDeepLinkMatcher, यूआरआई आर्ग्युमेंट को प्रिमिटिव टाइप, enum, कलेक्शन, और कस्टम ऑब्जेक्ट में डीसीरियलाइज़ करने की सुविधा देता है. सीरियलाइज़ेशन को दो कैटगरी में
बांटा जा सकता है:
- स्टैंडर्ड सीरियलाइज़ेशन: इसमें
kotlinx.serializationका इस्तेमाल करके, डेटा को डीसीरियलाइज़ किया जाता है:- प्रिमिटिव (
Boolean,Int,Long,Float,Double,Char,Byte,Short) औरString - एनम्स
Set,ListयाArrayप्रिमिटिव, स्ट्रिंग या एनम- नेस्टेड
@Serializableक्लास (इनकी प्रॉपर्टी को अलग-अलग यूआरआई प्लेसहोल्डर में फ़्लैट किया जाता है)
- प्रिमिटिव (
DeepLinkSerializerके साथ कस्टम सीरियलाइज़ेशन: यह एकStringऔर कस्टम ऑब्जेक्ट, बाहरी टाइप (जैसे किjava.time.LocalDate) या कस्टम-डिलिमिटेड कलेक्शन के बीच कन्वर्ज़न करता है.
स्टैंडर्ड सीरियलाइज़ेशन
UriDeepLinkMatcher, स्टैंडर्ड टाइप और फ़्लैट किए गए स्ट्रक्चर के लिए, कस्टम सीरियलाइज़र को लागू किए बिना ही काम करता है.
प्रिमिटिव और स्ट्रिंग
UriDeepLinkMatcher, प्रिमिटिव टाइप (Boolean, Int, Long, Float, Double, Char, Byte, Short) और String को अपने-आप डिकोड करता है:
@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)
एनम्स
ईनम की वैल्यू, ईनम एलिमेंट के नामों से केस-सेंसिटिव तरीके से मैच की जाती हैं:
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)
बार-बार पूछे जाने वाले सवालों के कलेक्शन
बार-बार इस्तेमाल होने वाली कुंजियों (जैसे, ?id=10&id=20) वाले क्वेरी पैरामीटर, अपने-आप List<T>, Set<T> या Array<T> में डीसीरियलाइज़ हो जाते हैं. यहां T एक प्रिमिटिव टाइप, String या enum है:
@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))
नेस्ट की गई @Serializable क्लास
जब किसी NavKey में ऐसी प्रॉपर्टी शामिल होती है जिसका टाइप कोई दूसरा @Serializable क्लास होता है, तो UriDeepLinkMatcher इसकी प्रॉपर्टी को फ़्लैट कर देता है. इससे नेस्ट की गई क्लास की हर प्रॉपर्टी, सीधे तौर पर उसी नाम के अलग-अलग यूआरआई पैरामीटर से मैप हो जाती है:
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 के साथ कस्टम सीरियलाइज़ेशन
कस्टम ऑब्जेक्ट (जैसे, Filter(key = "brand", value =
"pixel")), बाहरी टाइप (जैसे, java.time.LocalDate) या कस्टम डीलिमिटेड स्ट्रिंग (जैसे, कॉमा लगाकर अलग की गई वैल्यू) को डीसीरियलाइज़ करने के लिए, DeepLinkSerializer<T> को बढ़ाएं.
DeepLinkSerializer<T> एक ऐब्स्ट्रैक्ट KSerializer<T> है, जो String और T के बीच कन्वर्ज़न करता है:
abstract class DeepLinkSerializer<T : Any> : KSerializer<T> {
abstract val serialName: String
abstract fun deserialize(value: String): T
abstract fun serialize(value: T): String
}
उदाहरण के लिए, Filter और FilterSerializer की परिभाषाओं पर ध्यान दें, जिनका इस्तेमाल इन स्निपेट में किया गया है:
@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}" }
सिंगल कस्टम ऑब्जेक्ट
किसी ऑब्जेक्ट को एक यूआरआई पैरामीटर स्ट्रिंग (जैसे कि ?filter=brand:google) से डिकोड करने के लिए, प्रॉपर्टी को @Serializable(with = ...) के साथ एनोटेट करें:
@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"))
बार-बार इस्तेमाल होने वाले क्वेरी पैरामीटर में कस्टम ऑब्जेक्ट
बार-बार इस्तेमाल होने वाले क्वेरी पैरामीटर को कस्टम ऑब्जेक्ट (List<T>, Set<T> या Array<T>) के कलेक्शन में डीसीरियलाइज़ करने के लिए, एलिमेंट टाइप T के लिए DeepLinkSerializer<T> लागू करें. साथ ही, प्रॉपर्टी के टाइप आर्ग्युमेंट को @Serializable(with = ...) के साथ एनोटेट करें:
@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")))
सिंगल पैरामीटर में डीलिमिटेड कलेक्शन
कॉमा लगाकर अलग किए गए या कस्टम-डीलिमिटेड वैल्यू (जैसे कि ?ids=1,2,3) को किसी कलेक्शन में पार्स करने के लिए, पूरे कलेक्शन टाइप के लिए DeepLinkSerializer लागू करें और प्रॉपर्टी को @Serializable(with = ...) के साथ एनोटेट करें:
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))
तर्कों की पुष्टि करना और नतीजों का मिलान करना
UriDeepLinkMatcher, मेल न खाने वाली वैल्यू (null दिखाता है, ताकि अन्य मैचर को आज़माया जा सके) और काम न करने वाले कॉन्फ़िगरेशन (अपवाद दिखाता है) के बीच अंतर करता है.
मेल न खाने वाली वैल्यू
मिसमैच तब होता है, जब कोई इनकमिंग अनुरोध URI, पैटर्न या टाइप की ज़रूरी शर्तों को पूरा नहीं करता:
- ज़रूरी पैरामीटर मौजूद नहीं हैं: ऐसी मुख्य प्रॉपर्टी जिनकी वैल्यू शून्य नहीं हो सकती और जिनकी डिफ़ॉल्ट वैल्यू नहीं होती. साथ ही, जिनके यूआरआई पैरामीटर, अनुरोध यूआरआई में मौजूद नहीं होते.
- टाइप पार्सिंग से जुड़ी गड़बड़ियां: एक्सट्रैक्ट की गई आर्ग्युमेंट वैल्यू, जिन्हें अनुमानित प्रॉपर्टी टाइप में पार्स नहीं किया जा सकता. उदाहरण के लिए,
Intप्रॉपर्टी के लिए"abc".
जब कोई मैच नहीं होता है, तो UriDeepLinkMatcher.match null दिखाता है. इससे, बाद के मैच करने वालों का आकलन किया जा सकता है.
डिफ़ॉल्ट वैल्यू, नेस्ट किए गए ऑब्जेक्ट, और enum के साथ कॉन्फ़िगर की गई मुख्य क्लास और मैचर पर विचार करें:
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>() )
यहां दी गई टेबल में, अलग-अलग अनुरोध यूआरआई के लिए मैच होने वाले नतीजे दिखाए गए हैं:
| अनुरोध यूआरआई | Decoding Outcome | मैच का नतीजा |
|---|---|---|
https://www.example.com/map/paris?zoom=15&style=dark&layer=SATELLITE |
सफलता (सभी पैरामीटर दिए गए हैं) | UriMatchResult(MapKey("paris", 15, LayerOptions("dark", MapLayer.SATELLITE))) |
https://www.example.com/map/paris?style=dark |
Success (zoom defaults to 12, layer to STANDARD) |
UriMatchResult(MapKey("paris", 12, LayerOptions("dark", MapLayer.STANDARD))) |
https://www.example.com/map/paris?zoom=&style=dark |
Success (खाली छोड़े गए वैकल्पिक क्वेरी पैरामीटर के लिए, डिफ़ॉल्ट 12 का इस्तेमाल किया जाता है) |
UriMatchResult(MapKey("paris", 12, LayerOptions("dark", MapLayer.STANDARD))) |
https://www.example.com/map?style=dark |
मेल न खाना (ज़रूरी location पैरामीटर मौजूद नहीं है) |
null |
https://www.example.com/map/paris?zoom=close&style=dark |
मेल नहीं खाता ("close", Int नहीं है) |
null |
https://www.example.com/map/paris?style=dark&layer=HYBRID |
मेल नहीं खाता ("HYBRID", enum में नहीं है) |
null |
काम न करने वाले कॉन्फ़िगरेशन
अगर आपकी मुख्य क्लास में काम न करने वाले डेटा टाइप शामिल हैं, तो मैच करने के दौरान UriDeepLinkMatcher, null को दिखाने के बजाय एक अपवाद दिखाता है.
- मैप और मल्टी-डाइमेंशनल कलेक्शन:
UriDeepLinkMatcherसिर्फ़ प्रिमिटिव, स्ट्रिंग, एनम याDeepLinkSerializerके साथ एनोटेट किए गए कस्टम टाइप के सिंगल-डाइमेंशनल कलेक्शन के साथ काम करता है.Mapटाइप,IllegalArgumentExceptionदिखाता है. वहीं, नेस्ट किए गए कलेक्शन (जैसे,List<List<String>>),SerializationExceptionदिखाते हैं. - बिना एनोटेशन वाले कस्टम ऑब्जेक्ट कलेक्शन: कस्टम टाइप के कलेक्शन (जैसे कि
List<Filter>) मेंSerializationExceptionदिखता है. ऐसा तब तक होता है, जब तक एलिमेंट टाइप कोDeepLinkSerializerके साथ एनोटेट नहीं किया जाता. - अनफ़्लैटन की गई नेस्टेड क्लास: नेस्टेड
@Serializableक्लास कोDeepLinkSerializerके बिना, किसी एक प्लेसहोल्डर (जैसे कि?user={user}) पर मैप नहीं किया जा सकता.
// 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 कंपैरिज़न
UriMatchResult इंस्टेंस को इस क्रम में रैंक किया जाता है:
- MatchResult टाइप:
UriMatchResultको अन्यMatchResultटाइप के मुकाबले ज़्यादा रैंक मिलती है. - एग्ज़ैक्ट पाथ: लिटरल पाथ मैच की रैंक, प्लेसहोल्डर या वाइल्डकार्ड मैच से ज़्यादा होती है.
- पाथ आर्ग्युमेंट की संख्या: ज़्यादा पाथ आर्ग्युमेंट वाले यूआरएल को ज़्यादा रैंक मिलती है.
- आर्ग्युमेंट की मौजूदगी: आर्ग्युमेंट कैप्चर करने वाले मैच, आर्ग्युमेंट कैप्चर न करने वाले मैच की तुलना में ज़्यादा रैंक करते हैं.
- आर्ग्युमेंट की कुल संख्या: आर्ग्युमेंट (पाथ, क्वेरी, फ़्रैगमेंट) की कुल संख्या, फ़ाइनल टाई-ब्रेकर होती है.
UriDeepLinkMatcher को पसंद के मुताबिक बनाएं
UriDeepLinkMatcher एक open क्लास है, जिसे सबक्लास करके यूआरआई मैचिंग और आर्ग्युमेंट एक्सट्रैक्शन के व्यवहार को पसंद के मुताबिक बनाया जा सकता है:
matchRequest: यह आने वालेDeepLinkRequestके लिए, टॉप-लेवल मैचिंग एंट्री पॉइंट है. अनुरोध के अतिरिक्त डेटा की जांच करने या यूआरआई मैचिंग से पहले, पसंद के मुताबिक पहले से तय की गई शर्तें लागू करने के लिए, इसे बदलें.matchUri: यह कॉन्फ़िगर किए गए पैटर्न के हिसाब से,DeepLinkUriसे मैच करता है.super.matchUriको कॉल करने से पहले, आने वाले यूआरआई को इंटरसेप्ट और नॉर्मलाइज़ करने के लिए, इसे बदलें. उदाहरण के लिए, डाइनैमिक सबडोमेन या लेगसी पाथ फ़ॉर्मैट को फिर से लिखना.matchArguments: यह दिए गएserializerका इस्तेमाल करके, निकाले गए पाथ, क्वेरी, और फ़्रैगमेंट आर्ग्युमेंट मैप को नेविगेशन बटन के इंस्टेंस में डीसीरियलाइज़ करता है. कुंजी को इंस्टैंशिएट करने से पहले, डाइनैमिक वैल्यू इंजेक्ट करने या आर्ग्युमेंट को बदलने के लिए, इसे बदलें.
यहां दिए गए उदाहरण में, मैच करने से पहले लेगसी यूआरएल पाथ प्रीफ़िक्स को सामान्य बनाने के लिए, UriDeepLinkMatcher की सबक्लास बनाने का तरीका बताया गया है:
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) } }