Вы привязываете Android-правило открытия приложения к com.instagram.android, публикуете его — и Instagram открывается у всех, у кого приложение установлено. Делаете то же самое для Telegram, привязываете к org.telegram.messenger — и часть Telegram-трафика всё равно попадает на browser fallback: посетители, которые клянутся, что приложение у них есть. Потому что оно действительно есть. Правило не сломано. Package-строка неполная.
Android package name — это не то же самое, что «приложение». Это идентификатор сборки, и несколько популярных приложений выпускают больше одной сборки, каждую под своим package id. Если ваш роутинг, таргетинг рекламной платформы по устройству или собственный QA-чеклист исходят из того, что одно приложение равно одному package, у вас есть слепая зона размером ровно в столько посетителей, сколько установило другую сборку.
Где ломается это допущение
| Приложение | Packages |
|---|---|
| Telegram | org.telegram.messenger (Play), org.telegram.messenger.web (APK на telegram.org), org.thunderdog.challegram (Telegram X) |
com.whatsapp, com.whatsapp.w4b (Business) | |
| TikTok | com.zhiliaoapp.musically, com.ss.android.ugc.trill |
com.instagram.android | |
| Shopee | по одному package на страну: com.shopee. + id, br, vn, th, ph, tw, my, sg, mx, cl, ar |
| Amazon | com.amazon.mShop.android.shopping глобально, кроме Индии: in.amazon.mShop.android.shopping |
Instagram — исключение в этой таблице: одно приложение, один package, без исключений. Всё остальное в ней — напоминание, что «package name» — вопрос с более чем одним правильным ответом, и ответ зависит от того, откуда посетитель фактически получил приложение.
Ничто из этого не проявляется как ошибка нигде в вашем стеке. Посетитель с «неправильным» package не вызывает сбой запроса или запись в логах — он просто не совпадает с правилом, написанным под другую сборку того же приложения, и проваливается к тому, что делает ваш дефолт дальше. Если дефолт — это browser fallback или store-страница, посетитель видит ровно то же самое, что видел бы тот, у кого приложения нет вообще, и ничто в ваших логах не различает эти два случая между собой.
Telegram: три пакета, один продукт
Telegram — тот случай, которого никто не ожидает, потому что Telegram — приложение, которое каждый баер считает уже хорошо знакомым. Три отдельных package id соответствуют трём отдельным установкам того, что со стороны посетителя является одним и тем же продуктом:
org.telegram.messenger— сборка из Play Store, та, под которую по умолчанию написано большинство правил таргетинга.org.telegram.messenger.web— APK, который Telegram раздаёт со своего собственного сайта, telegram.org. Это не догадка и не название, придуманное каким-то community-зеркалом: package id считан непосредственно из манифеста этого APK —package=org.telegram.messenger.web, versionName 12.10.0. Сам Telegram выпускает эту сборку под другим идентификатором, чем свою Play-сборку.org.thunderdog.challegram— Telegram X, отдельный клиент целиком, со своим собственным package.
Правило, которое таргетирует только org.telegram.messenger, правильно для каждого посетителя, использовавшего Play Store. Оно тихо неправильно для всех, кто скачал приложение прямо с telegram.org — реальный, далеко не маргинальный канал привлечения в регионах, где доступ к Play нестабилен или где посетители по умолчанию идут на сайт вендора. У этих посетителей Telegram уже открыт на телефоне прямо перед ними, а ваш роутинг отправляет их на fallback, который предлагает установить то, что у них уже есть.
Заранее, до клика, нет способа узнать, какую именно из трёх сборок запускает конкретный посетитель. Ни источник перехода, ни устройство, ни сам клик не несут этой информации — единственный способ для уровня роутинга узнать это — спросить напрямую у Android, по одному package за раз. Именно это оправдывает рассмотрение задачи как задачи со списком, а не задачи с одним полем: вы не выбираете, какой package Telegram «правильный», вы покрываете все три, каждый из которых правильный для кого-то.
WhatsApp: consumer и Business — разные пакеты
com.whatsapp — это потребительское приложение. com.whatsapp.w4b — это WhatsApp Business: отдельная установка, отдельный package, распространённый среди мерчантов и небольших операторов, к которым построен целый ряд партнёрских воронок. Если ваша аудитория тяготеет к бизнес-аккаунтам, а правило проверяет только com.whatsapp, вы тестируете не ту половину собственного трафика.
Эти два приложения не сливаются в одно на устройстве, где установлены оба — многие владельцы малого бизнеса держат потребительский WhatsApp для личных контактов и Business для своего магазина одновременно, на одном телефоне. Правило, останавливающееся на первом совпадении, всё равно должно решить, какое из двух проверять первым, и это решение должно следовать за вашей аудиторией, а не за дефолтом, написанным до того, как кто-то задумался, в каком именно WhatsApp мерчант открывает ссылки.
TikTok: два пакета, невидимая разница для посетителя
com.zhiliaoapp.musically и com.ss.android.ugc.trill — оба это TikTok, то же приложение на другом конце каждого клика по рекламе TikTok, который вы уже трекаете. Ничто в интерфейсе приложения не подсказывает посетителю, какую сборку он запускает, и ничто не заставляет его выбирать — какая сборка окажется на устройстве, зависит от того, как и откуда её установили. Правило, проверяющее одно и не проверяющее другое, пропустит одних посетителей и тихо потеряет других, которые, насколько им известно, пользуются тем же самым приложением.
Shopee: одиннадцать пакетов, ни одного общего
У Shopee вообще нет единого Android package. Есть по одному на страну — com.shopee.id, com.shopee.br, com.shopee.vn, com.shopee.th, com.shopee.ph, com.shopee.tw, com.shopee.my, com.shopee.sg, com.shopee.mx, com.shopee.cl, com.shopee.ar. Нет ни одного com.shopee, который охватывал бы их все. Если вы ведёте трафик более чем на один из одиннадцати рынков Shopee, «package Shopee» — это не вопрос с одним ответом, а поиск, ключом к которому служит то, какое именно приложение конкретной страны установлено у посетителя.
Amazon: один package везде, с одним исключением
Amazon — близко к простому случаю: com.amazon.mShop.android.shopping — это package почти везде, где работает Amazon. Индия — единственное исключение, со своим in.amazon.mShop.android.shopping. Везде остальное — включая Японию, где на APK-зеркалах встречается package jp.amazon.mShop.android — реально живой в Play именно глобальный package. Этот «японский на вид» package id — не реальный листинг в Play; добавить его как кандидата означает добавить строку, которая никогда не приведёт к установке.
Это стоит сказать прямо, потому что здесь направление противоположно остальной таблице: большая часть фрагментации тут — это реальные приложения, которые стоит таргетировать, а сейчас вы этого не делаете. Кейс Amazon — напоминание, что не каждая строка, похожая на package, им является: правдоподобный id на зеркале ничего не стоит добавить в список кандидатов и ничего не возвращает, когда вы это делаете, — но стоит проверить, что package реально резолвится в Play, прежде чем он попадёт в правило, а не доверять тому, что выглядит правильно.
Цель — это список, а не строка
Собственный механизм перехода Android принимает только один package за попытку — короткий путь, которого нет в iOS:
intent://host/path#Intent;scheme=https;package=<package>;end
Чтобы покрыть приложение, выпускающееся под несколькими package, вы не можете вписать два id в одно поле package= — вы пробуете кандидатов последовательно, один intent на package, пока один из них не резолвится в установленное приложение. К этому привязано одно жёсткое правило: ни один кандидат в этой последовательности не может нести S.browser_fallback_url, включая последний. Fallback на первой попытке позволяет посетителю, у которого просто установлен второй package, попасть в браузер ещё до того, как вторую попытку вообще попробовали, — а с вашей стороны это выглядит ровно как «приложения нет», хотя на самом деле это «сначала попробовали не тот package». Fallback принадлежит после того, как исчерпаны все кандидаты, и применяется вашей собственной страницей, а не привязан к какому-то одному шагу.
Это означает, что реальный объект, который вы поддерживаете на каждое приложение, — не package name. Это упорядоченный список package-кандидатов, и порядок — это решение: тот кандидат, которого вы ставите первым, побеждает, когда у посетителя случайно установлена более чем одна сборка, и именно он — единственный, кого вообще попробуют для посетителя, чья навигация в Chrome не сопровождалась user gesture — Chrome не запускает intent:// без него и тихо проваливается к fallback вместо этого. Ставьте первой сборку с наивысшей вероятностью для вашего фактического трафика — для большинства воронок это Play-package, — но «большинство воронок» — ровно то допущение, которое ломает website-APK Telegram, и которое полностью ломает одиннадцатикратный раскол Shopee, потому что там нет ни одной единственной наиболее вероятной страны, которую можно поставить дефолтом для всех рынков.
Для Telegram этот список кандидатов — три попытки по очереди, каждая без fallback:
intent://resolve?domain=<x>#Intent;scheme=https;package=org.telegram.messenger;end
intent://resolve?domain=<x>#Intent;scheme=https;package=org.telegram.messenger.web;end
intent://resolve?domain=<x>#Intent;scheme=https;package=org.thunderdog.challegram;end
Только после того, как испробованы все три и ни один не резолвился, ваша собственная страница решает, что увидит посетитель без какого-либо Telegram. Пропустите вторую строку, потому что «это не настоящий package», — и вы тихо воспроизведёте ту же слепую зону, с которой началась эта статья.
Store fallback наследует ту же проблему
Общий Android store fallback — это шаблон:
https://play.google.com/store/apps/details?id=<package>
Заполните его не тем кандидатом — и вы только что предложили посетителю, у которого приложение уже есть, «установить» его снова — или, ещё хуже, для Shopee, отправили его на листинг одной конкретной страны, тогда как ваш трафик охватывает одиннадцать. Нет ни одной store-страницы com.shopee, на которую можно упасть обратно; заполнение шаблона любым одним package Shopee отправляет десять из одиннадцати рынков на листинг не той страны. Для приложения со split package без общей идентичности store fallback — не страховка, а второе место, где та же проблема «не того кандидата» может возникнуть снова. Веб-страница, которую вы уже контролируете, правильна везде, где store-ссылка не может быть правильной.
Что это меняет в том, как вы пишете правило
Относитесь к каждому приложению в вашем конфиге роутинга как к списку кандидатов, а не одному полю, и относитесь к порядку этого списка как к реальной настройке, которую вы подстраиваете под каждый источник трафика, а не как к дефолту, к которому вы никогда не возвращаетесь. Для Telegram конкретно это означает решение, принадлежит ли org.telegram.messenger.web списку вообще — и для большинства воронок с заметным объёмом трафика принадлежит, потому что его отсутствие не проваливается громко. Оно просто тихо перестаёт считать людей, которые уже сделали то, чего вы от них хотели.
Аудит, который стоит провести перед тем, как доверять любому числу открытий Android-приложения: для каждого приложения в вашем листе правил перечислите каждый package id, под которым оно, как известно, выпускается, сверьте каждый со своим текущим правилом, и относитесь к каждому приложению только с одним кандидатом как к правилу, которое вы ещё не дописали, — а не как к правилу, которое проще, потому что приложение якобы простое.
Трекер, который моделирует это корректно, хранит список package на приложение, в заданном порядке, а не одно поле id, — именно такую форму для Android-роутинга использует DarkCore PWA Tracker, потому что «одно приложение, один package» перестало быть безопасным допущением в тот момент, когда Telegram выпустил второй.