Вы когда-нибудь нажимали на ссылку в письме, и вместо браузера сразу открывалось приложение — на нужном товаре или экране? Это не магия, а 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 в приложение.

Как это работает технически:

  1. На сервере размещается специальный файл apple-app-site-association (AASA)
  2. Приложение в настройках указывает домены, которым доверяет
  3. При установке приложения iOS скачивает AASA-файл и запоминает, какие пути этого домена нужно открывать в приложении
  4. Когда пользователь нажимает на ссылку — 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 решают это. Механика:

  1. Пользователь нажимает на ссылку
  2. Приложения нет — его редиректят в App Store с параметрами в URL
  3. Приложение устанавливается
  4. При первом запуске оно запрашивает сервис (например, Branch, AppsFlyer, Firebase Dynamic Links) — «была ли ссылка для этого устройства?»
  5. Получает параметры и открывает нужный экран

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 — одна из тех вещей, которые при правильной настройке работают незаметно. Пользователь просто нажимает ссылку и оказывается там, где нужно. Но если настроить небрежно — получаете хаотичное поведение, которое сложно воспроизвести и отладить.