feat(notifications): added push notifications navigation handling and fixed ws notification parsing

This commit is contained in:
misha
2026-03-04 09:05:00 +03:00
parent 58d99424a0
commit 08eeea6ba4
18 changed files with 424 additions and 239 deletions

View File

@@ -0,0 +1,91 @@
import 'dart:developer' as developer;
import 'package:eatvio_app/core/app_router.dart';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter/services.dart';
import 'package:flutter/widgets.dart';
/// Отвечает за навигацию по диплинкам, пришедшим в пуш-уведомлениях.
class PushNavigationHandler {
static bool _initialized = false;
static const MethodChannel _hmsChannel = MethodChannel('com.eatvioapp/hms_push');
/// Инициализация обработчиков Firebase Messaging.
/// Должна вызываться один раз после старта приложения.
static Future<void> initialize() async {
if (_initialized) return;
_initialized = true;
// Сообщение, по которому запустили приложение из "убитого" состояния.
try {
final initialMessage = await FirebaseMessaging.instance.getInitialMessage();
if (initialMessage != null) {
WidgetsBinding.instance.addPostFrameCallback((_) {
_handleMessageInternal(initialMessage, source: 'initialMessage');
});
}
} catch (e) {
developer.log(
'PushNavigationHandler: error while getting initialMessage: $e',
name: 'PushNavigationHandler',
);
}
// Тап по уведомлению, когда приложение было в фоне.
FirebaseMessaging.onMessageOpenedApp.listen(
(message) => _handleMessageInternal(message, source: 'onMessageOpenedApp'),
);
// Подписка на события от native-кода (HMS через MethodChannel).
_hmsChannel.setMethodCallHandler((call) async {
if (call.method == 'openActionUrl') {
final url = call.arguments as String? ?? '';
handleActionUrlFromNative(url);
}
});
}
/// Входная точка для навигации из native-кода (например, HMS через MethodChannel).
static void handleActionUrlFromNative(String url) {
if (url.isEmpty) {
developer.log(
'PushNavigationHandler.handleActionUrlFromNative: empty url',
name: 'PushNavigationHandler',
);
return;
}
developer.log(
'PushNavigationHandler.handleActionUrlFromNative: navigating by url=$url',
name: 'PushNavigationHandler',
);
AppRouter.navigateByDeepLinkUrl(url);
}
/// Публичный метод для единичной обработки сообщения (если понадобится где-то ещё).
static void handleMessage(RemoteMessage message) {
_handleMessageInternal(message, source: 'manualHandle');
}
static void _handleMessageInternal(RemoteMessage message, {required String source}) {
final data = message.data;
final actionUrl = data['action_url'] as String?;
if (actionUrl == null || actionUrl.isEmpty) {
developer.log(
'PushNavigationHandler: no action_url in message data, source=$source, data=$data',
name: 'PushNavigationHandler',
);
return;
}
developer.log(
'PushNavigationHandler: navigating by action_url=$actionUrl, source=$source',
name: 'PushNavigationHandler',
);
AppRouter.navigateByDeepLinkUrl(actionUrl);
}
}