Начальный коммит
This commit is contained in:
151
lib/services/api/push_notification_service.dart
Normal file
151
lib/services/api/push_notification_service.dart
Normal file
@@ -0,0 +1,151 @@
|
||||
// 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}');
|
||||
// Пример: сохранить в локальную БД, чтобы обработать при запуске
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user