Вы когда-нибудь нажимали на ссылку в письме, и вместо браузера сразу открывалось приложение — на нужном товаре или экране? Это не магия, а Deep Links или Universal Links. Разберём, как это работает, чем они отличаются и как их правильно внедрить.
Что такое Deep Link и зачем он нужен
Deep Link — это ссылка, которая ведёт не просто в приложение, а в конкретное место внутри него. Например, не на главный экран, а сразу на карточку товара, профиль пользователя или экран оформления заказа.
Обычная ссылка открывает браузер. Deep Link говорит системе: «Открой вот это приложение и передай ему вот эти данные». Приложение уже само решает, что с ними делать.
Практическое применение:
- Push-уведомление с акцией → сразу на экран акции
- Письмо с заказом → сразу на статус заказа
- QR-код в офлайне → нужный раздел приложения
- Реферальная ссылка → регистрация с уже заполненным промокодом
Без Deep Links пользователь попадает на главный экран и сам ищет нужный раздел. Часть людей уходит на этом шаге. С Deep Links — сразу видит то, зачем пришёл.
Три типа ссылок: в чём разница
URL Scheme (Custom URL Scheme)
Самый старый способ. Работает через кастомную схему, которую приложение регистрирует в системе. Выглядит вот так:
myapp://product/12345
telegram://resolve?domain=username
vk://profile/123
Как это устроено: в Info.plist приложения прописывают схему myapp, iOS запоминает, что такие ссылки надо открывать в этом приложении. Когда пользователь нажимает на myapp://..., система ищет, кто зарегистрировал схему myapp, и запускает нужное приложение.
Плюсы:
- Просто настроить
- Работает с iOS 3
- Не требует сервера
Минусы:
- Если приложение не установлено — ничего не происходит, просто ошибка
- Схему может зарегистрировать любое другое приложение — конфликты никто не проверяет
- В браузере ссылка
myapp:// выглядит странно и не открывается как обычная веб-страница
Custom URL Scheme подходит для внутренних сценариев — например, между двумя приложениями одной компании. Для публичных ссылок лучше использовать Universal Links.
Universal Links
Apple представила Universal Links в iOS 9. Идея простая: ссылка выглядит как обычный веб-адрес, но если на устройстве есть приложение — открывается приложение. Нет приложения — открывается сайт в браузере.
https://myshop.ru/product/12345
Эта же ссылка работает и как веб-страница, и как Deep Link в приложение.
Как это работает технически:
- На сервере размещается специальный файл
apple-app-site-association (AASA)
- Приложение в настройках указывает домены, которым доверяет
- При установке приложения iOS скачивает AASA-файл и запоминает, какие пути этого домена нужно открывать в приложении
- Когда пользователь нажимает на ссылку — iOS проверяет, есть ли приложение для этого домена, и решает, куда направить
Файл apple-app-site-association — это JSON без расширения, лежит по адресу https://yourdomain.com/.well-known/apple-app-site-association:
{
"applinks": {
"apps": [],
"details": [
{
"appIDs": ["TEAMID.com.yourcompany.yourapp"],
"components": [
{
"/": "/product/*",
"comment": "Все страницы товаров"
},
{
"/": "/order/*",
"comment": "Статусы заказов"
}
]
}
]
}
}
Плюсы Universal Links:
- Ссылки выглядят как обычные URL — можно делиться в мессенджерах, письмах, соцсетях
- Если приложения нет — открывается сайт, пользователь не получает ошибку
- Нет конфликтов между приложениями: домен принадлежит вам
- Работает в Safari, в большинстве сторонних браузеров и приложений
Минусы:
- Нужен работающий сайт и возможность разместить файл на сервере
- iOS иногда кеширует AASA-файл — изменения не применяются мгновенно
- В некоторых мессенджерах (например, ВКонтакте) Universal Links не срабатывают, потому что приложение открывает ссылки во встроенном браузере
Android App Links
Аналог Universal Links для Android — называется Android App Links, работает через файл assetlinks.json. Если делаете кроссплатформенное приложение, придётся настроить оба.
Настройка Universal Links в iOS-приложении
Шаг 1 — Associated Domains
В Xcode открываем Signing & Capabilities, добавляем Associated Domains. Прописываем домены в формате:
applinks:yourdomain.ru
applinks:www.yourdomain.ru
Это говорит iOS: «При открытии ссылок с этих доменов — проверяй, есть ли наше приложение».
Шаг 2 — AASA-файл на сервере
Файл должен быть доступен по HTTPS, без редиректов, с Content-Type application/json. Расположение:
https://yourdomain.ru/.well-known/apple-app-site-association
Apple CDN скачивает этот файл при установке приложения. Важно: Apple делает это со своих серверов, а не с устройства пользователя — если у вас геоблокировка или файл недоступен извне, Universal Links не заработают.
Шаг 3 — Обработка в коде приложения
Когда пользователь переходит по Universal Link, система вызывает метод в AppDelegate или SceneDelegate:
// AppDelegate
func application(
_ application: UIApplication,
continue userActivity: NSUserActivity,
restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void
) -> Bool {
guard userActivity.activityType == NSUserActivityTypeBrowsingWeb,
let url = userActivity.webpageURL else {
return false
}
return handleDeepLink(url: url)
}
func handleDeepLink(url: URL) -> Bool {
let pathComponents = url.pathComponents
// Пример: /product/12345
if pathComponents.count >= 3,
pathComponents[1] == "product",
let productId = pathComponents[2] as String? {
navigateToProduct(id: productId)
return true
}
// Пример: /order/ABC-789
if pathComponents.count >= 3,
pathComponents[1] == "order",
let orderId = pathComponents[2] as String? {
navigateToOrder(id: orderId)
return true
}
return false
}
Если используете SwiftUI и @main-структуру, то обработку вешают через .onOpenURL:
@main
struct MyApp: App {
var body: some Scene {
WindowGroup {
ContentView()
.onOpenURL { url in
handleDeepLink(url: url)
}
}
}
}
Deferred Deep Links — особый случай
Есть сценарий, который стандартные Deep Links не решают: пользователь нажал на ссылку, но приложения нет. Его отправили в App Store, он установил приложение — и попал на главный экран, потеряв контекст.
Deferred Deep Links решают это. Механика:
- Пользователь нажимает на ссылку
- Приложения нет — его редиректят в App Store с параметрами в URL
- Приложение устанавливается
- При первом запуске оно запрашивает сервис (например, Branch, AppsFlyer, Firebase Dynamic Links) — «была ли ссылка для этого устройства?»
- Получает параметры и открывает нужный экран
Apple не даёт прямого способа передать данные через установку — нельзя просто сохранить что-то в App Store и получить при запуске. Deferred Deep Links работают через fingerprinting (IP, User-Agent, время) или через SKAdNetwork. Точность не 100%, но для маркетинговых сценариев достаточно.
Firebase Dynamic Links, кстати, Apple объявила устаревшими в 2023 году и отключила в 2025. Если вы ещё используете их — пора переходить на Branch, AppsFlyer или собственное решение.
Частые ошибки
AASA-файл не обновляется у пользователей. iOS кеширует его агрессивно. При изменении файла на сервере у существующих пользователей обновление произойдёт не сразу — только при переустановке или через несколько дней. Для критичных изменений нужно учитывать этот лаг.
Редирект перед AASA-файлом. Если /.well-known/apple-app-site-association отдаётся с 301 или 302 — Apple не пойдёт по редиректу. Файл должен отдаваться напрямую с 200.
Неверный Team ID. В AASA прописывается TEAMID.bundleidentifier. Team ID берётся из Apple Developer Portal — это 10-значный код. Ошибка в нём — и Universal Links не работают без каких-либо внятных ошибок.
Ссылка открывается в браузере внутри другого приложения. Если пользователь перешёл по ссылке из ВКонтакте, Telegram (в некоторых режимах) или другого приложения, которое использует WKWebView — Universal Links могут не срабатывать. Это ограничение системы: WKWebView не триггерит обработку Universal Links.
Нет обработки fallback. Если приложение получило ссылку, которую не умеет обработать — оно должно либо открыть главный экран, либо показать разумный экран ошибки. Нельзя просто ничего не делать.
Тестирование
Для отладки Universal Links есть несколько способов:
Apple AASA Validator — официальный инструмент Apple для проверки файла: https://app-site-association.cdn-apple.com/a/v1/yourdomain.ru. Покажет, как Apple видит ваш файл.
Симулятор не подходит — Universal Links на симуляторе работают иначе, чем на реальном устройстве. Тестируйте на железе.
Xcrun simctl для симулятора всё же есть способ:
xcrun simctl openurl booted 'https://yourdomain.ru/product/123'
Console.app — при открытии Universal Link iOS пишет логи. Фильтруйте по swcd — это демон, отвечающий за Associated Domains.
Charles Proxy или Proxyman — можно посмотреть, как iOS обращается к вашему AASA-файлу при установке.
Когда это реально влияет на бизнес
Deep Links — это не просто техническая фича для разработчиков. Они напрямую влияют на конверсию.
Несколько сценариев, где разница измеримая:
- Email-маркетинг. Ссылка в письме с акцией ведёт прямо на акционный товар. Без Deep Link пользователь попадает на главную и ищет сам — часть уходит.
- Реферальные программы. Ссылка с промокодом открывает приложение с уже применённым промокодом. Никаких «введите код вручную».
- Push-уведомления. Уведомление о новом сообщении открывает этот конкретный чат, а не список всех чатов.
- QR-коды в офлайне. На ценнике магазина — QR, который открывает карточку этого товара в приложении.
Если вы заказываете разработку мобильного приложения, уточните заранее: поддерживает ли оно Deep Links и как обрабатываются сценарии, когда приложение не установлено. Команда REEXY при разработке под iOS закладывает Universal Links в архитектуру с самого начала — переделывать навигацию постфактум дороже и сложнее.
Быстрый чеклист
Чтобы Universal Links заработали правильно:
- AASA-файл доступен по HTTPS без редиректов
- Content-Type —
application/json
- Team ID в AASA совпадает с реальным
- Associated Domains настроены в Xcode с правильными доменами
- В коде приложения есть обработчик
continue userActivity
- Есть fallback — что показывать, если путь не распознан
- Протестировано на реальном устройстве, а не только на симуляторе
- AASA проверен через официальный валидатор Apple
Universal Links — одна из тех вещей, которые при правильной настройке работают незаметно. Пользователь просто нажимает ссылку и оказывается там, где нужно. Но если настроить небрежно — получаете хаотичное поведение, которое сложно воспроизвести и отладить.