Соответствие URI для прямых ссылок

Для сопоставления иерархических URI с шаблонами и извлечения аргументов используйте UriDeepLinkMatcher . Он использует kotlinx.serialization для десериализации найденных аргументов в ваши ключевые классы.

Для создания объекта UriDeepLinkMatcher укажите шаблон DeepLinkUri и сериализатор для соответствующего ключа:

Для неиерархических URI или пользовательских схем (например, tel: см. раздел «Создание пользовательских сопоставителей глубоких ссылок» .

Поддерживаемые шаблоны сопоставления

UriDeepLinkMatcher сопоставляет URI на основе пяти их компонентов: схемы, авторитета, пути, запроса и фрагмента. В следующих разделах описывается поддерживаемый синтаксис шаблонов, заполнители аргументов и правила сопоставления для каждого компонента.

Сопоставление схем

Если в шаблоне URI отсутствует схема, будут найдены как http так и https . Чтобы найти конкретную схему, укажите её в шаблоне. Исключение составляет схема http в шаблоне, которая соответствует как http так и https запросам, тогда как 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 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/ ❌ (Конечная косая черта создает дополнительный сегмент) Н/Д

Сопоставление запросов

Порядок параметров запроса в 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 для десериализации в:
    • Примитивные типы данных ( Boolean , Int , Long , Float , Double , Char , Byte , Short ) и String
    • Перечисления
    • Set , List или Array примитивных типов, строк или перечислений.
    • Вложенные классы с @Serializable (свойства которых преобразуются в отдельные URI-заполнители)
  • Пользовательская сериализация с помощью DeepLinkSerializer : преобразует одну String в пользовательские объекты, внешние типы (например, java.time.LocalDate ) или коллекции с пользовательскими разделителями.

Стандартная сериализация

UriDeepLinkMatcher работает «из коробки» со стандартными типами и плоскими структурами, не требуя реализации пользовательских сериализаторов.

Примитивы и струны

UriDeepLinkMatcher автоматически декодирует примитивные типы ( Boolean , Int , Long , Float , Double , Char , Byte , Short ) и 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> , который преобразует данные между 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 , используемые в следующих фрагментах кода:

Отдельные пользовательские объекты

Чтобы декодировать объект из строки параметров URI (например ?filter=brand:google ), добавьте к свойству аннотацию ` @Serializable(with = ...) :

Пользовательские объекты в повторяющихся параметрах запроса

Для десериализации повторяющихся параметров запроса в коллекцию пользовательских объектов ( List<T> , Set<T> или Array<T> ) реализуйте интерфейс DeepLinkSerializer<T> для элемента типа T и аннотируйте аргумент типа свойства с помощью @Serializable(with = ...) :

Ограниченные коллекции в отдельных параметрах

Для преобразования значений, разделенных запятыми или заданными пользователем разделителями (например, ?ids=1,2,3 ), в коллекцию, реализуйте DeepLinkSerializer для всего типа коллекции и аннотируйте свойство с помощью @Serializable(with = ...) :

Проверка аргументации и сопоставление результатов.

UriDeepLinkMatcher различает несоответствия (возвращает null , чтобы можно было попробовать другие сопоставители) и неподдерживаемые конфигурации (выбрасывает исключение).

Несоответствия

Несоответствие возникает, когда входящий URI запроса не соответствует требованиям к шаблону или типу:

  • Отсутствуют обязательные параметры : Непустые ключевые свойства без значений по умолчанию, соответствующие параметры URI которых отсутствуют в URI запроса.
  • Ошибки при разборе типов : Извлеченные значения аргументов не могут быть преобразованы в ожидаемый тип свойства (например, "abc" для свойства типа Int ).

При возникновении несоответствия метод 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 по умолчанию установлено на 12 , layerSTANDARD ) 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

UriDeepLinkMatcher — это open класс, на основе которого можно создавать подклассы для настройки поведения сопоставления URI и извлечения аргументов:

  • matchRequest : Точка входа верхнего уровня для сопоставления входящего запроса DeepLinkRequest . Переопределите этот параметр, чтобы проверить дополнительные параметры запроса или применить пользовательские предварительные условия перед сопоставлением URI.
  • matchUri : Сопоставляет DeepLinkUri с заданным шаблоном. Переопределите этот параметр, чтобы перехватывать и нормализовать входящие URI (например, перезаписывать динамические поддомены или устаревшие форматы путей) перед вызовом super.matchUri .
  • matchArguments : Десериализует извлеченные карты аргументов пути, запроса и фрагмента в экземпляр навигационного ключа, используя предоставленный serializer . Переопределите этот метод, чтобы внедрять динамические значения или аргументы преобразования перед созданием экземпляра ключа.

В следующем примере демонстрируется создание подкласса UriDeepLinkMatcher для нормализации префиксов путей устаревших URL-адресов перед сопоставлением: