Flutter Firebase 通知未重定向到相关屏幕

问题描述 投票:0回答:1

我有一个 flutter 应用程序,我使用

Firebase
flutter_local_notifications
。 目前,我的应用程序收到通知,当我单击它们时,它会打开该应用程序。但是它没有重定向到预期的屏幕。

我已经抽象了代码以使其更加清晰,这可能是问题所在。我可能会缺少一些东西。这是我的代码:

firebase_notification.helper.dart

import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:timezone/data/latest_all.dart' as timezone;
import 'package:timezone/timezone.dart' as timezone;

class FirebaseNotificationHelper {
  static final _notification = FlutterLocalNotificationsPlugin();

  static void init() {
    _notification.initialize(
      const InitializationSettings(
        android: AndroidInitializationSettings('@mipmap/ic_launcher'),
        iOS: DarwinInitializationSettings(),
      ),
    );
  }

  static pushNotification(
    RemoteMessage message,
  ) async {
    var androidPlatformChannelSpecifics = const AndroidNotificationDetails(
      'channel id',
      'channel name',
      channelDescription: 'channel description',
      importance: Importance.max,
      priority: Priority.high,
    );
    var iOSPlatformChannelSpecifics = const DarwinNotificationDetails();
    var platformChannelSpecifics = NotificationDetails(
      android: androidPlatformChannelSpecifics,
      iOS: iOSPlatformChannelSpecifics,
    );
    await _notification.show(1, message.notification?.title,
        message.notification?.body, platformChannelSpecifics);
  }
}

firebase.helper.dart

import 'dart:convert';

import 'package:firebase_core/firebase_core.dart';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter/material.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'package:grocstock/firebase_options.dart';
import 'package:grocstock/helpers/firebase_notification.helper.dart';
import 'package:grocstock/helpers/firestore.helper.dart';
import 'package:grocstock/helpers/page.helper.dart';
import 'package:grocstock/helpers/popup.helper.dart';
import 'package:grocstock/helpers/storage.helper.dart';
import 'package:grocstock/models/logged.user.model.dart';
import 'package:grocstock/modules/home/home.dart';
import 'package:grocstock/modules/preview_home/preview_home.dart';
import 'package:grocstock/services/house.service.dart';

initializeFirebase(BuildContext context) async {
  await Firebase.initializeApp(
    options: DefaultFirebaseOptions.currentPlatform,
  );

  FirebaseNotificationHelper.init();
  listenToMessages(context);
}

initFirebaseMessaging() async {
  FirebaseMessaging messaging = FirebaseMessaging.instance;

  try {
    String? token = await FirebaseMessaging.instance.getToken();
    const storage = FlutterSecureStorage();
    storage.write(key: 'fcmToken', value: token);
    await initFireBaseHouseUser(token);
  } catch (e) {
    print('Failed to get FCM token: $e');
  }

  await messaging.requestPermission();
}

listenToMessages(BuildContext context) {
  FirebaseMessaging.onMessage.listen((RemoteMessage message) async {
    if (message.notification != null) {
      print('Message also contained a notification: ${message.data}');
    }
    bool notificationsEnabled = await checkAppPopUpPermission();
    bool actionNotificationsEnabled = await checkActionAppPopUpPermission();
    bool messageNotificationsEnabled = await checkMessageAppPopUpPermission();

    if (!notificationsEnabled) return;

    String type = message.data['type'];
    bool showNotification = true;

    if (type == 'ACTION' && !actionNotificationsEnabled) {
      showNotification = false;
    } else if (type == 'MESSAGE' && !messageNotificationsEnabled) {
      showNotification = false;
    }

    if (showNotification) {
      await FirebaseNotificationHelper.pushNotification(message);
    }
  });

  FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message) async {
    await _redirectToHouse(context, message);
  });

  FirebaseMessaging.instance.getInitialMessage().then((RemoteMessage? message) {
    if (message != null) {
      print(
          'App opened from terminated state by notification with data: ${message.data}');
      _redirectToHouse(context, message);
    }
  });
}

Future<void> _redirectToHouse(BuildContext context, RemoteMessage message) async {
  try {
    String? houseId = message.data['houseId'];
    if(houseId != null && houseId.isNotEmpty) {
      var house = await getHouse(context, houseId);
      var user = await safeReadFromStorage('user', null);
      var loggedUser = LoggedUser.fromJson(jsonDecode(user!));

      String isAdmin = message.data['isAdmin'];
      if(isAdmin == 'true') {
        print('Navigate to Saved house');
        redirectToPage(context, PreviewHomePage(house: house, user: loggedUser));
      } else {
        redirectToPage(context, HomePage(house: house, user: loggedUser));
        print('Navigate to actual house');
      }
      //
      // SplashScreenState.navigatorKey.currentState?.push(
      //   housePageSelection(
      //     message.data['houseId'],
      //     loggedUser,
      //   ),
      // );
    }
  } catch (e) {
    print(e);
  }
}

splash.page.dart

class SplashScreenState extends State<SplashScreen> {
  static final GlobalKey<NavigatorState> navigatorKey =
  GlobalKey(debugLabel: 'Main Navigator');
  DarkThemeProvider themeChangeProvider = DarkThemeProvider();

  @override
  void initState() {
    super.initState();
    _initializeFirebase();
  }
  _initializeFirebase() async {
    await initializeFirebase(context);
  }


  Future<bool> _checkTermsAccepted() async {
    SharedPreferences prefs = await SharedPreferences.getInstance();
    return prefs.getBool('termsAccepted') ?? false;
  }

  @override
  Widget build(BuildContext context) {
    return ChangeNotifierProvider(
      create: (_) {
        return themeChangeProvider;
      },
      child: Consumer<DarkThemeProvider>(
        builder: (BuildContext builderContext, DarkThemeProvider value,
            Widget? child) {
          return FutureBuilder<bool>(
            future: _checkTermsAccepted(),
            builder: (context, snapshot) {
              if (snapshot.connectionState == ConnectionState.waiting) {
                return const Center(child: CircularProgressIndicator());
              } else {
                bool termsAccepted = snapshot.data ?? false;
                return MaterialApp(
                  navigatorKey: navigatorKey,
                  title: 'Welcome',
                  debugShowCheckedModeBanner: false,
                  theme: Styles.themeData(
                      themeChangeProvider.darkTheme, builderContext),
                  home: termsAccepted
                      ? Login(shouldRedirect: true)
                      : const TermsAndConditionsPage(),
                  onGenerateRoute: generateRoute,
                  builder: BotToastInit(),
                  navigatorObservers: [BotToastNavigatorObserver()],
                );
              }
            },
          );
        },
      ),
    );
  }
}

我尝试传递 BuildContext 并使用

GlobalKey<NavigatorState>
。 我需要修复三种情况,但现在应用程序的行为很奇怪。

  1. 当应用程序关闭时。
  2. 当应用程序最小化时。
  3. 当应用程序打开时。

我做错了什么?我该如何解决这个问题?

  flutter_local_notifications: ^17.2.1+2
  firebase_core: ^3.4.0
  cloud_firestore: ^5.3.0
  firebase_messaging: ^15.1.0
flutter firebase push-notification firebase-cloud-messaging flutter-local-notification
1个回答
0
投票

要在应用程序处于不同状态时正确处理 Flutter 中的 Firebase 通知导航,我建议集中导航逻辑并使用像这样的更结构化的方法

class NotificationService {
static final _instance = NotificationService._();
static NotificationService get instance => _instance;
NotificationService._();

Future<void> setupNotifications(BuildContext context) async {
// Handle notification when app is in terminated state
FirebaseMessaging.instance.getInitialMessage().then(handleNotification);

// Handle notification when app is in background
FirebaseMessaging.onMessageOpenedApp.listen(handleNotification);

// Handle notification when app is in foreground
FirebaseMessaging.onMessage.listen((message) {
  // Show local notification
  showLocalNotification(message);
 });
}

void handleNotification(RemoteMessage? message) {
if (message == null) return;

final houseId = message.data['houseId'];
final isAdmin = message.data['isAdmin'] == 'true';

if (houseId != null && houseId.isNotEmpty) {
  navigateToHouse(houseId, isAdmin);
   }
  }
}

像这样在启动屏幕中使用它

 @override
 void initState() {
  super.initState();
  NotificationService.instance.setupNotifications(context);
 }
© www.soinside.com 2019 - 2024. All rights reserved.