Поводом к появлению этого материала послужила задача из прошлого проекта. Нужно было расширить покрытие контента приложения новыми Deep Link-ами. Все звучало просто, но, когда начали тестировать решение, появились неочевидные проблемы: на разных версиях Android, оболочках, устройствах, приложениях Deep Link-и работали по-разному.

Вы знаете ответы на вопросы?

  • Как отработает Deep Link на ссылку, если открыть ее в SMS клиенте Honor 9 Lite (Android 9.0, EMUI 9.1.0)?

  • А если попытаться в Gmail на Samsung A70 (Android 10.0, One UI 2.5)?

  • Или попробовать Telegram на Xiaomi Mi5 (Android 8.0, MIUI Global 10.2.2.0)?

Мы знаем, потому что провели 280+ тестов и увидели все своими глазами! Еще мы узнали, как можно обработать ссылки на уровне приложения (Linkify, HTML, Span), как выполняется их диспетчеризация (Jetpack Navigation Component, airbnb/DeepLinkDispatch, Custom), в какие нюансы Android придется удариться и как эти удары смягчить :)

Надеемся, этот цикл статей поможет вам сэкономить время и силы при работе с Deep Link.

В этой части мы зафиксируем основные понятия: ​​Deep Link, Web Link, App Link. Разберем особенности каждого вида Deep Link-ов и разницу между ними.

Содержание

  1. Введение

  2. Deep Link

  3. Web Link

  4. Android App Link

  5. Другие фичи Deep Link

  6. Что нам нужно было сделать?

  7. Еще пару слов о Deep Link

  8. Резюме

Deep Link

Перед тем, как начать наше глубокое погружение, надо расставить точки над i и разобраться что же такое Deep Link? 

“Deep links are URIs of any scheme that take users to your app”

developer.andoroid.com говорит, что это URI произвольной схемы, которые переносят пользователей в наше приложение. Давайте разберем это определение по частям.

Deep links are URIs of any scheme that take users to your app”

Что такое URI? Это идентификатор ресурса. Какие виды URI есть? С этим сложнее. Основная сложность состоит в том, чтобы классифицировать URL и URN. Подробнее о “классическом” и “современном” взгляде на эти понятия можно почитать здесь

Примеры классификации URI, URL, URN.
Примеры классификации URI, URL, URN.

Мы будем пользоваться классификацией с картинки: URI — идентификатор общего вида, URL и URN его подвиды, которые не пересекаются.

Классификации URI, URL, URN в статье.
Классификации URI, URL, URN в статье.

Но это не все. Давайте посмотрим на таблицу. 

Виды идентификаторов ресурсов, их описание и примеры.

Имя

Описание

Пример

XRI

Обобщенный URI для унификации многообразия идентификаторов

xri://broadview.library.example.com/(urn:isbn:0-395-36341-1)

IRI

URI с локализацией для удобства использования в не англоговорящих странах

http://ru.wikipedia.org/wiki/Кириллица

URI

Единый идентификатор ресурса

mailto:John.Doe@example.com

URL

Единый локатор ресурса. Указывает на место, где ресурс расположен

file://C:\UserName.HostName\Projects\Wikipedia_Articles\URI.xml

URN

Единое имя ресурса. Независимо от его расположения

urn:isbn:0451450523

URC

Единая характеристика ресурса. Содержит метаинформацию о ресурсе / описание ресурса

URN:IANA:626:oit:cs:ftp-and-telnet; URL:http://www.gatech.edu/oit/cs/ftp-and-telnet.html

Author: Arrowood, Adam;

PURL

Постоянный URL. Защищает от перемещения ресурса (404)

http://purl.russian-books.com/WarAndPeace/chapter12.html

PRURL

URL, способный определить схему по контексту использования

//domain.com/img/logo.png

CURIE

Compact URI. Сокращенное представление URI

[isbn:0393315703]

Видов оказалось сильно больше. И мы уверены, что в таблице представлены не все. Давайте кратко о некоторых из них:

  • IRI — это URI с поддержкой разных языков мира

  • Uniform Resource Characteristics определяет метаданные о ресурсе

  • PURL — Persistent URL не подразумевает изменение (используется для избежания 404 ошибок)

Графически эту таблицу можно представить так:

Классификация идентификаторов ресурсов.
Классификация идентификаторов ресурсов.
Схематическое представление параметров URI (очень хорошо иллюстрирует обязательные и опциональные параметры).
Схематическое представление параметров URI (очень хорошо иллюстрирует обязательные и опциональные параметры).

Пару слов о формате URI. Он состоит из обязательных параметров:

  • scheme — определяет контекст / смысл идентификатора;

  • path — иерархические данные для идентификации ресурса.

И опциональных:

  • userinfo — информация о том, кто взаимодействует с ресурсом;

  • host — адрес расположения ресурса;

  • port — точка взаимодействия с host / конкретный процесс или сервис;

  • query — неиерархические данные для идентификации ресурса;

  • fragment — идентификация вторичного ресурса внутри исходного ресурса.

Подробнее о параметрах можно почитать тут и тут.

“Deep links are URIs of any scheme that take users to your app”

Следующая часть определения про схемы. Deep link — URI произвольной схемы. Схем море. Если схема зарегистрирована в IANA, то она считается официальной. Некоторые из популярных официальных схем:

  • geo:55.79378663446035,49.11699501723111

  • mailto:technokratos.com

  • tel:+78432776410

  • sms:+78432776410?body=hello%20technokratos

  • Другие примеры тут

Если схема не зарегистрирована в IANA, то она неофициальная. Но даже не смотря на это есть схемы, которые сыскали популярность в сообществе, например:

  • jdbc:mysql://host:port/database?params…

  • slack://open?team={TEAM_ID}

  • zoommtg://zoom.us/join?confno=<confno>...

  • Другие примеры тут

“Mobile deep links are one example of a class of unofficial URI schemes that allow for linking directly to a specific location in a mobile app.”

Есть специальных подвид неофициальных схем, которые используются для перехода в мобильные приложения. Наверное, кто-то из вас видел подобное:

  • myapp://example/path/to/resource

  • superapp://example/path/to/resource

  • wow://example/path/to/resource

“Deep links are URIs of any scheme that take users to your app

Ну и наконец, deep link, в большинстве случаев, используется для редиректа пользователя в ваше мобильное приложение. Посмотрите на три примера. На каждом из них изображены сценарии перехода в мобильное приложение по ссылке.

Примеры перехода в мобильное приложение по deep link.
Примеры перехода в мобильное приложение по deep link.

“Users following links on devices have one goal in mind: to get to the content they want to see.”

Снова обратимся к developer.android.com. Там написано нечто подобное: “Пользователи, переходящие по ссылкам на устройствах, преследуют одну цель:  добраться до контента, который они хотят видеть”. Казалось бы, вcе просто:) 

Но это был бы не Android, если история закончилась вот так. Чтобы добраться до “content they want to see” нужно еще кое-что. Видели когда-нибудь такой диалог?

Диалог выбора приложения для открытия ссылки.
Диалог выбора приложения для открытия ссылки.

“This dialog allows the user to select one of multiple apps, including your app, that can handle the given deep link”

При нажатии на ссылку система показывает (не всегда, но об этом после) пользователю disambiguation dialog. В нем отображается список приложений-кандидатов для обработки перехода по ссылки. Список формируется в зависимости от ссылки и intent-filter установленных приложений (об этом тоже после). Кроме списка приложений, пользователю доступны две опции:

  • Just once (Только сейчас) открывает выбранное приложение и попросит заново выбрать из списка кандидатов при повторном нажатии. При этом система может запомнить предыдущий выбор и показать его в самом вверху диалога (возможно, для удобства пользователя).

Пример работы just once. До выбора приложения первым в списке показывается браузер. После выбора “Template” система покажет его в вверху списка.
Пример работы just once. До выбора приложения первым в списке показывается браузер. После выбора “Template” система покажет его в вверху списка.
  • Always (Всегда) запомнит выбор и больше не будет просить его сделать. В настройках приложения можно будет найти ссылки, которые всегда обрабатывается приложением и изменить поведение при необходимости.

Пример работы always. Единожды выбрав приложение-обработки, система больше не будет предлагать пользователю сделать выбор.
Пример работы always. Единожды выбрав приложение-обработки, система больше не будет предлагать пользователю сделать выбор.

Web Link

“Web links are deep links that always use the HTTP, HTTPS schema”

Теперь поговорим о web link. Это подвид deep link. Но в отличие от них, web link могут иметь только http и https схемы.

Очень важный момент: на Android 11 и ниже клик по web link может быть обработан вашим приложением, но начиная с 12 версии, web link открываются только в браузере. Это может быть связано с тем, что Google настаивает на использовании Android App Links.

Различие в обработке Web Link на разных версиях Android. На Android 11- (сверху) по клику на https-ссылку пользователю предлагается выбрать приложение. На Android 12+ (снизу) выполняется прямой переход в браузер.

Android App Link

“Android M (23) Will Support App Deep Linking Without That Annoying Selector Prompt”

В Android 6.0 появилась возможность выполнять переход по deep link без disambiguation dialog. Эта фича дает пользователю возможность не совершать дополнительных действий и сделать прямой переход в приложение, улучшая пользовательский опыт. Именно с версии 6.0 и появились Android App Link.

“Android App Links are web links that contain the autoVerify attribute”

Давайте по порядку. 

Q: Почему app link это web link? 

A: Потому что app link связывается с веб-доменом по протоколу http (ссылка).

https://domain.name/.well-known/assetlinks.json

Q: Зачем связываться с веб-доменом? 

A: Для того, чтобы выполнить верификацию приложения, то есть указать системе, что именно это приложение ответственно за выбранный домен (“... to associate an app with a web domain they own."). Получается, после успешной верификации система знает, кому адресовать переход по ссылке и может не открывать disambiguation dialog.

https://domain.name/.well-known/assetlinks.json

Q: Как происходит связывание между приложением и веб-доменом? 

A: Автоматически (“...contain the autoVerify attribute”). Посмотрим на схему. Во время установки приложения система по autoVerify атрибуту в intent-filter понимает, что необходимо выполнить верификацию. Так как приложение обычно скачивается из сети (Google Play Store, например), это самый удобный момент для выполнения http запроса на специальный ресурс (/.well-known/assetlinks.json, который описан в спецификации Digital Asset Link). В случае успеха система выполняет ассоциацию. Подробнее здесь.

Схема связывание приложения и веб-домена в момент установки. Связывание выполняется один раз — во время установки приложения.
Схема связывание приложения и веб-домена в момент установки. Связывание выполняется один раз — во время установки приложения.
Спойлер для самых пытливых читателей

Ранее было сказано, что web link не откроется на Android 12. Но web link можно превратить в app link и обойти это ограничение!

Другие фичи Deep Link

Также доступен поиск по контенту, на который есть deep link. На примере видно, что при вводе “Kenny” в поисковую строку у нас есть возможность перейти в другое приложение, для которого настроен deep link для обработки этой информации. Подробнее тут и тут.

Примеры использования deep link при поиске контента на устройстве.
Примеры использования deep link при поиске контента на устройстве.

Также deep link используются в дополнении к instant apps, делая вход в ваше приложении более нативным и прозрачным (ссылка). Посмотрите на каждый из примеров: пользователь нажимает на ссылку и сразу же переходит в ваше приложение (уменьшается порог вхождения, расширяются воронки, повышается конверсия!).

Пример использования технологии instant apps.
Пример использования технологии instant apps.

Что нам нужно было сделать?

Теперь, когда вы на 50% в теме, можем переходить к разбору задачи. Нам было необходимо реализовать переход в приложение по ссылкам: 

  • scheme: http, https

  • host: domain1.domain2.ru, domain1.domain3.ru

  • path: /, /landing, /landing/, /path1/path2/{id}

То есть сделать так, чтобы все эти ссылки:

Тонна ссылок
  • http://domain1.domain2.ru

  • http://domain1.domain2.ru/

  • http://domain1.domain2.ru/landing

  • http://domain1.domain2.ru/landing/

  • http://domain1.domain2.ru/path1/path2/{id}

  • http://domain1.domain2.ru/path1/path2/{id}/

  • https://domain1.domain2.ru

  • https://domain1.domain2.ru/

  • https://domain1.domain2.ru/landing

  • https://domain1.domain2.ru/landing/

  • https://domain1.domain2.ru/path1/path2/{id}

  • https://domain1.domain2.ru/path1/path2/{id}/

  • http://domain1.domain3.ru

  • http://domain1.domain3.ru/

  • http://domain1.domain3.ru/landing

  • http://domain1.domain3.ru/landing/

  • http://domain1.domain3.ru/path1/path2/{id}

  • http://domain1.domain3.ru/path1/path2/{id}/

  • https://domain1.domain3.ru

  • https://domain1.domain3.ru/

  • https://domain1.domain3.ru/landing

  • https://domain1.domain3.ru/landing/

  • https://domain1.domain3.ru/path1/path2/{id}

  • https://domain1.domain3.ru/path1/path2/{id}/

стали диплинками. На это уже сложно смотреть... Проще только потерять какую-нибудь ссылку или сделать опечатки :)

Тогда мы решили придумать визуальную документацию deep link — Deep Link Tree. Она нужна для того, чтобы не забыть обработать ни один URL и сделать представление более наглядным. 

Пример Deep Link Tree. Уровни дерева состоят из основных частей любой ссылки: scheme, host, port и path.
Пример Deep Link Tree. Уровни дерева состоят из основных частей любой ссылки: scheme, host, port и path.

Теперь переложим нашу задачу на Deep Link Tree. Изначально, наше приложение умело обрабатывать не все возможные диплинки — они все начинались с единственной https scheme, имели один host и заканчивались несколькими path. 

Но нам этого оказалось мало. Мы хотели добавить обработку ссылок с http и еще один host. При этом, чтобы все это работало и не пришлось писать много однотипного кода.

Deep Link Tree нашего приложения ДО.
Deep Link Tree нашего приложения ДО.
Deep Link Tree нашего приложения ПОСЛЕ.
Deep Link Tree нашего приложения ПОСЛЕ.

Теперь посмотрим, как это выглядит в коде. Внутри интент-фильтра прописываем параметры (подробнее читайте в документации):

  1. Сначала указываем action VIEW, чтобы наше приложение умело обрабатывать intent на просмотр контента.

  2. Затем обязательно устанавливаем category DEFAULT для пометки активности как обработчика для событий по умолчанию.

  3. Опционально добавляем category BROWSABLE. В этом случае мы говорим системе, что наше приложение способно обработать события, которые происходят в браузере.

Следующий обязательный тег — data. В нем описано, по каким данным фильтруется intent. Для deep link в качестве этих данных выступают части URL:

  1. scheme

  2. host

  3. port

  4. различные варианты путей: path, pathPrefix, pathPattern. Об их отличиях расскажем в следующих частях

  5. mimeType

<activity 
    android:name="com.technokratos.app.MainActivity"
    android:theme="@style/AppTheme.NoActionBar">

    <intent-filter>
          <!-- 1 -->
          <action android:name="android.intent.action.VIEW" />
          <!-- 2 -->
          <category android:name="android.intent.category.DEFAULT" />
          <!-- 3 -->
          <category android:name="android.intent.category.BROWSABLE" />
    
          <!-- 4 -->
          <data android:scheme="http" />
          <!-- 5 -->
          <data android:host="technokratos" />
          <!-- 6 -->
          <data android:port="8080" />
          <!-- 7 -->
          <data android:path="/android/meetup" />
          <data android:pathPattern="/*/meetup" />
          <data android:pathPrefix="/android" />
          <!-- 8 -->
          <data android:mimeType="*" />

    </intent-filter>

</activity>

Исходная задача описана. Можем приступать к решению! Но перед этим давайте поговорим о паре очень важных моментов. 

Еще пару слов о Deep Link

Сравним URI форматы из основной спецификации и из спецификации Android. Зеленым отметим общие параметры, серым уникальные. В силу ограничений Android, мы не можем использовать параметры: userinfo, query, fragment. Поэтому URI формат урезается до нижней схемы. Обратите внимание, что в ней scheme и host стали обязательными (в отличие от scheme и path в основной спецификации).

Почему именно такой формат?

Почему именно такой формат? Есть предположение, что это сделано для того, чтобы ускорить intent-resolution в тот момент, когда система ищет приложения-кандидаты. Чем меньше атрибутов, тем меньше сравнивать, тем быстрее сравнение. Это проблема станет более ярко выраженной, когда мы будет говорить про регулярные выражения в path.

Сравнение URI форматов в основной спецификации и в Android. Серым отмечены параметры, которые не используются в Android.
Сравнение URI форматов в основной спецификации и в Android. Серым отмечены параметры, которые не используются в Android.

Получается, что из-за ограничений формата URI, Android не может обрабатывать все их виды. Из рассмотренных ранее примеров могут быть обработанными только: URL, PURL, Clean URL, а значит:

“Deep links are URIs of any scheme that take users to your app”

заменяется на:

“Deep links are URIs URLs (but not all) of any scheme that take users to your app”

и классификация идентификаторов принимает вид:

Классификация идентификаторов ресурсов. Зеленым отмечены те, которые могут быть обработаны Android.
Классификация идентификаторов ресурсов. Зеленым отмечены те, которые могут быть обработаны Android.

Резюме

Подведем итоги. Отношения между deep link, web link, app link можно представить в виде пирамиды.

Отношения между Deep Link, Web Link, Android App Link.
Отношения между Deep Link, Web Link, Android App Link.

В ее основании которой лежит Deep Link — технология, пусть и самая старая, но базовая. Deep Link используется в уведомлениях, при поиске контента, в instant apps, передаче данных внутри приложения или между ними и т.д. Основная задача — перенести пользователя в мобильное приложение. Web Link нацелен на привлечение трафика из web в mobile. Поскольку http ссылки сильно распространены, именно такие ссылки дают возможность контенту шире распространяться в интернете. Android App Link — это современный и более продуманные с технической точки зрения Web Link. Нацелен на улучшение пользовательского опыта и безопасность.

Android накладывает ограничения на формат URI. Доступно всего четыре параметра для настройки:

  • Два обязательных: scheme, host

  • Два опциональных: port, path

Сравнение URI форматов в основной спецификации и в Android. Серым отмечены параметры, которые не используются в Android.
Сравнение URI форматов в основной спецификации и в Android. Серым отмечены параметры, которые не используются в Android.

Чтобы не допустить ошибки в ваших deep link и сделать их список более наглядным, рекомендуем обратить внимание на Deep Link Tree. Для его построения начните с определения scheme, далее соедините их с host, потом с path. Deep Link Tree может быть представлен графически, простым списком URL, XML-разметкой / программным кодом в intent-filter.

Поздравляем! Вы дочитали статью и потому можете сказать себе: “Я молодец!”. Надеемся, вам понравилось. Ответь, пожалуйста, на опрос и напиши комментарий (твои впечатления, замечания, рабочий опыт, мнение — все, что считаешь нужным). Встретимся во второй части!

Валера Петров

Android-разработчик

Ангелина Евсикова

Android-разработчица Технократии


Также подписывайтесь на наш телеграм-канал «Голос Технократии». Каждое утро мы публикуем новостной дайджест из мира ИТ, а по вечерам делимся интересными и полезными мастридами.

Комментарии (0)