← назад к разделу

Пользователь закрыл приложение — и связь с ним оборвалась. Push-уведомления решают эту задачу: позволяют отправить сообщение на устройство, даже когда приложение не открыто. Но в мобильном вебе существует два совершенно разных пути доставки push, и они работают по-разному на разных платформах.

Два пути: web push и нативный push

Раньше уведомления были доступны только нативным приложениям — нужно было публиковать приложение в магазине и использовать системные API. Браузеры этого не умели.

Со временем появился Web Push — стандартный браузерный механизм. Он строится на трёх составляющих:

  • Push API — браузер подписывается на уведомления и получает уникальный endpoint.
  • Notification API — показывает уведомление на экране.
  • Service worker — принимает входящее сообщение и показывает уведомление, даже когда вкладка закрыта.

Схема работает так: бэкенд отправляет зашифрованное сообщение на endpoint пользователя, push-сервис браузера (у Google — FCM, у Apple — APNs) доставляет его, service worker просыпается и показывает уведомление.

Нативный push работает иначе: приложение в нативной обёртке регистрируется напрямую в платформенной службе доставки, получает device token и отдаёт его бэкенду. Дальше сервер отправляет сообщение через платформенный шлюз — минуя браузер.

Главное отличие:

Web PushНативный push
Нужна обёртка?НетДа (Capacitor / магазин)
Работает на AndroidДаДа
Работает на iOSТолько установленное PWA (16.4+)Да, надёжно
НастройкаТолько бэкендПлатформенная (FCM, APNs, сертификаты)

FCM и APNs — что это такое

Нативную доставку обеспечивают две разные службы.

FCM (Firebase Cloud Messaging) — сервис Google. Бэкенд отправляет сообщение в FCM, тот доставляет его на Android-устройство.

APNs (Apple Push Notification service) — сервис Apple. Без него push на iPhone не придёт — никаким другим способом уведомление на iOS не доставить.

На практике используют такую схему: FCM выступает единым шлюзом и для iOS тоже. APNs-ключ загружается в Firebase, бэкенд работает только с FCM, а FCM сам ретранслирует сообщения в APNs. Это убирает из бэкенда вторую интеграцию.

Что потребуется настроить:

  • Android — файл google-services.json в проекте.
  • iOS — платный аккаунт Apple Developer, APNs-ключ (.p8), включённая capability «Push Notifications» в Xcode.

Подключение через Capacitor

В приложении на Capacitor нативный push подключается плагином @capacitor/push-notifications. Он даёт единый API поверх FCM и APNs: запрос разрешения, регистрация, получение токена и обработка событий.

npm install @capacitor/push-notifications
npx cap sync
import { PushNotifications } from "@capacitor/push-notifications";

export async function registerPush(onToken: (token: string) => void) {
  let status = await PushNotifications.checkPermissions();
  if (status.receive === "prompt") {
    status = await PushNotifications.requestPermissions();
  }
  if (status.receive !== "granted") {
    throw new Error("push permission denied");
  }

  await PushNotifications.addListener("registration", (token) => {
    onToken(token.value); // отправить токен на бэкенд
  });
  await PushNotifications.addListener("registrationError", (err) => {
    console.error("push registration failed", err.error);
  });

  await PushNotifications.register();
}

Несколько важных моментов:

  • register() не показывает диалог — он только запускает регистрацию в FCM или APNs. Диалог разрешения вызывается отдельно через requestPermissions().
  • Токен приходит асинхронно в слушателе события registration, а не как возвращаемое значение.
  • Возможные значения status.receive: prompt, prompt-with-rationale (Android), granted, denied.

Разрешения и токены

Разрешение и токен — два отдельных шага, и порядок важен.

Сначала проверяют текущий статус через checkPermissions(). Если разрешение не дано, запрашивают его через requestPermissions() — это показывает системный диалог. Только при granted имеет смысл вызывать register().

Когда регистрация прошла успешно, device token нужно сохранить на бэкенде, привязав к пользователю. Именно по нему сервер потом адресует push конкретному устройству.

Токен не вечен — платформа может его сменить при переустановке, восстановлении из резервной копии или ротации ключей. Поэтому событие registration обрабатывают при каждом запуске приложения и обновляют токен на сервере.

// Push пришёл, пока приложение открыто
await PushNotifications.addListener("pushNotificationReceived", (notification) => {
  console.log("received", notification.title, notification.body);
});

// Пользователь тапнул по уведомлению
await PushNotifications.addListener("pushNotificationActionPerformed", (action) => {
  navigateTo(action.notification.data?.route);
});

Через поле data удобно передавать маршрут, чтобы открыть нужный экран при тапе.

Ограничения iOS

iOS — главная причина, по которой выбор пути не очевиден.

Web Push на iOS появился в версии 16.4, но с серьёзным условием: сайт должен быть установлен как PWA через «Поделиться → На экран Домой». Только тогда Push API и service worker становятся доступны. В обычной вкладке Safari web push на iPhone не работает вовсе. Плюс системный диалог разрешения можно показать только в ответ на явный жест пользователя — нельзя вызвать его автоматически при загрузке страницы.

Это и есть ключевая развилка. Если охват iOS критичен и нельзя рассчитывать, что пользователь установит PWA, надёжный путь один — нативный push через APNs в Capacitor-обёртке.

Web push на iOS остаётся хорошим вариантом для установленного PWA, но как единственный канал для iPhone он ненадёжен. На Android и компьютерах таких ограничений нет — там web push работает в полную силу.

Коротко

  • Push-уведомления доставляются двумя путями: web push (браузерный стандарт) и нативный push (через FCM и APNs в Capacitor-обёртке).
  • Web push работает в PWA и браузере на Android и компьютерах без какой-либо нативной упаковки.
  • На iOS web push доступен только в установленном PWA (версия 16.4+) — в обычной вкладке Safari он не работает.
  • FCM (Google) и APNs (Apple) — платформенные службы доставки; FCM можно использовать как единый шлюз и для Android, и для iOS.
  • Плагин @capacitor/push-notifications даёт единый API поверх FCM и APNs.
  • Device token нужно обновлять на сервере при каждом запуске — он может измениться.
  • Для надёжного охвата iOS нужна Capacitor-обёртка и нативный push через APNs.

Что почитать дальше

  • Capacitor — нативная обёртка для веб-приложения — как устроена обёртка, в которой работает нативный push.
  • PWA — Progressive Web App — установка на домашний экран, service worker и web push без магазинов.
  • Нативные API в мобильном вебе — другие возможности платформы, доступные через Capacitor.
  • Когда нужно нативное приложение — где заканчиваются возможности веба.