Ответ
У меня есть опыт полного цикла интеграции 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 косяк, так ты вообще можешь неделю искать, в чём дело. Терпения ноль ебать после такого.
В общем, задача вроде простая, но если делать по-человечески, с обработкой везде и кастомными фичами — это целая история. Зато когда всё работает, и уведомление летит куда надо, и кнопки жмутся, и пользователь попадает ровно в нужное место — это, блядь, прям кайф.