Ссылка, которая в прошлом квартале открывала Telegram или Instagram напрямую, сегодня может выбросить того же посетителя в Safari — и в вашем коде при этом ничего не изменилось. Это не деградация. Вендоры намеренно выводят custom URL scheme из употребления, и не один из них прямо пишет об этом в собственной документации.
Список приложений, в которые можно надёжно перейти по ссылке, сокращается — и сокращается потому, что компании, которым принадлежат эти приложения, решили: scheme — это уязвимость, а не удобство. Понимание того, у кого scheme ещё работает, почему остальные её потеряли и что на самом деле даёт Universal Link взамен, меняет всю логику построения rewrite-цепочки — особенно на iOS, где нет аналога intent://, на который можно опереться, когда scheme не срабатывает.
Scheme, которые вендоры убрали — их же словами
Ни одна из них не является недоделанной реализацией, которую кто-то когда-нибудь доведёт до конца. Каждый вендор в собственной документации или справочном центре объяснил, почему переписывать ссылку больше не на что.
| Приложение | Статус | Причина, которую заявляет вендор |
|---|---|---|
| LINE | line:// выведена из употребления | Чтобы остановить атаки захвата, когда запускается не то приложение |
| Никогда не публиковался | В собственном справочном центре заявляет, что не публикует шаблоны для третьих сторон | |
| YouTube | Нет документированной scheme | Актуальная документация Google говорит, что Universal Links уже открывают приложение на iOS 9+ |
| X | Нет поддерживаемой scheme | Deep link для составления DM существует, но требует ручной отправки и платного уровня Account Activity API, который выводят из употребления |
| Snapchat | Нет scheme | В полном перечне продуктов платформы разработчика нет ни одного API для мессенджинга или чата |
| Нет кликабельной ссылки | Механизм передачи payload — это QR scene_id, а не URL | |
| Нет документированной scheme | — |
Аргументация LINE — самая прямая формулировка во всём этом списке того, почему scheme является поверхностью атаки, а не просто удобством. Регистрация scheme — это обещание, что на неё ответит именно нужное приложение, и в самом механизме ничто не мешает другому приложению зарегистрировать ту же строку первым. Вывод scheme из употребления закрывает эту дыру полностью, вместо того чтобы латать её приложение за приложением.
X — самый чистый пример вендора, который просто никогда не строил такую дверь вообще. Deep link для составления DM существует на бумаге, но требует ручной отправки от посетителя и стоит за платным уровнем Account Activity API, который сам по себе выводится из употребления. Для маршрутизации это означает то же самое, что и отсутствие scheme: всё, что вы построите против него, не переживёт столкновения с требованием уровня аккаунта.
Pinterest, Snapchat, WeChat и Reddit дополняют список тремя разными вариациями одного отказа. Справочный центр Pinterest прямо говорит, что не публикует шаблоны для сторонних разработчиков — реверс-инжинирить недокументированную scheme нет смысла, потому что позиция компании в том, что её и не должно существовать. У платформы разработчика Snapchat в перечне продуктов просто нет поверхности для мессенджинга или чата, поэтому нет и API, под который scheme могла бы подстраиваться. Аналог deep link в WeChat — это QR scene_id, который требует камеру, направленную на экран, а не URL, который может нести браузер, — это совершенно другой механизм, а не scheme под другим именем. Reddit не документирует ничего ни в одну сторону, то есть это скорее категория «неизвестно», чем «подтверждённо отсутствует», но для ссылки, которую вы вот-вот запустите в продакшн, практическое поведение идентично: не стройте rewrite-правило на scheme, которую никто не подтвердил.
Если читать это как тенденцию, а не как список, закономерность держится на всех семи строках: узкое покрытие на iOS здесь по большей части — сознательный шаг индустрии в сторону Universal Links, а не пробел, который кто-то забыл закрыть. Это стоит знать до того, как вы потратите вечер на поиск scheme LINE в декомпилированном APK — компания, которой она принадлежит, уже написала, что не хочет держать эту дверь открытой.
Что ещё работает
Несколько rewrite-правил подтверждены рабочими — см. полную справочную таблицу того, какие scheme ещё работают, — но у каждого своя грамматика. Общего шаблона, применимого ко всем приложениям так, как package=<package> покрывает любое приложение на Android, — нет.
| Публичный URL | Custom scheme | Примечание |
|---|---|---|
https://t.me/<bot>?start=<payload> | tg://resolve?domain=<bot>&start=<payload> | |
https://t.me/<channel> | tg://resolve?domain=<channel> | |
https://instagram.com/<username> | instagram://user?username=<username> | |
https://facebook.com/profile.php?id=<n> | fb://profile/<n> | нужен именно числовой id — Graph API отказывает в поиске по username (ошибка #803) |
https://open.spotify.com/track/<id> | spotify:track:<id> | двоеточия, а не слэши |
https://twitch.tv/<channel> | twitch://stream/<channel> | |
https://twitch.tv/<ch>/v/<id> | twitch://video/v<id> | id VOD требует префикс v |
У Instagram — своя версия проблемы Facebook, в обратном направлении. URL поста или reels несёт shortcode, а scheme требует внутренний числовой media id, и публичного пути из одного в другой нет. У Facebook — зеркальная проблема: fb://profile/ принимает только числовой id, а Graph API отказывается резолвить username в него, так что URL профиля, собранный скрейпингом, а не найденный в Business Manager, — это тупик.
TikTok заслуживает отдельного абзаца, а не строки в таблице, потому что направить TikTok-трафик не на ту scheme id — значит ошибиться тихо, а не громко. Её scheme на iOS — snssdk1233, согласно собственной SDK-документации TikTok. snssdk1128 принадлежит Douyin — другому приложению, из другого магазина, для другого рынка. Rewrite-правило, построенное против неправильного id, либо не открывает ничего, либо открывает Douyin для той небольшой доли посетителей, у кого он случайно установлен, — и ни один из этих сбоев не выглядит как обычная опечатка, когда вы смотрите на него в дебаггере.
Что даёт Universal Link и чего это стоит
Custom scheme детерминирована: любая страница, знающая синтаксис, может её вызвать, и приложение либо отвечает, либо нет — хотя ответить не то же самое, что удержать посетителя внутри. Universal Link устроена иначе. Это https:// URL всё время, поэтому она деградирует безопасно — браузер всегда сможет её открыть, — но откроется ли также приложение, решает от имени вендора операционная система, а не напрямую ваша ссылка. Именно на этот обмен пошли LINE, Pinterest, X и YouTube, когда отказались поддерживать собственную scheme: передать решение «открывать приложение или нет» механизму ассоциации платформы вместо того, чтобы самим удерживать защищённую дверь.
Собственная документация Google прямо говорит, что Universal Links покрывают YouTube со времён iOS 9 — это не недавний обходной путь, а механизм, задуманный как основной практически всё время существования платформы, и YouTube просто никогда не нуждался в собственной scheme с тех пор, как он появился. Но «решение за ОС» действует в обе стороны, как только вы на него полагаетесь. Та же ссылка, открытая изнутри встроенного браузера другого приложения, не обязательно получит такую же обработку, как открытая из Safari или Messages — контекст, в котором произошёл тап, входит в то, что взвешивает система, а не только сама строка URL. Если заметная доля вашего трафика приходит через встроенный браузер, а не нативный, — это как раз трафик, который с наибольшей вероятностью приземлится в браузере вместо приложения, тот самый трафик, над которым Universal Link даёт вам меньше всего контроля.
Одна строка против свода правил для каждого приложения
Android сводит всё это к одному механизму. Синтаксис intent требует ровно одну переменную на приложение:
intent://host/path#Intent;scheme=https;package=<package>;end
Правильно указали package — rewrite-правило готово. Instagram, Spotify, Twitch и Telegram — все резолвятся через идентичную грамматику на Android, просто с другой строкой в том же месте.
iOS не даёт такого сокращения. Нужна и scheme, и rewrite-правило, построенное под собственную структуру URL этого приложения, а форма меняется от приложения к приложению: боту нужен ?start=, каналу — нет; Spotify хочет двоеточия там, где Twitch хочет слэши; VOD Twitch требует префикс v перед id, которого ссылка на живой канал никогда не несёт. Семь рабочих scheme в таблице выше означают семь отдельных rewrite-правил, а не одно правило с семью подстановками.
Эта асимметрия и есть настоящая цена сокращения списка scheme. Дело не только в том, что каждый год всё меньше приложений отвечает на custom scheme, — дело в том, что каждое из тех, кто ещё отвечает, требует что-то немного другое от предыдущего, и общего шаблона для всех приложений на iOS фактически никогда не было так, как на Android. Уровень маршрутизации, который трактует каждое rewrite-правило как собственное редактируемое правило, а не одну общую схему с подставленным package, — это то, что не даёт сокращающемуся списку превратиться в кучу неработающих редиректов каждый раз, когда вендор передумает. Streams от DarkCore держит цепочки package Android и scheme-rewrite iOS как отдельные правила по каждому приложению, поэтому вывод scheme одного приложения из употребления — это изменение конфигурации на вашей стороне, а не редеплой.
Это не единоразовая инвентаризация. Scheme, подтверждённая рабочей сегодня, подтверждена по состоянию на последний раз, когда кто-то реально коснулся её на реальном устройстве, а не как постоянное свойство приложения — собственная история LINE это доказывает, ведь line:// работала годами до того, как появилось уведомление о выводе из употребления. Относитесь к каждой строке в обеих таблицах выше как к тому, что стоит периодически перепроверять на реальном устройстве, а не как к факту, который один раз захардкодили и забыли, и относитесь к «подтверждённо отсутствует» так же, как к «подтверждённо работает»: как к текущей позиции вендора — а это именно то, что вендоры меняют, не спрашивая вашу редирект-цепочку.