Перейти к содержимому
Все статьи
8 мин чтения

Universal Links против custom URL scheme: почему список продолжает сокращаться

Сокращающийся ряд иконок приложений рядом с единственным путём Universal Link на iOS

Ссылка, которая в прошлом квартале открывала Telegram или Instagram напрямую, сегодня может выбросить того же посетителя в Safari — и в вашем коде при этом ничего не изменилось. Это не деградация. Вендоры намеренно выводят custom URL scheme из употребления, и не один из них прямо пишет об этом в собственной документации.

Список приложений, в которые можно надёжно перейти по ссылке, сокращается — и сокращается потому, что компании, которым принадлежат эти приложения, решили: scheme — это уязвимость, а не удобство. Понимание того, у кого scheme ещё работает, почему остальные её потеряли и что на самом деле даёт Universal Link взамен, меняет всю логику построения rewrite-цепочки — особенно на iOS, где нет аналога intent://, на который можно опереться, когда scheme не срабатывает.

Scheme, которые вендоры убрали — их же словами

Ни одна из них не является недоделанной реализацией, которую кто-то когда-нибудь доведёт до конца. Каждый вендор в собственной документации или справочном центре объяснил, почему переписывать ссылку больше не на что.

ПриложениеСтатусПричина, которую заявляет вендор
LINEline:// выведена из употребленияЧтобы остановить атаки захвата, когда запускается не то приложение
PinterestНикогда не публиковалсяВ собственном справочном центре заявляет, что не публикует шаблоны для третьих сторон
YouTubeНет документированной schemeАктуальная документация Google говорит, что Universal Links уже открывают приложение на iOS 9+
XНет поддерживаемой schemeDeep link для составления DM существует, но требует ручной отправки и платного уровня Account Activity API, который выводят из употребления
SnapchatНет schemeВ полном перечне продуктов платформы разработчика нет ни одного API для мессенджинга или чата
WeChatНет кликабельной ссылкиМеханизм передачи payload — это QR scene_id, а не URL
RedditНет документированной 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, — нет.

Публичный URLCustom 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 для той небольшой доли посетителей, у кого он случайно установлен, — и ни один из этих сбоев не выглядит как обычная опечатка, когда вы смотрите на него в дебаггере.

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:// работала годами до того, как появилось уведомление о выводе из употребления. Относитесь к каждой строке в обеих таблицах выше как к тому, что стоит периодически перепроверять на реальном устройстве, а не как к факту, который один раз захардкодили и забыли, и относитесь к «подтверждённо отсутствует» так же, как к «подтверждённо работает»: как к текущей позиции вендора — а это именно то, что вендоры меняют, не спрашивая вашу редирект-цепочку.

  • universal links vs url scheme
  • ios deep link
  • line deprecated scheme
  • app links vs deep links