9 хв читанняМожливості

Deep links без SDK: Universal Links і App Links

Відкривайте застосунок за посиланням без SDK: два JSON-файли.

Marius Voß
DevRel · edge infra

Deep link - це URL, який операційна система передає застосунку замість браузера. Натисніть його при встановленому застосунку, і той відкриється. Без застосунку браузер завантажує веб-сторінку. В iOS це називається Universal Links, в Android - App Links, і жодному не потрібен SDK.

Налаштування - це два JSON-файли на домені під вашим контролем плюс один entitlement або intent filter у застосунку. Нижче: обидва файли, як вписується домен коротких посилань, частина, яку більшість посібників пропускає (застосунок отримує короткий URL, а не ціль редиректу), і три завдання, які SDK досі виконує краще.

Це важливіше, ніж раніше. Google закрив Firebase Dynamic Links 25 серпня 2025 року, і його FAQ тепер повертає HTTP 404 для таких посилань (Firebase support FAQ, дата звернення 2026-10-24). Цей FAQ вказує вендора для повного паритету функцій, а також App Links і Universal Links для застосунків, яким потрібно лише відкриватися, коли вони встановлені. Для випадку "з друку до встановлення" QR-код для завантаження застосунку ставить ту саму маршрутизацію за QR-кодом, який можна сканувати.

Коротко

  • Android App Links (Android 6, API 23, і новіші) та iOS Universal Links покривають "відкрити в застосунку, якщо встановлено, інакше веб-сторінка" без стороннього SDK.
  • Кожному потрібен домен під вашим контролем, що віддається по HTTPS, з файлом зв'язку в /.well-known/.
  • На домені коротких посилань застосунок запускається з коротким URL. Код вашого застосунку мусить перетворити його на екран. 302 ніколи не спрацьовує.
  • SDK досі виправдовують свою ціну для відкладеного deep linking, атрибуції встановлень і зшивання ідентичності. Пропускайте їх, якщо це вам не потрібно.

Як ОС вирішує відкрити ваш застосунок

Обидві системи стверджують підтверджений зв'язок між доменом і застосунком. Документація Android каже, що App Links дають підтвердженим URL сайту "негайно відкривати відповідний вміст у вашому застосунку Android без вимоги до користувача вибирати ваш застосунок у діалозі неоднозначності", а користувачі без застосунку "потрапляють замість цього на ваш сайт - жодних 404, жодних помилок" (developer.android.com/training/app-links/about, дата звернення 2026-10-24).

Android підтверджує під час встановлення. Коли intent filter має android:autoVerify="true", пристрій на Android 6 або новішій версії звіряє оголошені хости з https://hostname/.well-known/assetlinks.json під час встановлення застосунку (developer.android.com/training/app-links/verify-android-applinks, дата звернення 2026-10-24). Перед тестуванням зачекайте принаймні 20 секунд на цю перевірку. На Android 15 і новіших повторна перевірка також виконується періодично, а зміни файлу можуть поширюватися до семи днів. Android 14 і старші підхоплюють зміни лише під час встановлення чи оновлення.

Сторінки Apple для розробників (developer.apple.com, Supporting associated domains і Supporting universal links) не відобразилися під час мого завантаження 2026-10-24, тож я не цитую поведінку Apple поза тим, що показують її опубліковані приклади: файл лежить за адресою /.well-known/apple-app-site-association, застосунок оголошує applinks:your-domain у своєму entitlement Associated Domains, а Universal Link доходить до застосунку як user activity веб-перегляду з URL. Перевірте поточну сторінку Apple перед випуском, особливо щодо кешування й поведінки в режимі розробки.

Наслідок для коротких посилань випливає прямо. ОС вирішує за URL, який було натиснуто. Це відбувається до будь-якого запиту до вашого сервера. Якщо домен цього URL підтверджено для вашого застосунку, застосунок відкривається з цим URL. HTTP-запиту до короткого посилання не відбувається, тож редирект не виконується.

Два файли

Один файл на платформу, кожен за фіксованим шляхом на тому самому домені.

apple-app-site-association

Файл AASA має віддаватися за адресою https://yourdomain.example/.well-known/apple-app-site-association. Віддавайте його по HTTPS із дійсним ланцюжком сертифікатів, статусом 200 та Content-Type: application/json, без редиректу.

Довідник формату Apple - Supporting associated domains; його сторінка не відобразилася в мене 2026-10-24, тож сприймайте зразок нижче як загальноопубліковану форму й звіряйте її з цією сторінкою.

Мінімальна форма AASA:

{
  "applinks": {
    "details": [
      {
        "appIDs": ["ABCDE12345.com.example.acme"],
        "components": [
          {
            "/": "/spring-*",
            "comment": "Match any path starting with /spring-"
          },
          {
            "/": "/campaigns/*"
          }
        ]
      }
    ]
  }
}

appIDs - це конкатенація вашого Apple Team ID і bundle identifier застосунку, розділених крапкою. Масив components керує тим, які шляхи запускають маршрутизацію в застосунок; усе, що не збігається з компонентом, провалюється в браузер. У масиві details можна зареєструвати кілька застосунків - це корисно, якщо у вас є споживацький та корпоративний варіанти одного продукту на одному домені.

Одну деталь варто сказати прямо: "/" із шаблоном-підстановкою на кшталт /spring-* - це збіг за префіксом шляху. Синтаксис шаблонів у тому ж довіднику включає * (будь-який підрядок), ? (будь-який один символ) та об'єкти виключення. Якщо хочете збігатися з кожним шляхом на домені, використайте "/" : "/*". Якщо хочете виключити конкретний шлях із маршрутизації в застосунок - скажімо, сторінка /account/delete має завжди відкриватися в браузері, - додайте об'єкт виключення перед підстановкою:

{
  "/": "/account/delete",
  "exclude": true
}

Правила оцінюються від першого до останнього, тож ставте виключення перед підстановками.

assetlinks.json

Файл Digital Asset Links для Android лежить за адресою https://yourdomain.example/.well-known/assetlinks.json. Google документує формат на developers.google.com/digital-asset-links/v1/getting-started.

[
  {
    "relation": ["delegate_permission/common.handle_all_urls"],
    "target": {
      "namespace": "android_app",
      "package_name": "com.example.acme",
      "sha256_cert_fingerprints": [
        "AA:BB:CC:DD:EE:FF:00:11:22:33:44:55:66:77:88:99:AA:BB:CC:DD:EE:FF:00:11:22:33:44:55:66:77:88:99"
      ]
    }
  }
]

package_name - це application ID вашого застосунку в Play Store. sha256_cert_fingerprints містить SHA-256-відбитки сертифіката підпису вашого застосунку (сторінка Google каже, що мобільні цілі ідентифікуються за хешем сертифіката й назвою пакета). Отримайте його через keytool -list -v -keystore your.keystore або з налаштувань підпису Play Console, якщо застосунок підписує Play. Перелічіть кожен сертифікат, збірки з яким ви встановлюєте, зокрема debug.

На відміну від файлу AASA, файл Android не містить правил шляхів. Збіг шляхів для App Links виконується в AndroidManifest.xml через <intent-filter> з android:pathPrefix, android:pathPattern. Файл assetlinks.json стверджує володіння доменом; маніфест оголошує, які шляхи обробляє застосунок.

Послідовність розв'язання AASA: натискання короткого посилання, отримання файлу ОС при першому встановленні, влучання в кеш при наступних натисканнях

Як вписується домен коротких посилань

Посилання на кшталт go.acme.example/spring-launch - це просто URL на домені. Дайте go.acme.example два файли зв'язку й оголосіть його в застосунку, і натискання цього посилання відкриє застосунок на пристроях, де він встановлений. У цьому фокус, і водночас підступ. Застосунок отримує https://go.acme.example/spring-launch, а не сторінку, на яку посилання редиректить.

Тоді код вашого застосунку має два варіанти. Перший: зіставити шлях самому (/spring-launch означає екран spring), що працює, коли ви контролюєте slug. Другий: запитати сервер, куди веде коротке посилання, і маршрутизувати за відповіддю. В Elido немає задокументованого ендпойнта, щоб застосунок міг розв'язати slug у його ціль. Публічний редирект просто відповідає 302. Сьогодні надійний перший варіант, а прогалина є в нашому беклозі.

На пристроях без застосунку, або коли натискання відбувається там, де посилання не передаються в ОС, коротке посилання поводиться як завжди. Edge відповідає редиректом (за замовчуванням 302; посиланню можна задати 301 або 307), і браузер переходить за ним. Правила націлювання Elido можуть зіставляти за ОС, тож одне посилання може надсилати відвідувачів iOS на сторінку App Store, а відвідувачів Android - на Google Play, коли застосунку немає.

Ось що Elido робить і чого не робить для цього сьогодні, перевірено за кодом:

МожливістьСтатусДе
Віддавати apple-app-site-association для власного доменуТакВставте JSON для кожного домену в дашборді
Віддавати assetlinks.json для власного доменуТакТа сама панель
Повертати 404, коли для домену не налаштовано файлТакДомени без застосунку нічого не відкривають
Спрямовувати відвідувачів iOS і Android на різні URLТакПравила націлювання (збіг за ОС)
Відкладений deep linking після встановленняНіВикористовуйте SDK вендора
Атрибуція встановлень для кожного клікуНіКонсолі магазинів або вендор

Elido зберігає JSON, який ви складаєте, і віддає його без змін за власними шляхами /.well-known/ домену. Elido не генерує за вас Team ID, bundle ID чи відбиток сертифіката підпису; вони беруться з вашого облікового запису Apple Developer і вашого ключа підпису. Налаштування самого домену (CNAME і TLS) таке саме, як у коротких посиланнях на власному домені, а сторінка функції deep links показує потік у дашборді. Для продуктових команд, що використовують короткі посилання для онбордингу, цей шаблон покриває запрошення й реферальні посилання без додавання SDK до бінарного файлу. Половину проблеми, де нічого ще не встановлено, вирішують App Clip Codes в iOS.

Що SDK досі робить краще

Три речі лежать поза тим, що дає ОС.

Відкладений deep linking. Користувач натискає до встановлення. У ОС немає застосунку, якому передати URL, тож натискання йде в браузер, а намір втрачається. Вендори відновлюють його ймовірнісним зіставленням за даними запиту або передачею через буфер обміну. Запит Apple на згоду на відстеження робить крайні випадки неприємними. Elido цього сьогодні не робить.

Атрибуція встановлень. Без SDK ви все одно бачите встановлення в App Store Connect і Play Console, але не можете прив'язати жодне до конкретного натискання посилання. Відносні сигнали зберігаються: запускайте експерименти з розумними посиланнями і порівнюйте встановлення за кампаніями. Атрибуція на рівні пристрою потребує вендора.

Зшивання ідентичності. З'єднання натискання з адресою email чи контактом CRM - це проєкт з даними. Вендори підтримують для цього граф пристроїв.

Якщо жодне з цих трьох не має значення, примітивів ОС достатньо. Якщо має одне, наймайте вендора лише для цього завдання.

Матриця функцій: примітиви ОС і платний SDK обидва відкривають застосунок і повертаються до вебу, але лише SDK додає відкладений deep linking, атрибуцію встановлень для кожного кліку та міжплатформний граф ідентичності

Збірник налаштувань

Три місця, які треба налаштувати правильно: сервер, проєкт iOS і маніфест Android.

Вимоги до HTTPS і шляху

Віддавайте обидва файли по HTTPS із сертифікатом, що ланцюжком веде до публічного кореневого CA. Сторінка Google Digital Asset Links каже, що список тверджень "має" лежати в /.well-known/assetlinks.json, а списки деінде чи під іншими назвами недійсні (developers.google.com/digital-asset-links/v1/getting-started, дата звернення 2026-10-24). Ця сторінка не каже, чи виконуються редиректи, тож віддавайте файл напряму зі статусом 200 і не ризикуйте. Та сама порада стосується й файлу Apple.

iOS: entitlement Associated Domains

У Xcode, у Signing & Capabilities, додайте можливість Associated Domains зі значенням applinks:go.acme.example. Apple документує суфікс ?mode=developer для збірок розробки, який змушує пристрій отримувати файл із вашого сервера замість проходження через кеш Apple; я не зміг повторно перевірити цю сторінку 2026-10-24, тож підтвердьте це в документації Apple. Обробляйте вхідне посилання як user activity веб-перегляду (SwiftUI onContinueUserActivity(NSUserActivityTypeBrowsingWeb) або делегат UIKit continue userActivity) і читайте webpageURL.

Усередині activity, яка має обробляти посилання:

<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="go.acme.example"
    android:pathPrefix="/campaigns/" />
</intent-filter>

Android розглядає для автоперевірки фільтри з дією VIEW, обома категоріями вище та схемою http або https. На Android 11 і нижче система робить ваш застосунок обробником за замовчуванням, лише якщо знаходить файл Digital Asset Links для кожного хоста в маніфесті, тож один поганий хост ламає всі. На конкретному пристрої з доменом може бути пов'язаний лише один застосунок одночасно.

Перевірка роботи

В Android дайте перевірці принаймні 20 секунд після встановлення, потім виконайте adb shell pm get-app-links com.example.acme (Android 12 і новіший) і шукайте verified. Повторний запуск можна примусити через adb shell pm verify-app-links --re-verify com.example.acme. Результати на кшталт none, denied чи legacy_failure означають, що файл або відбиток хибний.

Для самого файлу API Digital Asset Links від Google перелічує твердження, які може прочитати для сайту: https://digitalassetlinks.googleapis.com/v1/statements:list?source.web.site=https://go.acme.example&relation=delegate_permission/common.handle_all_urls. Порожня відповідь означає, що Android не підтвердить застосунок.

Для обох платформ отримайте файл так, як це робив би краулер:

curl -si https://go.acme.example/.well-known/assetlinks.json | head -20
curl -si https://go.acme.example/.well-known/apple-app-site-association | head -20

Потрібен статус 200 і тіло JSON. Elido надсилає application/json для обох файлів. Типові помилки: друкарська помилка в Team ID або bundle ID, релізна збірка, чийого сертифіката підпису немає у списку відбитків, і файл, що існує лише на apex, тоді як посилання використовують субдомен.

Компроміс, сказаний прямо

Відмова від SDK для deep link прибирає залежність із бінарного файлу застосунку та відносини обміну даними з вашого повідомлення про приватність. Цифри розміру я не наводитиму; вона залежить від вендора, і я її не вимірював. Ціна: натискання до встановлення не можна прив'язати до встановлення.

Для команд ранньої стадії, де вартість встановлення за каналами ще не керує бюджетом, почніть із примітивів ОС і додайте вендора атрибуції, коли дані стануть придатними для дій.

Читайте також у блозі

Поширені запитання

Чи можна робити deep linking без Firebase або стороннього SDK?

Так, для випадку, коли застосунок уже встановлено. iOS Universal Links і Android App Links потребують домену під вашим контролем, JSON-файлу зв'язку на цьому домені та кількох рядків у застосунку. У власному FAQ щодо Firebase Dynamic Links Google вказує на ці два механізми як на варіант для deep linking у встановлені застосунки. Ви відмовляєтеся від відкладеного deep linking, тобто відкриття потрібного екрана після свіжого встановлення.

Чи працюють Universal Links і App Links із доменом короткого посилання?

Так, якщо домен короткого посилання віддає файли зв'язку, а застосунок оголошує цей домен. Підступ у тому, що операційна система відкриває застосунок із самим натиснутим коротким URL, тож застосунок мусить перетворити цей URL на екран. Він не може розраховувати, що редирект спрацював. Коли застосунок не встановлено, те саме натискання завантажується в браузері, і діє звичайний редирект.

Куди класти файли зв'язку?

Android читає https://your-domain/.well-known/assetlinks.json, і документація Google Digital Asset Links каже, що це єдине дійсне розташування. Файл Apple лежить за адресою https://your-domain/.well-known/apple-app-site-association без розширення. Віддавайте обидва по HTTPS із сертифікатом, що ланцюжком веде до публічного CA.

Чому мій застосунок Android показує вибір замість прямого відкриття?

Пряме відкриття потребує підтвердженого App Link. Android звіряє домен із assetlinks.json під час встановлення застосунку і лише тоді, коли intent filter має android:autoVerify="true". Якщо файлу немає, він хибний або вказує інший сертифікат підпису, ніж встановлена збірка, посилання поводиться як звичайний deep link.

Що таке відкладений deep linking і чи можна його пропустити?

Відкладений deep linking переносить призначення посилання крізь встановлення застосунку, тож користувач, який натиснув до встановлення, при першому запуску потрапляє на потрібний екран. Universal Links і App Links у такому разі нічого не роблять, бо застосунку, що прийняв би натискання, немає. Його можна пропустити для сценаріїв онбордингу, де достатньо головного екрана, і додавати вендора лише тоді, коли маршрутизація першого запуску рухає ваші показники.

Що з цього обробляє Elido?

Elido віддає файли apple-app-site-association та assetlinks.json для власних доменів із JSON, який ви вставляєте в налаштування домену в дашборді. Він також спрямовує відвідувачів iOS і Android на різні призначення за правилами націлювання. Відкладеного deep linking і атрибуції встановлень він не пропонує, тож за потреби використовуйте SDK вендора.

Спробуйте Elido

Вставте URL - отримайте коротке посилання

Без реєстрації. Посилання живе 30 днів. Зареєструйтесь, щоб зберегти назавжди.

Без реєстрації. Зареєструйтеся безкоштовно і отримайте 50 посилань на місяць.

Спробуйте Elido

URL-скорочувач із хостингом у ЄС: власні домени, глибока аналітика, відкритий API. Безкоштовний тариф - без кредитної картки.

Теги
mobile deep linking
universal links
app links android
deep linking without sdk
apple app site association
digital asset links

Читати далі