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

«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:
- Выполните
curl -v https://<domain>/.well-known/apple-app-site-associationи убедитесь, что получили 200 и JSON, а не 301, 302, 403 или 404. - На Mac
sudo swcutil dl -d <domain>проверяет, что файл загружается, аsudo swcutil verify -d <domain> -j <path-to-JSON> -u <URL>проверяет, что URL соответствует шаблону. - На 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.
Частые вопросы
Чем universal links отличаются от deep links?
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 с действующим сертификатом и без редиректов. Каждому поддомену из списка приложения нужна своя копия.
Почему моя universal link открывает Safari, а не приложение?
Обычные причины: редирект, ответ 403 или 404 на файл, отсутствующая запись для поддомена или нажатие на ссылку внутри того же домена. Apple перечисляет их в TN3155; ввод URL в адресную строку или нажатие на ссылку на тот же домен во время просмотра его в Safari оставляет пользователя в браузере. Сначала проверьте файл через curl -v.
Нужны ли оба файла?
Файл нужен для каждой платформы, приложение для которой вы выпускаете. Сайту с приложениями для iOS и Android нужны оба, и они не зависят друг от друга.