Перейти до вмісту
Усі статті
9 хв читання

Фрагментація Android package name: один застосунок — це не один пакет

Іконка одного застосунку розділяється на кілька підписаних Android package identifiers

Ви прив’язуєте Android-правило відкриття застосунку до com.instagram.android, публікуєте його — і Instagram відкривається у всіх, хто має застосунок. Робите те саме для Telegram, прив’язуєте до org.telegram.messenger — і частина Telegram-трафіку все одно потрапляє на browser fallback: відвідувачі, які клянуться, що застосунок у них є. Бо він справді є. Правило не зламане. Package-рядок неповний.

Android package name — це не те саме, що «застосунок». Це ідентифікатор збірки, і кілька популярних застосунків випускають більш ніж одну збірку, кожну під своїм package id. Якщо ваш роутинг, таргетинг рекламної платформи за пристроєм чи власний QA-чекліст виходять з того, що один застосунок дорівнює одному package, у вас є сліпа зона розміром рівно у стільки відвідувачів, скільки встановило іншу збірку.

Де ламається це припущення

ЗастосунокPackages
Telegramorg.telegram.messenger (Play), org.telegram.messenger.web (APK на telegram.org), org.thunderdog.challegram (Telegram X)
WhatsAppcom.whatsapp, com.whatsapp.w4b (Business)
TikTokcom.zhiliaoapp.musically, com.ss.android.ugc.trill
Instagramcom.instagram.android
Shopeeпо одному package на країну: com.shopee. + id, br, vn, th, ph, tw, my, sg, mx, cl, ar
Amazoncom.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 випустив другий.

  • android package name
  • org.telegram.messenger
  • whatsapp business package name
  • tiktok package name
  • app package id