Files
Stocky/lib/services/api/push_notification_service.dart

152 lines
5.6 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// lib/services/api/push_notification_service.dart
import 'dart:async';
import 'package:Stocky/Pages/controllers/MainController.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'api_service.dart'; // Убедитесь, что путь правильный
class PushNotificationService extends GetxService {
final FirebaseMessaging _messaging = FirebaseMessaging.instance;
final StreamController<String?> _tokenController =
StreamController<String?>.broadcast();
final StreamController<RemoteMessage> _foregroundMessageController =
StreamController<RemoteMessage>.broadcast();
// Поток для уведомлений, пришедших при открытом приложении
Stream<RemoteMessage> get foregroundMessageStream =>
_foregroundMessageController.stream;
// Поток FCM-токена
Stream<String?> get tokenStream => _tokenController.stream;
@override
void onInit() {
_initFirebase();
super.onInit();
}
@override
void onClose() {
_tokenController.close();
_foregroundMessageController.close();
super.onClose();
}
Future<void> _initFirebase() async {
try {
await Firebase.initializeApp();
// Запрашиваем разрешение
await _requestPermission();
// Получаем токен
await _getToken();
// Настраиваем обработчики
_setupMessageHandling();
} catch (e) {
debugPrint('Ошибка инициализации FCM: $e');
}
}
Future<void> _requestPermission() async {
final status = await _messaging.requestPermission(
alert: true,
badge: true,
sound: true,
// остальные по умолчанию false
);
if (status.authorizationStatus == AuthorizationStatus.authorized ||
status.authorizationStatus == AuthorizationStatus.provisional) {
debugPrint('Разрешение на уведомления получено');
} else {
debugPrint('Разрешение отклонено');
}
}
Future<void> _getToken() async {
try {
final String? token = await _messaging.getToken();
if (token != null) {
_tokenController.add(token);
print('FCM Token: $token');
// Отправляем токен на сервер — но только если ApiService уже инициализирован
if (Get.isRegistered<ApiService>()) {
Get.find<ApiService>().setFcmToken(token);
} else {
// Опционально: сохраните токен локально и отправьте позже
print('ApiService не готов — токен временно не отправлен');
}
}
} catch (e) {
debugPrint('Ошибка получения токена FCM: $e');
}
}
void _setupMessageHandling() {
// Уведомления, пришедшие при открытом приложении
FirebaseMessaging.onMessage.listen((RemoteMessage message) {
debugPrint('Уведомление в foreground: ${message.notification?.title}');
Get.find<MainController>().fetchTasks();
_foregroundMessageController.add(message); // ← Передаём дальше
});
// Пользователь нажал на уведомление из фонового режима
FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message) {
debugPrint('Уведомление открыто из фона: ${message.notification?.title}');
_handleMessageAction(message);
});
// Фоновый обработчик (для закрытого приложения)
FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler);
}
// Обработка действия из уведомления
void _handleMessageAction(RemoteMessage message) {
final data = message.data;
// Пример: действие зависит от поля "action" в payload
final action = data['action'];
switch (action) {
case 'open_task':
final taskId = data['task_id'];
if (taskId != null) {
// Здесь можно вызвать навигацию или обновить состояние
// Например, через Get.toNamed('/task/$taskId');
// Но лучше делегировать это MainController или другому слушателю
Get.find<MainController>().openTaskFromNotification(taskId);
}
break;
case 'refresh_tasks':
if (Get.isRegistered<MainController>()) {
Get.find<MainController>().fetchTasks();
}
break;
// Добавьте другие действия по мере необходимости
default:
debugPrint('Неизвестное действие: $action');
}
}
// Статический фоновый обработчик (ограниченный функционал)
static Future<void> _firebaseMessagingBackgroundHandler(
RemoteMessage message,
) async {
// В фоне нельзя использовать GetX, Dio с авторизацией и т.п.
// Только простые операции: логирование, запись в Hive и т.д.
debugPrint('Фоновое уведомление: ${message.messageId}');
// Пример: сохранить в локальную БД, чтобы обработать при запуске
}
}