forked from eatvio/eatvio_app
feat(pushNotifications): fixed push notifications navigation
This commit is contained in:
@@ -1,23 +1,18 @@
|
||||
import 'dart:developer' as developer;
|
||||
|
||||
import 'package:eatvio_app/core/app_router.dart';
|
||||
import 'package:eatvio_app/core/routing/route_constants.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) {
|
||||
@@ -26,18 +21,11 @@ class PushNavigationHandler {
|
||||
});
|
||||
}
|
||||
} catch (e) {
|
||||
developer.log(
|
||||
'PushNavigationHandler: error while getting initialMessage: $e',
|
||||
name: 'PushNavigationHandler',
|
||||
);
|
||||
developer.log('PushNavigationHandler: error while getting initialMessage: $e', name: 'PushNavigationHandler');
|
||||
}
|
||||
|
||||
// Тап по уведомлению, когда приложение было в фоне.
|
||||
FirebaseMessaging.onMessageOpenedApp.listen(
|
||||
(message) => _handleMessageInternal(message, source: 'onMessageOpenedApp'),
|
||||
);
|
||||
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? ?? '';
|
||||
@@ -46,118 +34,31 @@ class PushNavigationHandler {
|
||||
});
|
||||
}
|
||||
|
||||
/// Входная точка для навигации из native-кода (например, HMS через MethodChannel).
|
||||
static void handleActionUrlFromNative(String url) {
|
||||
if (url.isEmpty) {
|
||||
developer.log(
|
||||
'PushNavigationHandler.handleActionUrlFromNative: empty url',
|
||||
name: 'PushNavigationHandler',
|
||||
);
|
||||
developer.log('PushNavigationHandler.handleActionUrlFromNative: empty url', name: 'PushNavigationHandler');
|
||||
return;
|
||||
}
|
||||
|
||||
developer.log(
|
||||
'PushNavigationHandler.handleActionUrlFromNative: navigating by url=$url',
|
||||
name: 'PushNavigationHandler',
|
||||
);
|
||||
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}) {
|
||||
developer.log(
|
||||
'PushNavigationHandler: received message. data=${message.data}, notification=${message.notification?.title}, source=$source',
|
||||
name: 'PushNavigationHandler',
|
||||
);
|
||||
|
||||
final data = message.data;
|
||||
|
||||
// Пытаемся взять URL из action_url или action (бэкенд шлёт и то и другое)
|
||||
String? rawUrl = data['action_url'] as String?;
|
||||
if (rawUrl == null || rawUrl.isEmpty) {
|
||||
rawUrl = data['action'] as String?;
|
||||
}
|
||||
|
||||
if (rawUrl != null && rawUrl.isNotEmpty) {
|
||||
developer.log(
|
||||
'PushNavigationHandler: manual navigation by url=$rawUrl, source=$source',
|
||||
name: 'PushNavigationHandler',
|
||||
);
|
||||
|
||||
// Если это URL, но без схемы, добавляем https
|
||||
String finalUrl = rawUrl;
|
||||
if (!finalUrl.startsWith('http') && finalUrl.contains('/')) {
|
||||
finalUrl = 'https://${AppRouter.deepLinkHosts.first}/$finalUrl'.replaceAll('//', '/').replaceFirst('https:/', 'https://');
|
||||
}
|
||||
|
||||
AppRouter.navigateByDeepLinkUrl(finalUrl);
|
||||
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;
|
||||
}
|
||||
|
||||
// Fallback: навигация по типу уведомления, если URL отсутствует.
|
||||
final target = _resolveTargetByType(data);
|
||||
if (target != null) {
|
||||
developer.log(
|
||||
'PushNavigationHandler: fallback navigation by type, target=$target, source=$source, data=$data',
|
||||
name: 'PushNavigationHandler',
|
||||
);
|
||||
AppRouter.appRouter.go(target);
|
||||
return;
|
||||
}
|
||||
developer.log('PushNavigationHandler: navigating by action_url=$actionUrl, source=$source', name: 'PushNavigationHandler');
|
||||
|
||||
developer.log(
|
||||
'PushNavigationHandler: no action_url/action and no known type, source=$source, data=$data',
|
||||
name: 'PushNavigationHandler',
|
||||
);
|
||||
}
|
||||
|
||||
/// Определяет маршрут по полям `type` / `action` из data, если URL отсутствует.
|
||||
static String? _resolveTargetByType(Map<String, dynamic> data) {
|
||||
final type = data['type'] as String? ?? '';
|
||||
final action = data['action'] as String? ?? '';
|
||||
final databaseType = data['database_type'] as String? ?? '';
|
||||
|
||||
// Чат
|
||||
if (type == 'chat_message' || databaseType == 'chat-message') {
|
||||
return RouteConstants.chatSelectScreen;
|
||||
}
|
||||
|
||||
// Дневник
|
||||
if (type == 'diary_reminder' || action == 'open_diary' || databaseType == 'diary-reminder') {
|
||||
return RouteConstants.diaryScreen;
|
||||
}
|
||||
|
||||
// Комментарий консультанта к дневнику
|
||||
if (type == 'consultant_diary_comment' || databaseType == 'consultant-left-diary-comment') {
|
||||
return RouteConstants.diaryScreen;
|
||||
}
|
||||
|
||||
// Консультации (plan-related)
|
||||
if (type.startsWith('plan_') || type.startsWith('chosen_plan_') || databaseType.contains('plan')) {
|
||||
return RouteConstants.consultationsScreen;
|
||||
}
|
||||
|
||||
// Диета
|
||||
if (type == 'diet_started' || type == 'diet_cancelled' || databaseType.startsWith('diet-')) {
|
||||
return RouteConstants.feedScreen;
|
||||
}
|
||||
|
||||
// Бейдж
|
||||
if (type == 'badge_awarded' || databaseType == 'badge-awarded') {
|
||||
return RouteConstants.myProfileScreen;
|
||||
}
|
||||
|
||||
// Мотивация
|
||||
if (type == 'motivation') {
|
||||
return RouteConstants.feedScreen;
|
||||
}
|
||||
|
||||
return null;
|
||||
AppRouter.navigateByDeepLinkUrl(actionUrl);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user