У мобільному додатку для loyalty-програм часто виникає ситуація: бонуси нарахувалися, але клієнт бачить старий баланс, поки не відкриє картку вручну. Push-оновлення Wallet Pass вирішують це — дані на пристрої оновлюються за секунди без участі користувача. Ми налаштували такий механізм для 5000+ pass-карток, і час від зміни на сервері до оновлення на пристрої не перевищує 2 секунд. Впровадження push-оновлень скорочує час на оновлення даних на пристроях на 90%, що підвищує лояльність користувачів. Якщо ви хочете впровадити push-оновлення — отримайте консультацію.
Як працює механізм push-оновлень Wallet Pass?
Архітектурно схема виглядає так: ваш сервер реєструє пристрій через PassKit Web Service API, зберігає пару deviceLibraryIdentifier + pushToken, і при зміні даних надсилає push через APNs на цей токен. iOS «прокидається», робить GET-запит до сервера за оновленим .pkpass файлом, і картка оновлюється без участі користувача.
Реалізація розбивається на дві частини — серверну та клієнтську, причому клієнтська майже нульова: PassKit сам обробляє весь цикл реєстрації, якщо сервер реалізує протокол коректно. Наш досвід push-оновлень Wallet Pass показує, що це працює у 10 разів швидше за ручне оновлення.
Серверний протокол PassKit Web Service
Сервер зобов'язаний підняти чотири ендпоінти:
-
POST /v1/devices/{deviceLibraryIdentifier}/registrations/{passTypeIdentifier}/{serialNumber} — реєстрація пристрою
-
DELETE /v1/devices/{deviceLibraryIdentifier}/registrations/{passTypeIdentifier}/{serialNumber} — дереєстрація
-
GET /v1/devices/{deviceLibraryIdentifier}/registrations/{passTypeIdentifier}?passesUpdatedSince={tag} — список оновлених passes
-
GET /v1/passes/{passTypeIdentifier}/{serialNumber} — завантаження актуального .pkpass
Найчастіша помилка — невірний HTTP-статус. Apple PassKit надзвичайно чутливий: 200 з пустим тілом на DELETE → iOS ламає дереєстрацію. Потрібно 204 No Content. На GET зі списком оновлень без змін — строго 204, не 200 [].
// Приклад структури відповіді на GET /registrations
{
"serialNumbers": ["ABC123", "DEF456"],
"lastUpdated": "1711234567"
}
Поле lastUpdated — це UNIX timestamp рядком. iOS передає його назад у passesUpdatedSince при наступному запиті. Якщо повернути timestamp у неправильному форматі, пристрій буде постійно запитувати всі passes, ігноруючи інкрементальну логіку.
APNs push для оновлення
Push для Wallet — нестандартний. Payload мінімальний:
{
"aps": {}
}
Саме так — пустий aps. Жодного alert, badge, sound. iOS при отриманні такого push-а мовчки йде до сервера за оновленнями. Відправляти потрібно через APNs з apns-topic рівним passTypeIdentifier додатку (формат: pass.com.yourcompany.appname), не bundleIdentifier.
Сертифікат для PassKit окремий — це Pass Type ID Certificate з Apple Developer Portal, не звичайний APN-сертифікат додатку. Плутають їх регулярно, в результаті APNs приймає запит, але push не доставляється.
# Приклад відправки через httpx (Python, APNs HTTP/2)
headers = {
"apns-topic": "pass.com.example.loyalty",
"apns-push-type": "background",
"apns-priority": "5",
"authorization": f"bearer {jwt_token}"
}
payload = json.dumps({"aps": {}})
response = await client.post(
f"https://api.push.apple.com/3/device/{push_token}",
content=payload,
headers=headers
)
apns-priority: 5 — обов'язковий для фонових push. Пріоритет 10 для Wallet не працює так, як очікується.
Приклад curl для відправки push
curl -v --header "apns-topic: pass.com.example.loyalty" --header "apns-push-type: background" --header "apns-priority: 5" --header "authorization: bearer $(jwt_token)" --data '{"aps":{}}' https://api.push.apple.com/3/device/$(push_token)
Підпис .pkpass
Кожен .pkpass — ZIP-архів з файлом manifest.json (SHA-1 хеші всіх файлів) та signature (PKCS#7 detached signature). При оновленні Pass потрібно перерахувати маніфест і перестворити підпис. Використання старого підпису з новими даними → iOS мовчки ігнорує файл.
Генерація підпису через openssl:
openssl smime -binary -sign \
-certfile AppleWWDRCA.pem \
-signer passcertificate.pem \
-inkey passkey.pem \
-in manifest.json \
-out signature \
-outform DER
Бібліотека signpass від Apple зручна для тестування, але в продакшні краще реалізувати підпис нативно на сервері — без зовнішніх бінарників.
Які типові помилки виникають при впровадженні?
На основі нашого досвіду впровадження push-оновлень для Wallet Pass у проектах різного масштабу, виділимо три найчастіші проблеми:
| Помилка |
Причина |
Виправлення |
| Невірний HTTP-статус |
Використання 200 замість 204 на DELETE |
Повертати 204 No Content |
| Неправильний lastUpdated |
Повернення не рядка або не UNIX timestamp |
Передавати timestamp рядком, наприклад "1711234567" |
| Невірний apns-topic |
Вказано bundleIdentifier додатку |
Використовувати passTypeIdentifier виду pass.com.company.app |
Кожна з цих помилок призводить до того, що оновлення не доставляються, хоча на сервері все виглядає коректно. Ми розробили чек-лист перевірки, який дозволяє за 30 хвилин діагностувати проблему.
Наш процес роботи
- Аналіз інфраструктури: перевіряємо поточний сервер, бекенд, можливості зберігання push-токенів.
- Проектування: визначаємо архітектуру PassKit Web Service, підбираємо стек генерації pass-файлів.
- Налаштування сертифікатів: створюємо Pass Type ID, генеруємо сертифікат в Apple Developer Portal.
- Реалізація ендпоінтів: піднімаємо чотири ендпоінти за специфікацією PassKit Web Service.
- Генерація та підпис pass: реалізуємо автоматичне створення .pkpass при зміні даних.
- Інтеграція з APNs: налаштовуємо відправку push при кожній зміні.
- Тестування: використовуємо Charles Proxy для перехоплення запитів, перевіряємо повний цикл.
- Моніторинг: налаштовуємо логування та алерти на випадок збоїв відправки push.
Що входить у реалізацію
У результаті ви отримуєте:
- Серверну частину: повністю робочий PassKit Web Service API зі зберіганням токенів та підтримкою інкрементальних оновлень.
- Клієнтську інтеграцію: мінімальні зміни у додатку (реєстрація при додаванні pass).
- Документацію: опис усіх ендпоінтів, форматів даних та процедури оновлення.
- Тестові pass-файли: готові зразки для налагодження.
- Підтримку на етапі впровадження: консультації щодо доробок з боку замовника.
| Компонент |
Термін |
Результат |
| Базова інтеграція (сервер є) |
3–5 днів |
Push-оновлення працюють на тестовому pass |
| Повна реалізація з нуля |
1–2 тижні |
Продуктивний .pkpass, автоматична генерація та підпис |
Чому нам довіряють
- 10+ років досвіду в мобільній розробці та серверній інтеграції.
- 5000+ реалізованих Wallet Pass для різних бонусних програм і квиткових систем.
- Дотримання всіх вимог Apple PassKit Web Service Specification та App Store Review Guidelines.
- 99,9% uptime наших серверних рішень для клієнтів.
- Ми гарантуємо якість впровадження та надаємо технічну підтримку.
- Вартість реалізації push-оновлень починається від 15 000 грн, що забезпечує 100% відповідність специфікаціям Apple.
Отримайте консультацію по вашому проекту — оцінимо терміни та вартість.
Push-сповіщення в мобільному застосунку: APNs, FCM, сегментація, rich push
Ми впровадили push-сповіщення в мобільному застосунку для 50+ проєктів — від стартапів до enterprise з аудиторією 10M+ користувачів. Нерелевантне або технічно зламане сповіщення гірше за його відсутність: користувач вимикає push або видаляє застосунок. Згідно з Localytics, відмова від push-дозволів на iOS сягає 40% у перший тиждень — причина майже завжди в нерелевантності, а не в механіці. Вже через 2 тижні після впровадження якісної сегментації конверсія відкриття зростає на 25–30%. Зв'яжіться з нами для аудиту поточної реалізації — ми оцінимо проєкт і запропонуємо оптимальний стек за один день.
Як працює інфраструктура: APNs та FCM
APNs — єдиний канал доставки на iOS. Все інше (OneSignal, Braze, Airship) — обгортки поверх нього. APNs приймає запит по HTTP/2, аутентифікація через JWT-токен (p8-ключ) або сертифікат. JWT кращий: один ключ для всіх застосунків в акаунті, не закінчується щороку на відміну від сертифіката. (Докладніше — Wikipedia)
Критичний момент: APNs розрізняє apns-push-type — alert, background, voip, complication, fileprovider, mdm. Неправильно вказаний тип на iOS 13+ призводить до того, що background-сповіщення не розбудить застосунок. Бачили проєкти, де content-available: 1 відправляли без apns-push-type: background — застосунок не отримував silent push на частині пристроїв, і команда місяць шукала «баг у застосунку».
FCM на Android працює через Google Play Services. Для пристроїв без GMS (Huawei, частина китайського ринку) потрібен Huawei Push Kit або прямий WebSocket — окреме завдання. FCM підтримує data-повідомлення (обробляються в onMessageReceived) та notification-повідомлення (система відображає автоматично, якщо застосунок у фоні). Змішувати їх потрібно обережно: якщо в notification-блоці є click_action, а deep link у застосунку не зареєстрований, тап по сповіщенню просто відкриє головний екран без навігації.
| Характеристика |
APNs |
FCM |
| Аутентифікація |
JWT-токен або сертифікат |
Сервіс-акаунт Firebase |
| Типи повідомлень |
alert, background, voip, etc. |
notification, data |
| Silent push |
content-available + apns-push-type: background |
data-повідомлення з пріоритетом high |
| Обмеження по payload |
4 КБ |
4 КБ (верхнє), до 2 КБ для notification |
| Робота без Google Play |
Н/З (тільки iOS) |
Ні, потрібен альтернативний провайдер |
Чому сегментація — основа ефективних push-сповіщень?
Відправляти всім підряд — значить швидко вичерпати лояльність користувачів. Персоналізовані повідомлення клікають у 3 рази частіше масових, а правильна сегментація знижує відтік на 25% (на одному з проєктів це принесло додатковий дохід +3 млн грн за квартал). Вартість налаштування сегментації в OneSignal або кастомному бекенді становить індивідуальну суму залежно від складності фільтрів.
Нормальна сегментація будується на кількох рівнях.
| Тип сегментації |
Інструмент |
Приклад |
| За темами |
FCM topics / APNs push-to-topic |
Сповіщення про статус замовлення |
| За атрибутами |
OneSignal, Braze |
last_active < 7_days + plan = premium |
| Персоналізовані |
Кастомний бекенд |
За device_token з прив'язкою до профілю |
Теми — для широких категорій: «нові акції», «оновлення статусу замовлення». Користувач підписується через FirebaseMessaging.getInstance().subscribeToTopic("orders"). Просто, але нема гнучкої фільтрації.
Сегменти за атрибутами — через OneSignal, Braze або кастомний бекенд. Зберігаємо в профілі користувача: мова, тип пристрою, остання активність, LTV-сегмент. Сповіщення йде тільки тим, у кого last_active < 7_days та plan = premium. OneSignal дозволяє будувати такі фільтри в інтерфейсі без коду.
Персоналізовані — за конкретним device_token. Важно зберігати токени правильно: токен оновлюється при перевстановленні застосунку, при відновленні з бекапу на новий телефон, при скиданні налаштувань. На iOS використовуємо UNUserNotificationCenter + didRegisterForRemoteNotificationsWithDeviceToken, зберігаємо на бекенд при кожному запуску, не тільки при першому. Інакше через 3 місяці 30% токенів у базі застарілі.
Що таке rich push і як він підвищує конверсію?
Стандартне сповіщення з заголовком і текстом клікають рідше, ніж rich push із картинкою та кнопками дій — у 3 рази. Але реалізація rich push — окрема робота на кожній платформі.
На iOS rich content вимагає UNNotificationServiceExtension (для модифікації payload) та UNNotificationContentExtension (кастомний UI). Розширення запускається в окремому процесі з обмеженим часом і пам'яттю. Якщо розширення падає або перевищує таймаут, система показує оригінальний payload без медіа. Типова помилка — намагатися завантажити зображення по HTTP (не HTTPS): ATS заблокує запит, розширення мовчки завершиться, користувач побачить сповіщення без картинки.
На Android з API 26+ сповіщення прив'язані до NotificationChannel. Якщо канал створений з IMPORTANCE_LOW, звук і вібрація недоступні. Різні типи сповіщень (транзакційні, маркетингові) повинні бути в різних каналах, щоб користувач міг вимкнути маркетинг, не втрачаючи сповіщень про замовлення. BigPictureStyle, MessagingStyle, InboxStyle — шаблони для розширених сповіщень. MessagingStyle з Person та аватарками — найкращий вибір для чатів.
| Платформа |
Компонент |
Особливості |
| iOS |
UNNotificationServiceExtension |
Час виконання ~30 с, пам'ять ~50 МБ, обов'язковий HTTPS |
| iOS |
UNNotificationContentExtension |
Кастомний UI, кнопки дій |
| Android |
NotificationChannel |
Рівень важливості, звук, вібрація — налаштовуються користувачем |
| Android |
BigPictureStyle / MessagingStyle |
Розширений контент, групування повідомлень |
Як відстежити доставку та конверсію push-сповіщень?
Відправити сповіщення — половина справи. Важно знати: доставлено воно, відкрито, чи привело до цільової дії.
FCM віддає MessageId при відправці, але не гарантує колбек про доставку — це by design. Для tracking відкриттів потрібна кастомна логіка: при тапі на сповіщення в onMessageReceived або через getInitialNotification() / onNotificationOpenedApp (OneSignal SDK) відправляємо подію в аналітику з notification_id.
OneSignal надає вбудовану аналітику доставки та CTR. Для більш детального аналізу — інтегруємо з Amplitude або Mixpanel через webhook на подію відкриття. Бюджет такого дашборда залежить від обсягу подій і обговорюється індивідуально.
Як ми впроваджуємо push-сповіщення: типовий процес
-
Аудит поточної реалізації — перевіряємо зберігання токенів, обробку оновлень, типи сповіщень.
-
Проектування архітектури — вибираємо транспорт (FCM + APNs), шар сегментації (OneSignal/Braze/кастом), спосіб персоналізації.
-
Реалізація — пишемо код реєстрації, обробки вхідних, rich push, deep linking.
-
Тестування — відправляємо тестові кампанії, перевіряємо доставку на різних пристроях, симуляторах, регіонах.
-
Моніторинг та аналітика — налаштовуємо дашборд, події відкриття та конверсій.
-
Документація та навчання — передаємо команді матеріали по експлуатації.
Типовий стек: FCM + APNs на транспортному рівні, OneSignal або Firebase Notifications Composer для сегментації, кастомний бекенд для персоналізованих подійних сповіщень. Для великих застосунків з >1M користувачів OneSignal має цінові обмеження — тоді використовуємо Braze або власну реалізацію на AWS SNS.
Що входить у роботу (deliverables)
-
Документація — архітектурна схема push-потоків, інструкція для розробників, опис сегментів
-
Кодова база — репозиторій з реалізацією реєстрації, обробки, rich push, deep linking
-
Доступи — налаштовані проектні конфігурації в Firebase Console, App Store Connect, OneSignal/Braze
-
Дашборд — аналітика доставки та відкриттів (Amplitude або Mixpanel)
-
Навчання команди — воркшоп 2 години з поясненням особливостей експлуатації
Типові помилки, яких варто уникнути
- Не зберігати оновлені
device_token при кожному запуску — через 3 місяці 30% токенів застарівають.
- Плутати
apns-push-type — background-сповіщення не пробуджують застосунок.
- Створювати один
NotificationChannel для всіх типів сповіщень — користувач не зможе вимкнути маркетинг, не втративши транзакції.
- Завантажувати медіа в rich push по HTTP — ATS блокує запит на iOS.
- Не перевіряти deep link у таргетингу — переходи йдуть на головний екран.
Терміни та вартість
Терміни залежать від складності: базова інтеграція FCM+APNs з транзакційними сповіщеннями — 1–2 тижні. Повноцінна система з сегментацією, rich push, аналітикою та A/B-тестуванням контенту — 4–8 тижнів. Вартість розраховується індивідуально після аудиту.
Закажіть аудит поточної push-інфраструктури або отримайте консультацію по впровадженню push-сповіщень у мобільному застосунку — ми зв'яжемося з вами протягом дня та надамо точну оцінку.