比對 URI 深層連結

如要根據模式比對階層式 URI 並擷取引數,請使用 UriDeepLinkMatcher。這項功能會依據 kotlinx.serialization,將相符的引數還原序列化為主要類別。

如要建立 UriDeepLinkMatcher,請提供模式 DeepLinkUri 和對應鍵的序列化程式:

如為非階層式 URI 或自訂配置 (例如 tel:),請參閱「建立自訂深層連結比對器」。

支援的相符模式

UriDeepLinkMatcher 會根據 URI 的五個元件 (配置、授權、路徑、查詢和片段) 比對 URI。以下各節說明每個元件支援的模式語法、引數預留位置和比對規則。

比對架構

如果 URI 模式中沒有配置,系統會比對 httphttps。 如要比對特定架構,請將該架構納入模式。例外狀況是,模式中的 http 配置會同時比對 httphttps 要求 URI,而模式中的 https 只會比對 https 要求。

模式 URI 要求 URI 比對
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 會對 URI 授權 (主機和選用通訊埠) 執行不區分大小寫的完全比對。授權單位不支援預留位置或萬用字元,且不會擷取任何引數:

模式 URI 要求 URI 比對
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

路徑比對

支援的路徑模式如下:

模式 URI 要求 URI 比對 擷取的引數
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/ ❌ (尾端斜線會建立額外區隔) N/A

查詢比對

要求 URI 中的查詢參數順序不必與模式 URI 中的順序相符。此外,系統會忽略要求 URI 中存在但模式 URI 中沒有的參數。

系統支援下列查詢參數模式:

模式 URI 要求 URI 擷取的引數
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"

片段比對

系統支援下列片段模式類型:

模式 URI 要求 URI 擷取的引數
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 支援將 URI 引數還原序列化為原始型別、列舉、集合和自訂物件。序列化分為兩類:

  • 標準序列化:使用 kotlinx.serialization 還原序列化為:
    • 原始型別 (BooleanIntLongFloatDoubleCharByteShort) 和 String
    • 列舉
    • 原始型別、字串或列舉的 SetListArray
    • 巢狀 @Serializable 類別 (屬性會扁平化為個別 URI 預留位置)
  • 使用 DeepLinkSerializer 進行自訂序列化:在單一 String 和自訂物件、外部型別 (例如 java.time.LocalDate) 或自訂分隔符號集合之間轉換。

標準序列化

UriDeepLinkMatcher 可直接用於標準型別和扁平化結構,不必實作自訂序列化程式。

基本型別和字串

UriDeepLinkMatcher 會自動解碼原始型別 (BooleanIntLongFloatDoubleCharByteShort) 和 String

列舉

系統會區分大小寫,比對列舉值與列舉元素名稱:

重複的查詢集合

具有重複鍵的查詢參數 (例如 ?id=10&id=20) 會自動還原序列化為 List<T>Set<T>Array<T>,其中 T 是原始型別、String 或列舉:

巢狀 @Serializable 類別

如果 NavKey 包含的屬性類型是另一個 @Serializable 類別,UriDeepLinkMatcher 會將其屬性扁平化,因此巢狀類別的每個屬性都會直接對應至同名的個別 URI 參數:

如要還原序列化自訂物件 (例如 Filter(key = "brand", value = "pixel"))、外部型別 (例如 java.time.LocalDate) 或自訂分隔字串 (例如逗號分隔值),請擴充 DeepLinkSerializer<T>

DeepLinkSerializer<T> 是抽象 KSerializer<T>,可在 StringT 之間轉換:

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

舉例來說,請考慮下列程式碼片段中使用的 FilterFilterSerializer 定義:

單一自訂物件

如要從單一 URI 參數字串 (例如 ?filter=brand:google) 解碼物件,請使用 @Serializable(with = ...) 註解標註屬性:

重複查詢參數中的自訂物件

如要將重複的查詢參數還原序列化為自訂物件集合 (List<T>Set<T>Array<T>),請為元素類型 T 實作 DeepLinkSerializer<T>,並使用 @Serializable(with = ...) 註解屬性的型別引數:

單一參數中的分隔符號集合

如要將以半形逗號分隔或自訂分隔的值 (例如 ?ids=1,2,3) 剖析為集合,請為整個集合型別實作 DeepLinkSerializer,並使用 @Serializable(with = ...) 註解屬性:

引數驗證和比對結果

UriDeepLinkMatcher 會區分不符 (傳回 null,因此可以嘗試其他比對器) 和不支援的設定 (會擲回例外狀況)。

不相符

如果傳入的要求 URI 不符合模式或類型規定,就會發生不符情況:

  • 缺少必要參數:沒有預設值的不可為空鍵屬性,且要求 URI 中缺少對應的 URI 參數。
  • 類型剖析失敗:無法剖析為預期屬性類型的擷取引數值 (例如 Int 屬性的 "abc")。

如果發生不符的情況,UriDeepLinkMatcher.match 會傳回 null,以便評估後續的相符項目。

請考慮使用預設值、巢狀物件和列舉設定的重要類別和比對器:

下表顯示各種要求 URI 的比對結果:

要求 URI 解碼結果 賽事結果
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 成功 (zoom 預設為 12layer 預設為 STANDARD) UriMatchResult(MapKey("paris", 12, LayerOptions("dark", MapLayer.STANDARD)))
https://www.example.com/map/paris?zoom=&style=dark 成功 (空白的選用查詢參數會使用預設 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" 不在列舉中) null

不支援的設定

如果金鑰類別包含不支援的資料類型,UriDeepLinkMatcher 會在比對期間擲回例外狀況,而不是傳回 null

  • 對應和多維度集合UriDeepLinkMatcher 僅支援原始型別、字串、列舉或以 DeepLinkSerializer 註解的自訂型別的一維集合。Map 類型會擲回 IllegalArgumentException,而巢狀集合 (例如 List<List<String>>) 則會擲回 SerializationException
  • 未註解的自訂物件集合:自訂型別 (例如 List<Filter>) 的集合會擲回 SerializationException,除非元素型別已使用 DeepLinkSerializer 註解。
  • 未扁平化的巢狀類別:巢狀 @Serializable 類別無法對應至單一預留位置 (例如 ?user={user}),除非有 DeepLinkSerializer

UriMatchResult比較

系統會依序根據下列條件,對 UriMatchResult 執行個體進行排名:

  1. MatchResult 類型UriMatchResult 的排名高於其他MatchResult 類型。
  2. 確切路徑:確切路徑比對的排名高於預留位置或萬用字元比對。
  3. 路徑引數計數:路徑引數越多,排名越高。
  4. 引數存在與否:擷取引數的相符項目排名會高於未擷取引數的相符項目。
  5. 引數總數:引數 (路徑、查詢、片段) 總數是最終的決勝關鍵。

自訂UriDeepLinkMatcher

UriDeepLinkMatcheropen 類別,您可以將其加入子類別,自訂 URI 比對和引數擷取行為:

  • matchRequest:傳入 DeepLinkRequest 的頂層比對進入點。覆寫此項目,即可檢查要求額外資訊或在 URI 比對前套用自訂前提條件。
  • matchUri:根據設定的模式比對 DeepLinkUri。覆寫此項目,即可在呼叫 super.matchUri 前攔截及正規化傳入的 URI (例如重新編寫動態子網域或舊版路徑格式)。
  • matchArguments:使用提供的 serializer,將擷取的路徑、查詢和片段引數對應項還原序列化為導覽鍵例項。覆寫此項目,在鍵例項化之前插入動態值或轉換引數。

以下範例說明如何將 UriDeepLinkMatcher 子類別化,以便在比對前正規化舊版網址路徑前置字串: