Universal links и Android App Links: настройка на стороне сайта

Настройка universal links и Android App Links на сайте: файлы apple-app-site-association и assetlinks.json, правила сервера, проверка и запасные варианты.

Содержание

Universal links (iOS) и Android App Links открывают ваше приложение вместо сайта, когда человек нажимает обычную ссылку https://, а со стороны сайта нужны два JSON-файла, которые вы размещаете сами: apple-app-site-association для iOS и assetlinks.json для Android. Оба лежат в /.well-known/ на каждом домене, который обрабатывает приложение, оба должны отдаваться по HTTPS без редиректов, и в каждом назначено приложение, которому разрешено открывать ваши URL. Нужна и соответствующая настройка в самом приложении (entitlement в iOS, intent-фильтр в Android); она показана ниже рядом с каждым файлом.

Обе системы связывают сайт и приложение в двух направлениях: приложение объявляет, какие домены оно обрабатывает, а сайт это подтверждает. Apple описывает universal links как обычные ссылки HTTP или HTTPS, так что один URL работает и для сайта, и для приложения, а у пользователей без приложения страница открывается в браузере (Apple). Android App Links, по словам Google, строятся на той же системе интентов, что и другие deep links, но добавляют шаг проверки с файлом Digital Asset Links на вашем сайте (Android Developers).

iOS universal links Android App Links
Файл на сайте apple-app-site-association assetlinks.json
Расположение https://<domain>/.well-known/apple-app-site-association https://<domain>/.well-known/assetlinks.json
Что объявляет приложение Entitlement Associated Domains, applinks:<domain> Intent-фильтр с android:autoVerify="true"
Как определяется приложение Team ID плюс bundle ID Имя пакета плюс отпечаток сертификата подписи
Когда проверяется При установке, через CDN Apple При установке, а на Android 15 и новее ещё и в фоне
Universal Links и App Links работают, когда есть обе стороны: приложение объявляет домен (Associated Domains или intent filter с autoVerify), а сайт отдаёт файл в .well-known (apple-app-site-association или assetlinks.json)

«Deep link» — более широкий термин. Обычный deep link может использовать собственную схему или непроверенную ссылку https://; universal links и App Links — проверенные.

Файл для iOS: apple-app-site-association

Создайте файл с именем apple-app-site-association без расширения и перечислите в нём идентификаторы приложения и шаблоны URL, которые приложение должно открывать. Это структура из документации Apple в сокращённом виде:

{
  "applinks": {
    "details": [
      {
        "appIDs": ["ABCDE12345.com.example.app"],
        "components": [
          { "/": "/buy/*", "comment": "Open URLs that start with /buy/ in the app." },
          { "/": "/help/website/*", "exclude": true, "comment": "Keep these in the browser." }
        ]
      }
    ]
  }
}

Значение appIDs — префикс идентификатора приложения (ваш Team ID), точка и bundle identifier. Каждая запись в components соответствует части URL, а "exclude": true велит системе не открывать подходящие URL в приложении (Apple, Supporting associated domains). Apple принимает и старый формат с appID и paths; в заметке об отладке сказано не смешивать два формата (TN3155).

Разместите его по адресу https://<полное доменное имя>/.well-known/apple-app-site-association с действующим сертификатом и без редиректов. Три правила со страниц Apple, на которых чаще всего ошибаются:

  • Каждому поддомену нужна своя запись в приложении. Файл на example.com обслуживает applinks:example.com и applinks:*.example.com, а отдельному поддомену вроде www.example.com нужен собственный файл.
  • Файл должен быть доступен с любого IP-адреса и для любого user agent. Ответ 403 или 404 от файрвола, фильтра ботов или страницы входа не даёт серверам Apple его закэшировать.
  • Начиная с iOS 14 устройства не берут файл с вашего сервера. Его загружает и кэширует CDN Apple, устройства проверяют обновления примерно раз в неделю, а сбросить кэш напрямую нельзя; переустановка приложения загружает более свежую копию (TN3155).

При разработке можно добавить ?mode=developer в запись entitlement (applinks:example.com?mode=developer), чтобы устройство читало файл прямо с вашего сервера, а не из CDN Apple.

Файл для Android: assetlinks.json

assetlinks.json — массив утверждений, в которых указаны ваш пакет и отпечаток SHA-256 сертификата, которым подписано приложение. Пример Google для одного приложения:

[{
  "relation": ["delegate_permission/common.handle_all_urls"],
  "target": {
    "namespace": "android_app",
    "package_name": "com.example",
    "sha256_cert_fingerprints":
    ["14:6D:E9:83:C5:73:06:50:D8:EE:B9:95:2F:34:FC:64:16:A0:83:42:E6:1D:BE:A8:8A:04:96:B2:3F:CF:44:E5"]
  }
}]

Замените имя пакета и отпечаток своими. Требования из руководства Google (обновлено 23 октября 2026):

  • Отдавайте файл по адресу https://<domain>/.well-known/assetlinks.json с типом содержимого application/json.
  • Используйте HTTPS, даже если intent-фильтры приложения объявляют и http.
  • Никаких редиректов, ни 301, ни 302.
  • Публикуйте файл на каждом домене-хосте, который обрабатывает приложение.
  • В одном файле можно перечислить несколько приложений, а поле sha256_cert_fingerprints принимает несколько отпечатков, например для отладочной и рабочей сборок.

Если вы используете Play App Signing, отпечаток из локального keytool, как правило, не совпадёт с тем, что стоит на устройствах пользователей. Google советует взять правильный фрагмент JSON в Play Console, в разделе Release > Setup > App signing.

Со стороны приложения нужен intent-фильтр с autoVerify. Это форма из документации Android:

<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="http" />
    <data android:scheme="https" />
    <data android:host="www.example.com" />
</intent-filter>

Android проверяет каждое имя хоста в таких фильтрах, а для хоста с подстановкой вроде *.example.com нужен файл на корневом домене example.com (Android Developers). На Android 15 и новее проверка ещё и выполняется периодически, а изменение файла может распространяться до семи дней; на Android 14 и ниже файл читается только при установке или обновлении (Android Developers).

Чек-лист для сервера

Оба файла ломаются по одним и тем же нескольким причинам, поэтому проверьте сервер сразу для обоих:

Проверка Зачем Как проверить
HTTPS Нужен обеим платформам, а Apple требует действующий сертификат Откройте URL в браузере
Нет 301 и 302 Редиректы не поддерживаются ни для одного из файлов curl -sI показывает 200
iOS: доступ для любых IP и user agent Файл загружает CDN Apple, а файрвол или фильтр ботов его блокирует curl -A "MyAgent-Bot/1.0" <url> возвращает файл
Android: Content-Type: application/json Google указывает это как требование Заголовок из curl -sI
Тот же файл на каждом домене и поддомене из списка Каждый хост проверяется отдельно Выполните проверку для каждого хоста

Для типа содержимого отдача обоих файлов как application/json сохраняет настройку одинаковой. В документации Apple тип содержимого для iOS-файла не указан, так что эту часть считайте вашим выбором. Статический пример для nginx:

location = /.well-known/apple-app-site-association {
    default_type application/json;
}
location = /.well-known/assetlinks.json {
    default_type application/json;
}

Как проверить, что всё работает

Сначала проверьте файл снаружи, затем поведение на устройстве. Шаги отладки от самой Apple, из TN3155:

  1. Выполните curl -v https://<domain>/.well-known/apple-app-site-association и убедитесь, что получили 200 и JSON, а не 301, 302, 403 или 404.
  2. На Mac sudo swcutil dl -d <domain> проверяет, что файл загружается, а sudo swcutil verify -d <domain> -j <path-to-JSON> -u <URL> проверяет, что URL соответствует шаблону.
  3. На iPhone вставьте ссылку в приложение «Заметки» и нажмите на неё с удержанием. Если всё настроено, появятся варианты открытия и в приложении, и в браузере.

Для Android — ручная проверка Google на Android 12 и новее (для приложения с целевой версией ниже Android 12 сначала выполните adb shell am compat enable 175408749 com.example):

adb shell pm set-app-links --package com.example 0 all
adb shell pm verify-app-links --re-verify com.example
# подождите несколько минут, затем:
adb shell pm get-app-links com.example

В выводе для каждого домена указано состояние, например verified или legacy_failure. Google также предлагает Statement List Generator and Tester (инструмент Digital Asset Links) для проверки существующего файла утверждений. Для более широкой процедуры тестирования смотрите чек-лист тестирования мобильного сайта.

Где ссылки не открывают приложение

Ввод URL в адресную строку браузера на iOS никогда не открывает приложение, потому что это прямая навигация внутри браузера; если пользователь уже на вашем домене, ссылка на тот же домен тоже остаётся в Safari (TN3155). Решение Apple для сценариев вроде кнопки входа — другой поддомен со своей записью applinks и файлом AASA, чтобы система считала нажатие уходом с сайта.

Встроенные браузеры нужно тестировать отдельно. Apple пишет, что ссылки, нажатые в приложении-браузере или в WKWebView, могут открывать ваше приложение, но там же сказано, что сторонние браузеры сами решают, включать ли universal links («Universal links may not be enabled in every web browser», по TN3155), и что приложение, которое открывает вашу ссылку собственным вызовом open(_:), не откроет в ответ ваше (Apple). Передаёт ли браузер конкретного социального приложения ссылку вашему приложению, в документации платформ не описано, поэтому проверьте каждый нужный вам на настоящем телефоне.

Smart app banner как запасной вариант

Smart app banner — приглашение только для iOS на веб-странице: один метатег в <head> каждой страницы, где он нужен. По словам Apple, он открывает приложение, если оно установлено, а если нет, ведёт в App Store.

<meta name="apple-itunes-app" content="app-id=myAppStoreID, app-argument=https://example.com/buy/42">

app-id обязателен, а необязательный app-argument передаёт приложению URL, чтобы оно открыло нужный экран. Apple называет два ограничения: баннеры не появляются внутри фрейма и не появляются в симуляторе iOS.

Если нативного приложения у вас нет, ни один из файлов не нужен; прогрессивное веб-приложение устанавливается из браузера.

Проверьте запасную страницу на ширине телефона

Все, у кого нет приложения, и каждая ссылка, которая не передаётся приложению, попадают на вашу веб-страницу, так что она должна работать на телефоне. Mobile View Extension перезагружает вкладку с user agent, размером экрана и pixel ratio телефона, так что вы видите настоящую мобильную версию запасной страницы в нескольких размерах, а рядом можно использовать эмуляцию устройств в Chrome. Передачу в приложение расширение проверить не может: оно работает в десктопном Chrome, без событий касания и без установленных приложений, поэтому обработку ссылок проверяйте на iPhone или Android-телефоне либо в симуляторе iOS или эмуляторе Android. Для iOS без устройства смотрите статью как проверить сайт на iPhone без iPhone.

Частые вопросы

Deep links — общая категория; universal links — проверенный вид от Apple, построенный на обычных ссылках HTTP или HTTPS. Deep link может использовать и собственную схему URL, которая не привязана к сайту, который вы контролируете. Android App Links — проверенная форма на Android: обычные deep links плюс проверка Digital Asset Links.

Куда класть apple-app-site-association?

По адресу https://<domain>/.well-known/apple-app-site-association, без расширения файла, по HTTPS с действующим сертификатом и без редиректов. Каждому поддомену из списка приложения нужна своя копия.

Обычные причины: редирект, ответ 403 или 404 на файл, отсутствующая запись для поддомена или нажатие на ссылку внутри того же домена. Apple перечисляет их в TN3155; ввод URL в адресную строку или нажатие на ссылку на тот же домен во время просмотра его в Safari оставляет пользователя в браузере. Сначала проверьте файл через curl -v.

Нужны ли оба файла?

Файл нужен для каждой платформы, приложение для которой вы выпускаете. Сайту с приложениями для iOS и Android нужны оба, и они не зависят друг от друга.

Откройте следующий сайт в мобильном виде.

Установите расширение и запускайте превью устройств прямо в той вкладке, где уже работаете.