Реализация Deep Linking в мобильном приложении

TRUETECH занимается разработкой, поддержкой и обслуживанием мобильных приложений iOS, Android, PWA. Имеем большой опыт и экспертизу для публикации мобильных приложений в популярные маркеты Google Play, App Store, Amazon, AppGallery и другие.
Разработка и поддержка любых видов мобильных приложений:
Информационные и развлекательные мобильные приложения
Новостные приложения, игры, справочники, онлайн-каталоги, погодные, фитнес и здоровье, туристические, образовательные, социальные сети и мессенджеры, квиз, блоги и подкасты, форумы, агрегаторы
Мобильные приложения электронной коммерции
Интернет-магазины, B2B-приложения, маркетплейсы, онлайн-обменники, кэшбэк-сервисы, биржи, дропшиппинг-платформы, программы лояльности, доставка еды и товаров, платежные системы
Мобильные приложения для управления бизнес-процессами
CRM-системы, ERP-системы, управление проектами, инструменты для команды продаж, учет финансов, управление производством, логистика и доставка, управление персоналом, системы мониторинга данных
Мобильные приложения электронных услуг
Доски объявлений, онлайн-школы, онлайн-кинотеатры, платформы предоставления электронных услуг, платформы кешбека, видеохостинги, тематические порталы, платформы онлайн-бронирования и записи, платформы онлайн-торговли

Это лишь некоторые из типы мобильных приложений, с которыми мы работаем, и каждый из них может иметь свои специфические особенности и функциональность, а также быть адаптированным под конкретные потребности и цели клиента.

Предлагаемые услуги
Показано 1 из 1 услугВсе 1735 услуг
Реализация Deep Linking в мобильном приложении
Средняя
от 1 рабочего дня до 3 рабочих дней
Часто задаваемые вопросы
Наши компетенции:
Этапы разработки
Последние работы
  • image_mobile-applications_feedme_467_0.webp
    Разработка мобильного приложения для компании FEEDME
    760
  • image_mobile-applications_xoomer_471_0.webp
    Разработка мобильного приложения для компании XOOMER
    640
  • image_mobile-applications_rhl_428_0.webp
    Разработка мобильного приложения для компании RHL
    1056
  • image_mobile-applications_zippy_411_0.webp
    Разработка мобильного приложения для компании ZIPPY
    947
  • image_mobile-applications_affhome_429_0.webp
    Разработка мобильного приложения для компании Affhome
    878
  • image_mobile-applications_flavors_409_0.webp
    Разработка мобильного приложения для компании FLAVORS
    450

Реализация Deep Linking в мобильном приложении

Deep Link — это URL, который открывает конкретный экран в мобильном приложении. Не главную страницу, а именно нужный контент: товар, профиль, статью, страницу оплаты. Казалось бы, просто — пока не столкнёшься с разницей между Custom URL Scheme, Universal Links, App Links, Deferred Deep Links и тем, как каждый из них ломается в своём специфичном месте.

Три типа deep links

Custom URL Scheme (myapp://product/123) — самый простой, но самый ненадёжный. Если приложение не установлено — браузер показывает ошибку, никакого fallback. Несколько приложений могут зарегистрировать одну схему — непредсказуемо какое откроется. Подходит только для внутренних сценариев: кросс-апп коммуникация внутри своей экосистемы.

Universal Links (iOS) / App Links (Android) — HTTP/HTTPS ссылки, которые операционная система перехватывает и открывает в приложении вместо браузера. Если приложение не установлено — обычный браузер. Надёжно, верифицированно, правильный fallback. Это стандарт для production.

Deferred Deep Links — ссылка сохраняется даже если приложение не установлено. Пользователь тапает ссылку → App Store → устанавливает приложение → открывает → попадает на нужный экран. Реализуется через Firebase Dynamic Links (deprecated с 2025-08), Branch.io или Adjust.

Universal Links на iOS

Требует файл apple-app-site-association (AASA) на сервере:

// https://yourdomain.com/.well-known/apple-app-site-association
{
  "applinks": {
    "apps": [],
    "details": [
      {
        "appIDs": ["TEAMID.com.company.app"],
        "components": [
          { "/": "/product/*", "comment": "Страницы товаров" },
          { "/": "/profile/*" },
          { "/": "/order/*" },
          { "/": "/promo/*", "?": { "ref": "?" } }
        ]
      }
    ]
  }
}

AASA должен отдаваться с Content-Type: application/json, без редиректов, с кодом 200. Apple CDN кэширует его агрессивно — изменения вступают в силу с задержкой до 48 часов (Apple периодически обходит AASA в фоне). На iOS 16+ добавился "mode": "developer" для ускорения обновления AASA в debug.

В Info.plist — Associated Domains:

<key>com.apple.developer.associated-domains</key>
<array>
    <string>applinks:yourdomain.com</string>
    <string>applinks:www.yourdomain.com</string>
</array>

Обработка в SceneDelegate:

func scene(_ scene: UIScene, continue userActivity: NSUserActivity) {
    guard userActivity.activityType == NSUserActivityTypeBrowsingWeb,
          let url = userActivity.webpageURL else { return }
    DeepLinkRouter.shared.handle(url: url)
}

App Links на Android

Аналог Universal Links. Файл assetlinks.json на сервере:

// https://yourdomain.com/.well-known/assetlinks.json
[{
  "relation": ["delegate_permission/common.handle_all_urls"],
  "target": {
    "namespace": "android_app",
    "package_name": "com.company.app",
    "sha256_cert_fingerprints": ["AA:BB:CC:..."]
  }
}]

SHA256 fingerprint берётся из keystore: keytool -list -v -keystore release.jks. Для debug и release — разные fingerprints, оба нужно добавить в production assetlinks.json или использовать разные домены.

В AndroidManifest.xml:

<activity android:name=".MainActivity">
    <intent-filter android:autoVerify="true">
        <action android:name="android.intent.action.VIEW" />
        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="android.intent.category.BROWSABLE" />
        <data
            android:scheme="https"
            android:host="yourdomain.com"
            android:pathPrefix="/product/" />
    </intent-filter>
</activity>

android:autoVerify="true" запускает верификацию домена при установке. Проверить верификацию: adb shell pm get-app-links com.company.app. Если STATE_APPROVED — App Links работают. Если STATE_NO_RESPONSE или STATE_FAILED_VERIFICATION — проблема с AASA или сертификатом.

Частая проблема на Android 12+: даже с успешной верификацией пользователь может выбрать "Открывать в браузере" в системных настройках. Приложение не может это контролировать программно.

Роутер на клиенте

Централизованный роутер — обязательно. Никаких if (url.contains("product")) разбросанных по коду.

// Android
class DeepLinkRouter {
    fun handle(intent: Intent, navController: NavController) {
        val uri = intent.data ?: return
        val path = uri.path ?: return

        val route = when {
            path.matches(Regex("/product/(\\d+)")) -> {
                val productId = uri.lastPathSegment ?: return
                Route.ProductDetail(productId)
            }
            path.matches(Regex("/order/(\\w+)")) -> {
                Route.OrderDetail(uri.lastPathSegment ?: return)
            }
            path == "/profile" -> Route.Profile
            path.startsWith("/promo/") -> {
                val ref = uri.getQueryParameter("ref")
                Route.Promo(uri.lastPathSegment ?: return, ref)
            }
            else -> {
                // Неизвестный маршрут — открыть в браузере
                openInBrowser(uri)
                return
            }
        }
        navController.navigate(route)
    }
}
// iOS
final class DeepLinkRouter {
    func handle(url: URL) {
        guard let components = URLComponents(url: url, resolvingAgainstBaseURL: false) else { return }
        let pathComponents = components.path.split(separator: "/").map(String.init)

        switch pathComponents.first {
        case "product" where pathComponents.count == 2:
            navigationManager.push(.productDetail(id: pathComponents[1]))
        case "order" where pathComponents.count == 2:
            navigationManager.push(.orderDetail(id: pathComponents[1]))
        case "profile":
            navigationManager.push(.profile)
        default:
            UIApplication.shared.open(url) // fallback в браузер
        }
    }
}

Deferred Deep Links через Branch.io

Firebase Dynamic Links официально deprecated с августа 2025. Альтернативы: Branch.io, Adjust, AppsFlyer, Airbridge — все предоставляют SDK для iOS и Android.

Branch.io SDK отслеживает клик по ссылке до установки и восстанавливает параметры после первого запуска:

Branch.getInstance().initSession(
    branchReferralInitListener = { params, error ->
        if (error == null && params != null) {
            val productId = params.getString("product_id")
            val ref = params.getString("ref")
            if (productId != null) {
                deepLinkRouter.navigate(Route.ProductDetail(productId))
            }
        }
    },
    isReferrable = true,
    activity = this
)

Branch initSession вызывается при каждом запуске — SDK определяет, был ли это organic запуск или переход по ссылке.

Тестирование

Верификация App Links: adb shell am start -W -a android.intent.action.VIEW -d "https://yourdomain.com/product/123" com.company.app

Верификация Universal Links на симуляторе — невозможна. Только на физическом устройстве через xcrun simctl openurl booted "https://yourdomain.com/product/123" для симулятора iOS 14+, или через Notes.app → tap по ссылке.

Проверка AASA: curl -I https://yourdomain.com/.well-known/apple-app-site-association — нужен 200, без редиректов.

Apple предоставляет валидатор: https://app-site-association.cdn-apple.com/a/v1/yourdomain.com — так Apple сам кэширует ваш AASA файл.

Типичные ошибки

Redirect на CDN ломает App Links. Если yourdomain.com редиректит на www.yourdomain.com, а AASA лежит только на одном — верификация падает. AASA нужен на обоих доменах.

Неправильный Content-Type. AASA с Content-Type: text/html — Apple не принимает. Только application/json.

Deep link при cold start vs warm start. На Android Intent приходит в onCreate при cold start и в onNewIntent при warm start. Если обрабатываете только в onCreate — deep link при warm start игнорируется. Обрабатывайте в обоих местах.

Навигация до инициализации. Роутер пытается навигировать до того, как NavController готов. Нужна очередь pending deep links, которая обрабатывается после инициализации навигации.

Реализация Universal Links + App Links + роутер + deferred deep links: 2-4 недели. Стоимость рассчитывается индивидуально.