Firebase: push, Remote Config и Crashlytics
Достучаться до пользователей уведомлениями, менять поведение приложения без релиза и знать, когда оно падает.
За 30 секунд
Push-уведомления идут от вашего сервера в push-сервис Google или Apple, который доставляет их на конкретный токен устройства. Firebase Cloud Messaging (FCM) даёт один API для обеих платформ. Кроме того, в Firebase есть Remote Config — чтобы включать функции или принудительное обновление без выпуска новой сборки, — а также Crashlytics и Analytics, чтобы видеть падения и использование в продакшене.
Почему я это использую
- Я использую Firebase, потому что один сервис закрывает эксплуатационные потребности почти каждого приложения, которое я выпускаю: push, удалённые переключатели, отчёты о падениях и аналитику.
- Push — ключевая бизнес-функция в приложениях для заказов и лояльности: статус заказа, награды, кампании, — поэтому доставку, момент запроса разрешения и обработку нажатий я считаю продуктовой работой, а не чем-то второстепенным.
- Remote Config даёт мне предохранительный клапан: принудительное обновление или экран техработ можно включить за минуты, когда этого требует изменение на бэкенде или баг.
- Crashlytics сообщает мне о проблемах раньше, чем пользователи напишут отзывы, со стек-трейсами, привязанными к конкретной сборке.
Как это работает
01Как на самом деле работают push-уведомления
Ваш сервер никогда не общается с телефоном напрямую. На iOS операционная система держит одно соединение с APNs (Apple Push Notification service); на Android Google Play services держит одно соединение с FCM. При запуске приложение запрашивает у ОС токен устройства — адрес этого приложения на этом устройстве — и отправляет его на ваш бэкенд с привязкой к пользователю. Чтобы уведомить пользователя, бэкенд вызывает FCM HTTP v1 API с этим токеном; FCM доставляет сообщение напрямую на Android и передаёт его в APNs для iOS (APNs auth key один раз загружается в Firebase). Токены меняются: после переустановки, восстановления или периодически, поэтому подписывайтесь на обновление токена и обновляйте его на бэкенде. Когда FCM сообщает, что токен unregistered, удаляйте его. У одного пользователя может быть несколько устройств, поэтому храните несколько токенов на пользователя.
- Токен устройства: адрес одной установки приложения, а не человека
- APNs auth key (.p8), загруженный в Firebase для доставки на iOS
- FCM HTTP v1 API с сервисным аккаунтом; legacy API больше нет
- Topics: одно сообщение многим подписчикам (например, 'promo-hy')
02Разрешения и получение токена
На iOS для показа уведомлений всегда нужно разрешение пользователя, а на Android начиная с Android 13 (API 33) нужно runtime-разрешение POST_NOTIFICATIONS. Если пользователь нажал «Не разрешать», спросить ещё раз обычно нельзя — ему придётся идти в Настройки. Поэтому спрашивайте в момент, когда польза очевидна: после первого заказа («Сообщить, когда ваш кофе будет готов?»), а не на первом экране. Перед системным диалогом покажите короткое пояснение внутри приложения. iOS также поддерживает provisional authorization, при которой уведомления тихо попадают в центр уведомлений без запроса. С React Native Firebase поток такой: запросить разрешение, получить токен, отправить его в ваш API вместе с платформой и версией приложения и подписаться на обновление токена.
import { getMessaging, requestPermission, getToken, onTokenRefresh,
AuthorizationStatus } from "@react-native-firebase/messaging";
import { PermissionsAndroid, Platform } from "react-native";
export async function registerForPush(api: Api) {
const messaging = getMessaging();
if (Platform.OS === "android" && Platform.Version >= 33) {
await PermissionsAndroid.request("android.permission.POST_NOTIFICATIONS");
}
const status = await requestPermission(messaging);
if (status === AuthorizationStatus.DENIED) return;
const token = await getToken(messaging);
await api.post("/devices", { token, platform: Platform.OS });
onTokenRefresh(messaging, (t) => api.post("/devices", { token: t, platform: Platform.OS }));
}
03Notification и data сообщения, foreground и нажатия
Сообщение FCM может содержать блок notification (title, body), блок data (ваши собственные строки ключ-значение) или оба. Notification-сообщения ОС показывает автоматически, когда приложение в фоне или закрыто. Data-only сообщения доставляются вашему коду, который решает, что делать; на iOS это фоновые push, которые система может ограничивать или задерживать, поэтому никогда не полагайтесь на них для видимых пользователю оповещений. Когда приложение на переднем плане (foreground), ОС по умолчанию не показывает баннер: вы получаете сообщение в onMessage и решаете сами — показать toast внутри приложения, обновить бейдж или вывести локальное уведомление через Notifee. Обрабатывайте нажатия в трёх состояниях: foreground, фон (onNotificationOpenedApp) и холодный старт (getInitialNotification). Кладите маршрут deep link в data и навигируйте по нему.
{
"message": {
"token": "DEVICE_TOKEN",
"notification": { "title": "Order ready", "body": "Your latte is waiting at the counter" },
"data": { "type": "order_status", "orderId": "1042", "link": "app://orders/1042" },
"android": { "priority": "high", "notification": { "channel_id": "orders" } },
"apns": { "payload": { "aps": { "sound": "default" } } }
}
}
04Надёжная отправка с бэкенда
Отправляйте push из воркера очереди, а не внутри HTTP-запроса: изменение статуса заказа записывает задачу, а воркер вызывает FCM с повторами и backoff. Используйте Firebase Admin SDK или эндпоинт HTTP v1 с учётными данными сервисного аккаунта, которые хранятся как секрет на сервере, — никогда не в приложении. Сохраняйте каждую кампанию или сообщение и в собственной базе данных, чтобы приложение могло показывать внутренний inbox; доставка push не гарантирована, а пользователи их смахивают. Учитывайте тихие часы и настройки пользователя (обновления заказов включены, маркетинг выключен), а на Android создавайте отдельные каналы уведомлений, чтобы пользователи могли заглушить акции, не теряя обновлений заказов. Удаляйте токены, которые FCM возвращает как unregistered. Для массовых кампаний используйте topics или пакетную отправку и планируйте их через собственную систему задач.
05Remote Config: принудительное обновление, техработы, feature flags
Remote Config — это набор параметров ключ-значение в Firebase, которые приложение получает во время работы. Вы поставляете значения по умолчанию внутри приложения, при запуске делаете fetch и activate с разумным минимальным интервалом запроса и читаете значения как boolean, числа или строки. Условия позволяют таргетировать по платформе, версии приложения, стране или проценту пользователей. Три сценария окупаются сами. Принудительное обновление: храните min_supported_version для каждой платформы; если установленная версия ниже, показывайте блокирующий экран со ссылкой на стор — это необходимо, когда старое приложение сломается на новом API. Режим техработ: флаг, который показывает дружелюбный экран во время миграций. Feature flags и постепенный rollout: включите новый checkout для 10% пользователей, посмотрите на Crashlytics, затем доведите до 100%. Логика должна оставаться безопасной, если fetch не удался: приложение обязано работать на значениях по умолчанию.
import { getRemoteConfig, setDefaults, setConfigSettings,
fetchAndActivate, getValue } from "@react-native-firebase/remote-config";
import { Platform } from "react-native";
import DeviceInfo from "react-native-device-info";
export async function checkAppGate() {
const rc = getRemoteConfig();
await setDefaults(rc, { min_version_ios: "1.0.0", min_version_android: "1.0.0", maintenance: false });
await setConfigSettings(rc, { minimumFetchIntervalMillis: 15 * 60 * 1000 });
await fetchAndActivate(rc).catch(() => undefined); // offline: use cached/defaults
const key = Platform.OS === "ios" ? "min_version_ios" : "min_version_android";
if (getValue(rc, "maintenance").asBoolean()) return "maintenance";
if (isLower(DeviceInfo.getVersion(), getValue(rc, key).asString())) return "force_update";
return "ok";
}
06Crashlytics и Analytics
Crashlytics собирает нативные падения, а с React Native Firebase — и JavaScript-ошибки, которые вы записываете, группируя их по проблемам и привязывая к версии приложения и устройству. Следите, чтобы файлы символов (dSYM на iOS, mapping-файлы на Android) загружались во время сборки, иначе стек-трейсы останутся нечитаемыми. Добавляйте контекст: задайте неперсональный ID пользователя, пишите breadcrumbs перед рискованными шагами (начало оплаты, возврат с оплаты) и записывайте обработанные ошибки от важных сбоев API. Следите за долей пользователей без падений (crash-free users) по каждому релизу; во время поэтапного rollout это ваш сигнал поставить его на паузу. Analytics записывает события вроде screen_view, add_to_cart, begin_checkout и purchase. До написания кода определите небольшой план событий с единообразными именами, не отправляйте персональные данные и учитывайте согласие: отключайте сбор данных, пока пользователь не согласится, там, где этого требует закон.
Когда применять
- Любое приложение, которому нужны транзакционные уведомления: статус заказа, бронирования, напоминания, оповещения безопасности.
- Вам нужны удалённые переключатели — принудительное обновление, режим техработ, постепенный rollout функций — без релиза в стор.
- Вы хотите отчёты о падениях и продуктовую аналитику с минимальной настройкой на обеих платформах.
Когда не стоит
- Пользователи в основном на устройствах без Google Play services (на некоторых рынках) — нужен альтернативный push-провайдер для Android.
- Строгие требования к локализации данных или приватности запрещают отправлять данные об устройствах или использовании в Google — рассмотрите self-hosted аналитику и подходящего провайдера.
- Real-time обновления внутри открытого приложения — используйте WebSockets или SSE; push — не канал живых данных.
Альтернативы
- Expo Notifications
Единый push API и сервис для Expo-приложений; под капотом использует FCM и APNs.
- OneSignal / Braze
Хостинговые engagement-платформы с сегментацией, кампаниями и аналитикой поверх push.
- Напрямую APNs + FCM
Вызывать Apple и Google напрямую с бэкенда — полный контроль и никакого дополнительного вендора.
- Sentry
Альтернатива Crashlytics для мониторинга ошибок и производительности, с сильной поддержкой JS и source maps.
Лучшие практики
- Запрашивайте разрешение на уведомления в осмысленный момент, предварительно коротко объяснив зачем.
- Храните несколько токенов на пользователя, обновляйте их и удаляйте токены, которые FCM помечает как unregistered.
- Отправляйте из очереди с повторами; держите внутренний inbox, потому что доставка push не гарантирована.
- Используйте каналы уведомлений Android и настройки пользователя, чтобы разделять транзакционные и маркетинговые сообщения.
- Поставляйте значения Remote Config по умолчанию, чтобы приложение работало офлайн; используйте переключатели принудительного обновления и техработ с первого дня.
- Загружайте dSYM и mapping-файлы при каждой сборке и следите за crash-free users по каждому релизу.
- Держите ключи сервисного аккаунта только на сервере и никогда не кладите персональные данные в события аналитики.
Частые ошибки
- Запрашивать разрешение на push на самом первом экране и навсегда терять согласие большинства пользователей.
- Полагаться на data-only сообщения на iOS для важных оповещений, которые система может задержать или отбросить.
- Игнорировать foreground-сообщения, из-за чего пользователи с открытым приложением никогда не видят уведомление.
- Не обрабатывать нажатие при холодном старте, из-за чего нажатие на уведомление открывает главный экран вместо заказа.
- Выпустить приложение без переключателя принудительного обновления и потом не иметь возможности остановить старые сборки, вызывающие изменённый API.
Глубже
07Как устроена доставка: priority, TTL, collapsing и Doze
Доставку определяет управление питанием. Режим Doze в Android группирует сетевые обращения неактивных телефонов: FCM-сообщения с normal priority ждут окна обслуживания, а сообщения с high priority могут разбудить устройство. Google может понизить приоритет приложениям, чьи high-priority сообщения не приводят к видимому уведомлению, поэтому используйте high priority только для уведомлений, которые пользователь увидит. На iOS apns-priority 10 означает «доставить сейчас», а 5 — «доставить, когда удобно»; фоновые push (content-available) должны использовать priority 5 и ограничиваются системой. У каждого сообщения есть время жизни: android.ttl и заголовок apns-expiration определяют, как долго сервис пытается достучаться до офлайн-устройства. Collapse key (Android) или apns-collapse-id (iOS) заменяет более старые недоставленные сообщения самым новым, поэтому телефон, вернувшийся в сеть, покажет одно сообщение «корзина обновлена», а не десять. Держите payload маленьким: FCM отклоняет сообщения больше примерно 4 KB.
{
"message": {
"token": "DEVICE_TOKEN",
"data": { "type": "cart_sync", "cartId": "c_981" },
"android": { "priority": "normal", "ttl": "3600s", "collapse_key": "cart" },
"apns": {
"headers": {
"apns-priority": "5",
"apns-push-type": "background",
"apns-collapse-id": "cart"
},
"payload": { "aps": { "content-available": 1 } }
}
}
}
08Отправка в масштабе: батчи, ошибки и квоты
Firebase Admin SDK отправляет список до 500 токенов за один вызов через sendEachForMulticast и возвращает по одному результату на токен в том же порядке. Классифицируйте каждую ошибку. registration-token-not-registered означает, что приложение удалено или токен сменился: удалите его. invalid-argument означает, что ваш payload неверен: исправьте код, не повторяйте отправку. Quota-exceeded (HTTP 429) и ошибки unavailable или internal (503, 500) временные: повторяйте с экспоненциальным backoff и учитывайте заголовок Retry-After. Квоты на уровне проекта существуют, поэтому крупные кампании должны идти через очередь, которая дозирует отправку, а не через цикл, который отправляет всё сразу. Дозирование защищает и ваш бэкенд: если 200,000 человек получат акцию в одну и ту же секунду, многие откроют приложение в одну и ту же минуту.
import { getMessaging } from "firebase-admin/messaging";
export async function sendToUser(tokens: string[], title: string, body: string, link: string) {
const res = await getMessaging().sendEachForMulticast({
tokens, // up to 500 per call
notification: { title, body },
data: { link },
});
const dead = res.responses
.map((r, i) => (r.error?.code === "messaging/registration-token-not-registered" ? tokens[i] : null))
.filter((t): t is string => t !== null);
await removeTokens(dead); // keep the token table clean
return { sent: res.successCount, failed: res.failureCount };
}
09Приватность и безопасность уведомлений
Уведомление показывается на экране блокировки, дублируется на часы и иногда зачитывается вслух, поэтому считайте его текст публичным. Никогда не кладите в заголовок или текст одноразовые коды, балансы, сведения о здоровье или полные адреса; пишите «По вашему заказу есть обновление» и показывайте подробности внутри приложения после аутентификации. На iOS Notification Service Extension может расшифровать зашифрованный payload или загрузить rich media перед показом (mutable-content), что позволяет передавать через серверы Apple и Google меньше чувствительных данных. Учётные данные service account, которыми отправляются push, дают много прав: выдавайте ему только нужные роли Firebase Cloud Messaging, храните его в secret store и регулярно ротируйте. Токены устройств — не секреты, но это персональные данные, связанные с пользователем: отвязывайте их при выходе из аккаунта и удаляйте при удалении аккаунта.
10Устройство Remote Config и подводные камни
Remote Config — это конфигурация на стороне клиента, а не граница безопасности: значения скачиваются на устройство, и там их можно прочитать или изменить, поэтому никогда не храните в нём секреты и не используйте его для выдачи прав — доступ должен проверять сервер. SDK кэширует значения и ограничивает частоту fetch; минимальный интервал fetch по умолчанию — 12 часов, поэтому уменьшайте его осознанно и не делайте fetch на каждом экране. Решите, как значения активируются: fetchAndActivate при запуске — это просто, но может изменить UI уже после его появления; fetch в фоне и активация при следующем запуске позволяют избежать мерцания. Real-time Remote Config может отправлять изменения в запущенные приложения, когда нужны быстрые kill-switch. Процентные условия стабильны для каждой установки приложения, поэтому один и тот же пользователь остаётся в одной группе. Каждая публикация создаёт версию шаблона, на которую можно откатиться, — это полезно, когда неудачное значение что-то ломает.
Реальные ситуации
iOS push перестали приходить после выхода в production
Проблема
Android получает уведомления, и на iOS всё работало в development-сборках, но пользователи TestFlight и App Store ничего не получают. Логи бэкенда показывают, что FCM принимает запросы.
Как решить
Пройдите цепочку iOS шаг за шагом. Убедитесь, что ключ аутентификации APNs (.p8) загружен в настройки проекта Firebase с правильными Key ID и Team ID и что bundle ID iOS-приложения в Firebase точно совпадает с выпущенным приложением. Проверьте, что capability Push Notifications включена, чтобы production entitlement попал в подписанную сборку. Убедитесь, что приложение запрашивает разрешение и регистрируется для remote notifications до чтения FCM-токена и что сохранённый на бэкенде токен получен из production-сборки, а не из старой debug-установки. Наконец, отправьте тестовое сообщение из консоли Firebase на один свежий токен, чтобы отделить проблемы бэкенда от проблем конфигурации.
Push-кампания положила бэкенд
Проблема
Маркетинг отправил push со скидкой всем пользователям в 18:00. За две минуты десятки тысяч человек открыли приложение, время ответа API взлетело, и многие пользователи вместо предложения увидели ошибки.
Как решить
Дозируйте отправку. Кампании ставятся в очередь, которая отправляет батчами — например, по несколько тысяч устройств в минуту — или по часовым поясам, а не одним залпом. Сделайте целевой экран дешёвым: контент предложения кэшируется в Redis или CDN, а приложение показывает закэшированный контент, пока загружаются свежие данные. Проводите нагрузочное тестирование пути кампании перед крупными рассылками. Координируйтесь с бэкендом: autoscaling или дополнительная мощность, прогретая до запланированной кампании, и rate limit, которые деградируют мягко. Наконец, храните каждую кампанию в базе данных со статусом, чтобы приостановленная или частично отправленная кампания могла продолжиться без дублей.
Пользователи получают одно и то же уведомление дважды
Проблема
Некоторые пользователи получают два одинаковых уведомления «заказ готов». Это касается тех, кто переустанавливал приложение или пользуется двумя устройствами, и иногда случается после деплоев бэкенда.
Как решить
Определите, какой это тип дубля. Переустановка создаёт новый токен, а старый может какое-то время оставаться действительным, поэтому храните токены по ID установки и заменяйте старую запись, когда устройство регистрируется снова. Второй тип вызывают деплои и повторы: job в очереди, который упал по таймауту уже после того, как FCM принял сообщение, повторяется и отправляет снова. Дайте каждому уведомлению стабильный ID, записывайте его как отправленное до подтверждения job и пропускайте, если он уже существует. Используйте collapse key или apns-collapse-id, равный этому ID, — тогда даже если на устройство придут две копии, более новая заменит старую, а не встанет рядом.
Шпаргалка
- Endpoint отправки FCM HTTP v1
POST https://fcm.googleapis.com/v1/projects/PROJECT_ID/messages:send- OAuth scope для отправки
https://www.googleapis.com/auth/firebase.messaging- Разрешение в manifest для Android 13+
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />- Батч-отправка на устройства одного пользователя
getMessaging().sendEachForMulticast({ tokens, notification, data }) // max 500- Подписать устройства на topic
getMessaging().subscribeToTopic(tokens, "promo-hy")- Ошибка, после которой токен нужно удалить
messaging/registration-token-not-registered- Заменять старые недоставленные сообщения
android.collapse_key / apns-collapse-id header- Ограничить, как долго FCM повторяет доставку
"android": { "ttl": "3600s" } / apns-expiration header- Показать баннер iOS в foreground (нативно)
completionHandler([.banner, .list, .sound])- Интервал fetch Remote Config в dev
setConfigSettings(rc, { minimumFetchIntervalMillis: 0 }) // never in production
В моих реальных проектах
- Мои приложения для ресторанов, зоомагазина, спортзала и кофейни используют Firebase Messaging, Analytics, Crashlytics и Remote Config, большинство из них — с Notifee для уведомлений в foreground.
- Remote Config управляет принудительным обновлением и режимом техработ в моих приложениях; бэкенды отправляют push-кампании через FCM и ведут внутренний inbox уведомлений.
- CRM для спортзалов отправляет запланированные push-кампании, а админ-панели ресторанов и спортзалов используют web push для оповещений сотрудников.
- Для LiveOps-консоли игры я сделал редактор Remote Config с историей и диффами, а также FCM push игрокам; POS SaaS отправляет push через FCM и APNs, включая iOS Live Activities.
Вопросы и ответы
Q1В чём разница между notification и data сообщениями в FCM?
У notification-сообщения есть title и body, которые операционная система показывает автоматически, когда приложение в фоне или закрыто; ваш код для отображения не нужен. Data-сообщение несёт только ваш payload ключ-значение и доставляется приложению, которое решает, что делать. На Android data-сообщения с высоким приоритетом надёжны; на iOS они становятся тихими фоновыми push, которые система может ограничивать. На практике я отправляю оба блока: notification — для видимого оповещения, а data — с типом, ID и маршрутом deep link для обработки нажатия.
Q2Почему пользователи не видят моё уведомление, когда приложение открыто?
Потому что на переднем плане операционная система передаёт сообщение приложению, а не показывает баннер, — предполагается, что приложение покажет его в контексте. С React Native Firebase вы получаете его в слушателе onMessage. Дальше решаете вы: обновить экран заказа, если он открыт, показать toast внутри приложения или вывести локальное уведомление через Notifee в нужном канале Android. На iOS также можно настроить presentation options, чтобы показывать баннеры в foreground. Явная обработка этого — часть проектирования push, а не исправление бага.
Q3Как реализовать принудительное обновление в мобильном приложении?
Я храню минимальную поддерживаемую версию для каждой платформы в Remote Config с безопасным значением по умолчанию внутри приложения. При запуске приложение получает и активирует конфиг, сравнивает свою версию с минимальной по правилам семантического версионирования и, если она ниже, показывает блокирующий экран с кнопкой на страницу в сторе. Более мягкий ключ «рекомендуемая версия» может показывать закрываемое предложение. Бэкенд тоже может возвращать специальную ошибку для неподдерживаемых клиентов как вторую линию защиты. Это позволяет безопасно менять API, не опасаясь, что старые сборки тихо сломаются.
Q4Управление push-токенами — что может пойти не так?
Токены идентифицируют установку приложения, а не пользователя, и меняются после переустановки, восстановления данных или ротации. Если хранить только один токен на пользователя, второе устройство перестанет получать сообщения. Если никогда не удалять устаревшие токены, вы продолжаете слать сообщения на мёртвые адреса и искажаете метрики доставки. Я сохраняю токены по устройствам с платформой, версией приложения и датой последней активности, обновляю их при refresh и входе, удаляю токен при выходе, чтобы следующий пользователь телефона не получал чужие личные сообщения, и удаляю токены, которые FCM помечает как unregistered.
Q5Как бы вы безопасно выкатили рискованную функцию?
Спрятал бы её за флагом Remote Config, выключенным по умолчанию. Выпустил бы сборку со скрытой функцией, затем включил бы её для внутренних тестировщиков через условие, потом — для небольшого процента реальных пользователей. Следил бы за crash-free rate в Crashlytics, логами ошибок и ключевыми событиями Analytics, например завершением checkout, в сравнении с контрольной группой. Если что-то пойдёт не так, флаг выключается за минуты без нового релиза. Когда всё стабильно на 100%, убрал бы флаг и старую ветку кода, чтобы флаги не копились как технический долг.
Вопросы уровня senior
S1Спроектируйте систему уведомлений для приложения с миллионом пользователей.
Я отделяю намерение от доставки. Бизнес-события — заказ готов, напоминание о брони, кампания — создают в базе данных записи уведомлений с типом, пользователем, payload, приоритетом и стабильным ID. Сервис предпочтений для каждого пользователя и канала решает, отправлять ли (транзакционные включены, маркетинговые — по opt-in, тихие часы, ограничения частоты). Принятые уведомления попадают в очереди, разделённые по приоритету, чтобы крупная кампания никогда не задерживала уведомление «заказ готов». Воркеры рассылают их батчами на активные токены пользователя через FCM, классифицируют ошибки, удаляют мёртвые токены и повторяют временные сбои с backoff. Каждая запись также появляется во входящих внутри приложения, потому что push работает по принципу best-effort. Метрики покрывают отставание очереди, успешность отправки, открытия и долю отписок. Компромисс: движущихся частей больше, чем при прямом вызове FCM, зато есть справедливость, аудит и безопасные повторы.
S2Можно ли гарантировать, что push-уведомление будет доставлено ровно один раз?
Нет. Путь проходит через вашу очередь, FCM, APNs или транспорт Android и устройство, которое может быть офлайн, в Doze или с удалённым приложением; ни одно из звеньев не даёт вам сквозных гарантий. Что можно построить — это отправку at-least-once с дедупликацией. На сервере у каждого уведомления есть стабильный ID; воркер идемпотентно записывает успех, чтобы повторы после таймаута не отправляли сообщение снова. На устройстве дубли скрывает collapse ID или собственная проверка ID уведомления в приложении. Для всего действительно важного — уведомления о безопасности, статуса заказа — источник истины — это состояние внутри приложения и входящие, плюс резервный канал вроде SMS или email, если этого требует бизнес. Push — это повод открыть приложение, а не запись.
S3Firebase Remote Config или отдельный сервис feature flags?
Remote Config отлично подходит для переключателей только в мобильном приложении: принудительное обновление, режим обслуживания, простые процентные раскатки и A/B-тесты, связанные с Firebase Analytics, почти без инфраструктуры. Его ограничения проявляются, когда флаги нужно одинаково вычислять для одного пользователя в мобильном приложении, вебе и на бэкенде, когда нужен таргетинг по вашим собственным бизнес-атрибутам, процессы согласования, аудит сверх версий шаблона или серверное вычисление чувствительных правил. Тогда лучше подходит отдельный сервис флагов, open source или коммерческий, или небольшая внутренняя таблица флагов, которую отдаёт ваш API. Распространённый гибрид: Remote Config для гейтов на уровне приложения, которые должны работать до входа или когда ваш API недоступен, и флаги на бэкенде для бизнес-функций, чтобы сервер оставался главным арбитром того, что пользователю разрешено.
Глоссарий
- APNs
- Apple Push Notification service: серверы Apple, которые доставляют все удалённые уведомления на iPhone, iPad и Mac.
- FCM
- Firebase Cloud Messaging: сервис Google, который доставляет сообщения на Android напрямую, а на iOS — через APNs.
- Device token
- Адрес одной установки приложения на одном устройстве, по которому push-сервис доставляет сообщения.
- Topic
- Именованная группа, на которую подписываются устройства, чтобы одно сообщение дошло до всех подписчиков без перечисления токенов.
- Collapse key
- Идентификатор, сообщающий push-сервису, что более новое сообщение заменяет старые недоставленные с тем же ключом.
- Notification channel
- Категория уведомлений в Android со своим звуком и важностью, которую пользователь может отключить отдельно.
- Doze
- Режим энергосбережения Android, который откладывает сетевую активность на неактивных устройствах и влияет на сообщения с normal priority.
- Notification Service Extension
- Расширение iOS-приложения, которое может изменить уведомление перед показом, например расшифровать текст или прикрепить изображения.
- dSYM
- Файл отладочных символов iOS, который превращает адреса памяти в краш-репортах в читаемые имена функций и строки.
- Crash-free users
- Процент пользователей без крашей за период; главная метрика здоровья релиза в Crashlytics.
Что изучить дальше
Есть идея продукта?Давайте создадим его.
Расскажите о своей идее, продукте или команде. Обычно отвечаю в течение одного рабочего дня.