Какой у тебя опыт работы с push-уведомлениями в Flutter?

Ответ

У меня есть опыт полного цикла интеграции push-уведомлений в Flutter-приложения, от настройки до глубокой кастомизации обработки.

1. Базовая настройка с Firebase Cloud Messaging (FCM): Я настраивал FCM для проектов на Android, iOS и Web.

  • Добавление конфигурационных файлов (google-services.json, GoogleService-Info.plist).
  • Настройка entitlements и capabilities для iOS (Push Notifications, Background Modes).
  • Реализация запроса разрешений с учётом платформенных особенностей.
    Future<void> requestPermissions() async {
    FirebaseMessaging messaging = FirebaseMessaging.instance;
    NotificationSettings settings = await messaging.requestPermission(
    alert: true,
    badge: true,
    sound: true,
    );
    if (settings.authorizationStatus == AuthorizationStatus.authorized) {
    print('Разрешение получено');
    }
    }

2. Обработка уведомлений во всех состояниях приложения: Ключевая задача — корректно обработать уведомление, где бы ни было приложение.

// 1. Foreground
FirebaseMessaging.onMessage.listen((RemoteMessage message) {
  // Показываем своё уведомление, т.к. системное не появится.
  showLocalNotification(message);
});

// 2. Background/Терминировано (требуется статический/глобальный обработчик)
@pragma('vm:entry-point')
Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
  // Инициализируем Firebase в изоляте.
  await Firebase.initializeApp();
  // Обрабатываем данные уведомления.
  handleNotificationData(message.data);
}
// Регистрируем обработчик в main()
FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler);

3. Глубокие ссылки и кастомные действия: Я использовал пакет flutter_local_notifications для отображения кастомных уведомлений с действиями (actions) и передавал в payload данные для навигации внутри приложения.

// При инициализации канала уведомлений добавляем действия.
const AndroidNotificationDetails androidDetails = AndroidNotificationDetails(
  'channel_id',
  'Channel Name',
  actions: [
    AndroidNotificationAction('reply', 'Ответить', showsUserInterface: true),
  ],
);
// При тапе на уведомление или действие извлекаем payload и перенаправляем пользователя.

4. Тестирование и отладка: Я использовал консоль Firebase, Postman для отправки тестовых уведомлений и тщательно логировал токены устройств и статусы доставки для отладки проблем, особенно на iOS (сертификаты APNs).

Ответ 18+ 🔞

А, ну это же моя любимая тема — пуш-уведомления! Ёпта, сколько нервов на них потрачено, ебать мои старые костыли. Казалось бы, фигня — прилетело сообщение, пикнуло, всё. Ан нет, тут подводных камней — овердохуища.

Вот смотри, как обычно бывает. Берёшь ты Firebase, этот FCM. На андроиде вроде норм, google-services.json кинул, в build.gradle пару строк добавил — и уже почти работает. А потом открываешь iOS-часть проекта, и тут начинается ёперный театр. Сертификаты APNs, GoogleService-Info.plist, entitlements, capabilities... Чих-пых тебя в сраку! Один раз забыл в Xcode галочку в Background Modes поставить — и всё, сиди и гадай, почему в фоне не приходит. Подозрение ебать чувствую, что просто где-то опечатка.

А самое весёлое — это обработка. Ну, в смысле, когда приложение открыто — понятно, лови событие onMessage и делай что хочешь.

FirebaseMessaging.onMessage.listen((RemoteMessage message) {
  // Показываем своё уведомление, т.к. системное не появится.
  showLocalNotification(message);
});

Но вот когда оно свёрнуто или вообще закрыто — тут уже нужен отдельный, блядь, обработчик. И его надо объявить как-то так, шоб он был глобальный, статичный, с магической аннотацией. Иначе — хуй с горы, ничего не сработает.

@pragma('vm:entry-point')
Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
  // Инициализируем Firebase в изоляте.
  await Firebase.initializeApp();
  // Обрабатываем данные уведомления.
  handleNotificationData(message.data);
}
// Регистрируем обработчик в main()
FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler);

И самое главное — не забыть в этом изоляте Firebase инициализировать заново, а то будешь ловить ошибки, которых в логах даже нет. Доверия ебать ноль к этой тихой работе в фоне.

А ещё круче — это глубокие ссылки и кастомные кнопки в уведомлениях. Хочешь, чтобы была кнопка «Ответить» или «Посмотреть»? Придётся ставить flutter_local_notifications и там уже городить свой огород: каналы, иконки, действия.

const AndroidNotificationDetails androidDetails = AndroidNotificationDetails(
  'channel_id',
  'Channel Name',
  actions: [
    AndroidNotificationAction('reply', 'Ответить', showsUserInterface: true),
  ],
);

И потом ловить тап на эту кнопку, вытаскивать из payload данные и как-то херачить навигацию внутри приложения. Главное — не запутаться, где какой экран должен открыться. А то пользователь тапнет, а его в корзину выкинет вместо чата. Волнение ебать.

И да, про тестирование. Консоль Firebase — это ладно. Но когда начинаешь слать запросы через Postman, вручную формируя этот data и notification — вот тут понимаешь, насколько всё хрупкое. Один неправильный key в данных — и приложение в фоне просто сдохнет, даже не пикнув. А на iOS, если с сертификатами APNs косяк, так ты вообще можешь неделю искать, в чём дело. Терпения ноль ебать после такого.

В общем, задача вроде простая, но если делать по-человечески, с обработкой везде и кастомными фичами — это целая история. Зато когда всё работает, и уведомление летит куда надо, и кнопки жмутся, и пользователь попадает ровно в нужное место — это, блядь, прям кайф.