Mencocokkan deep link URI

Untuk mencocokkan URI hierarkis dengan pola dan mengekstrak argumen, gunakan UriDeepLinkMatcher. Fitur ini mengandalkan kotlinx.serialization untuk mendeserialisasi argumen yang cocok ke dalam class kunci Anda.

Untuk membuat UriDeepLinkMatcher, berikan pola DeepLinkUri dan serializer untuk kunci yang sesuai:

Untuk URI non-hierarkis atau skema kustom (seperti tel:), lihat Membuat pencocok deep link kustom.

Pola pencocokan yang didukung

UriDeepLinkMatcher mencocokkan URI berdasarkan lima komponennya: skema, otoritas, jalur, kueri, dan fragmen. Bagian berikut menjelaskan sintaksis pola, placeholder argumen, dan aturan pencocokan yang didukung untuk setiap komponen.

Pencocokan skema

Jika tidak ada skema dalam pola URI, http dan https akan cocok. Untuk mencocokkan skema tertentu, sertakan dalam pola. Sebagai pengecualian, skema http dalam pola cocok dengan URI permintaan http dan https, sedangkan https dalam pola hanya cocok dengan permintaan https.

URI Pola URI Permintaan Cocok
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

Pencocokan otoritas

UriDeepLinkMatcher melakukan pencocokan persis yang tidak peka huruf besar/kecil pada otoritas URI (host dan port opsional). Placeholder atau karakter pengganti tidak didukung dalam otoritas, dan tidak ada argumen yang diekstrak:

URI Pola URI Permintaan Cocok
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

Pencocokan jalur

Pola jalur berikut didukung:

URI Pola URI Permintaan Cocok Argumen yang Diekstrak
www.example.com/users https://www.example.com/users Tidak ada
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: "" (String kosong)
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 Tidak ada
www.example.com/users https://www.example.com/users/ ❌ (Garis miring di akhir membuat segmen tambahan) T/A

Pencocokan kueri

Urutan parameter kueri di URI permintaan tidak harus cocok dengan urutan di URI pola. Selain itu, parameter yang ada di URI permintaan, tetapi tidak ada di URI pola akan diabaikan.

Pola parameter kueri berikut didukung:

URI Pola URI Permintaan Argumen yang Diekstrak
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: "" (String kosong)
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"

Pencocokan fragmen

Jenis pola fragmen berikut didukung:

URI Pola URI Permintaan Argumen yang Diekstrak
www.example.com/#section1 https://www.example.com/#section1 Tidak ada
www.example.com/#section_{id} https://www.example.com/#section_123 id: "123"
www.example.com/#section_.* https://www.example.com/#section_123 Tidak ada

Jenis data yang didukung

UriDeepLinkMatcher mendukung deserialisasi argumen URI ke dalam jenis primitif, enum, koleksi, dan objek kustom. Serialisasi dibagi menjadi dua kategori:

  • Serialisasi standar: Menggunakan kotlinx.serialization untuk mendeserialisasi ke:
    • Primitif (Boolean, Int, Long, Float, Double, Char, Byte, Short) dan String
    • Enum
    • Set, List, atau Array dari primitif, string, atau enum
    • Class @Serializable bertingkat (yang propertinya diratakan ke dalam placeholder URI individual)
  • Serialisasi kustom dengan DeepLinkSerializer: Mengonversi antara satu String dan objek kustom, jenis eksternal (seperti java.time.LocalDate), atau koleksi yang dibatasi kustom.

Serialisasi standar

UriDeepLinkMatcher dapat langsung digunakan untuk jenis standar dan struktur yang diratakan tanpa memerlukan implementasi serializer kustom.

Primitif dan string

UriDeepLinkMatcher otomatis mendekode jenis primitif (Boolean, Int, Long, Float, Double, Char, Byte, Short) dan String:

Enum

Nilai enum dicocokkan dengan peka huruf besar/kecil terhadap nama elemen enum:

Koleksi kueri berulang

Parameter kueri dengan kunci berulang (seperti ?id=10&id=20) otomatis dideserialisasi ke dalam List<T>, Set<T>, atau Array<T> dengan T adalah jenis primitif type, String, atau enum:

Class @Serializable bertingkat

Jika NavKey berisi properti yang jenisnya adalah class @Serializable lain, UriDeepLinkMatcher akan meratakan propertinya sehingga setiap properti class bertingkat dipetakan langsung ke parameter URI individual dengan nama yang sama:

Untuk mendeserialisasi objek kustom (seperti Filter(key = "brand", value = "pixel")), jenis eksternal (seperti java.time.LocalDate), atau string yang dibatasi kustom (seperti nilai yang dipisahkan koma), perluas DeepLinkSerializer<T>.

DeepLinkSerializer<T> adalah KSerializer<T> abstrak yang mengonversi antara String dan T:

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

Misalnya, pertimbangkan definisi Filter dan FilterSerializer yang digunakan dalam cuplikan berikut:

Objek kustom tunggal

Untuk mendekode objek dari string parameter URI tunggal (seperti ?filter=brand:google), anotasi properti dengan @Serializable(with = ...):

Objek kustom dalam parameter kueri berulang

Untuk mendeserialisasi parameter kueri berulang ke dalam koleksi objek kustom (List<T>, Set<T>, atau Array<T>), terapkan DeepLinkSerializer<T> untuk jenis elemen T dan anotasi argumen jenis properti dengan @Serializable(with = ...):

Koleksi yang dibatasi dalam parameter tunggal

Untuk mengurai nilai yang dipisahkan koma atau dibatasi kustom (seperti ?ids=1,2,3) ke dalam koleksi, terapkan DeepLinkSerializer untuk seluruh jenis koleksi dan anotasi properti dengan @Serializable(with = ...):

Hasil pencocokan dan validasi argumen

UriDeepLinkMatcher membedakan antara ketidakcocokan (menampilkan null sehingga pencocok lain dapat dicoba) dan konfigurasi yang tidak didukung (menampilkan pengecualian).

Ketidakcocokan

Ketidakcocokan terjadi saat URI permintaan yang masuk tidak memenuhi persyaratan pola atau jenis:

  • Parameter wajib tidak ada: Properti kunci yang tidak dapat di-null-kan tanpa nilai default yang parameter URI-nya tidak ada dari URI permintaan.
  • Kegagalan penguraian jenis: Nilai argumen yang diekstrak yang tidak dapat diuraikan ke dalam jenis properti yang diharapkan (misalnya, "abc" untuk properti Int ).

Jika terjadi ketidakcocokan, UriDeepLinkMatcher.match akan menampilkan null, sehingga pencocok berikutnya dapat dievaluasi.

Pertimbangkan class kunci dan pencocok yang dikonfigurasi dengan nilai default, objek bertingkat, dan enum:

Tabel berikut menunjukkan hasil pencocokan untuk berbagai URI permintaan:

URI Permintaan Hasil Dekode Hasil Pencocokan
https://www.example.com/map/paris?zoom=15&style=dark&layer=SATELLITE Berhasil (Semua parameter disediakan) UriMatchResult(MapKey("paris", 15, LayerOptions("dark", MapLayer.SATELLITE)))
https://www.example.com/map/paris?style=dark Berhasil (zoom default ke 12, layer ke STANDARD) UriMatchResult(MapKey("paris", 12, LayerOptions("dark", MapLayer.STANDARD)))
https://www.example.com/map/paris?zoom=&style=dark Berhasil (Parameter kueri opsional kosong menggunakan default 12) UriMatchResult(MapKey("paris", 12, LayerOptions("dark", MapLayer.STANDARD)))
https://www.example.com/map?style=dark Tidak cocok (Parameter location wajib tidak ada) null
https://www.example.com/map/paris?zoom=close&style=dark Tidak cocok ("close" bukan Int) null
https://www.example.com/map/paris?style=dark&layer=HYBRID Tidak cocok ("HYBRID" tidak ada dalam enum) null

Konfigurasi yang tidak didukung

Jika class kunci Anda berisi jenis data yang tidak didukung, UriDeepLinkMatcher akan menampilkan pengecualian selama pencocokan, bukan menampilkan null.

  • Peta dan koleksi multidimensi: UriDeepLinkMatcher hanya mendukung koleksi primitif, string, enum, atau jenis kustom satu dimensi yang dianotasi dengan DeepLinkSerializer. Map jenis menampilkan an IllegalArgumentException, sedangkan koleksi bertingkat (seperti List<List<String>>) menampilkan SerializationException.
  • Koleksi objek kustom yang tidak dianotasi: Koleksi jenis kustom (seperti List<Filter>) menampilkan SerializationException kecuali jika jenis elemen dianotasi dengan DeepLinkSerializer.
  • Class bertingkat yang tidak diratakan: Class @Serializable tidak dapat di petakan ke satu placeholder (seperti ?user={user}) tanpa DeepLinkSerializer.

Perbandingan UriMatchResult

Instance UriMatchResult diberi peringkat menggunakan kriteria berikut secara berurutan:

  1. Jenis MatchResult: UriMatchResult diberi peringkat lebih tinggi daripada jenis MatchResult lainnya.
  2. Jalur persis: Pencocokan jalur literal diberi peringkat lebih tinggi daripada pencocokan placeholder atau karakter pengganti.
  3. Jumlah argumen jalur: Pencocokan dengan lebih banyak argumen jalur diberi peringkat lebih tinggi.
  4. Keberadaan argumen: Pencocokan yang mengambil argumen diberi peringkat lebih tinggi daripada pencocokan yang tidak mengambil argumen.
  5. Jumlah argumen total: Jumlah total argumen (jalur, kueri, fragmen) adalah pemutus seri terakhir.

Menyesuaikan UriDeepLinkMatcher

UriDeepLinkMatcher adalah class open yang dapat Anda buat subclass-nya untuk menyesuaikan pencocokan URI dan perilaku ekstraksi argumen:

  • matchRequest: Titik entri pencocokan tingkat atas untuk DeepLinkRequest yang masuk. Ganti ini untuk memeriksa tambahan permintaan atau menerapkan prasyarat kustom sebelum pencocokan URI.
  • matchUri: Mencocokkan DeepLinkUri dengan pola yang dikonfigurasi. Ganti ini untuk mencegat dan menormalkan URI yang masuk (misalnya, menulis ulang subdomain dinamis atau format jalur lama) sebelum memanggil super.matchUri.
  • matchArguments: Mendeserialisasi peta argumen jalur, kueri, dan fragmen yang diekstrak ke dalam instance kunci navigasi menggunakan serializer yang disediakan. Ganti ini untuk menyuntikkan nilai dinamis atau mengubah argumen sebelum pembuatan instance kunci.

Contoh berikut menunjukkan pembuatan subclass UriDeepLinkMatcher untuk menormalkan awalan jalur URL lama sebelum pencocokan: