我有一个 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>
。
我需要修复三种情况,但现在应用程序的行为很奇怪。
我做错了什么?我该如何解决这个问题?
flutter_local_notifications: ^17.2.1+2
firebase_core: ^3.4.0
cloud_firestore: ^5.3.0
firebase_messaging: ^15.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);
}