fix(notifications): handle deep linking on cold start without crash
This commit is contained in:
@@ -35,6 +35,7 @@ Future<void> initApp(EnvironmentEnum env) async {
|
|||||||
initSfTracking();
|
initSfTracking();
|
||||||
|
|
||||||
configureAppRouter();
|
configureAppRouter();
|
||||||
|
onRouterReady();
|
||||||
|
|
||||||
// TODO Fase 2: await initSentry(env);
|
// TODO Fase 2: await initSentry(env);
|
||||||
|
|
||||||
|
|||||||
@@ -6,15 +6,6 @@ import 'package:flutter_local_notifications/flutter_local_notifications.dart';
|
|||||||
import 'package:navigation/navigation.dart';
|
import 'package:navigation/navigation.dart';
|
||||||
import 'package:sf_app_platform/navigation/app_router.dart';
|
import 'package:sf_app_platform/navigation/app_router.dart';
|
||||||
|
|
||||||
/// Background message handler. MUST be a top-level function annotated with
|
|
||||||
/// `@pragma('vm:entry-point')` so the Flutter engine can dispatch it from a
|
|
||||||
/// background isolate when the app is terminated or backgrounded.
|
|
||||||
///
|
|
||||||
/// This runs in a separate isolate: it CANNOT access main-isolate state
|
|
||||||
/// (providers, GetIt, navigation). Keep it side-effect free or schedule work
|
|
||||||
/// via shared_preferences. Do not call `Firebase.initializeApp` here —
|
|
||||||
/// firebase_messaging 14+ auto-initializes the default app for the background
|
|
||||||
/// isolate.
|
|
||||||
@pragma('vm:entry-point')
|
@pragma('vm:entry-point')
|
||||||
Future<void> firebaseMessagingBackgroundHandler(RemoteMessage message) async {
|
Future<void> firebaseMessagingBackgroundHandler(RemoteMessage message) async {
|
||||||
debugPrint('[FCM-bg] messageId: ${message.messageId}');
|
debugPrint('[FCM-bg] messageId: ${message.messageId}');
|
||||||
@@ -30,6 +21,9 @@ const String _localChannelDescription =
|
|||||||
final FlutterLocalNotificationsPlugin _localNotifications =
|
final FlutterLocalNotificationsPlugin _localNotifications =
|
||||||
FlutterLocalNotificationsPlugin();
|
FlutterLocalNotificationsPlugin();
|
||||||
|
|
||||||
|
Map<String, dynamic>? _pendingNotificationData;
|
||||||
|
bool _routerReady = false;
|
||||||
|
|
||||||
Future<void> setupNotifications() async {
|
Future<void> setupNotifications() async {
|
||||||
final messaging = FirebaseMessaging.instance;
|
final messaging = FirebaseMessaging.instance;
|
||||||
|
|
||||||
@@ -66,10 +60,19 @@ Future<void> setupNotifications() async {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void onRouterReady() {
|
||||||
|
_routerReady = true;
|
||||||
|
final pending = _pendingNotificationData;
|
||||||
|
if (pending != null) {
|
||||||
|
_pendingNotificationData = null;
|
||||||
|
_handleNotificationNavigation(pending);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Future<void> _initLocalNotifications() async {
|
Future<void> _initLocalNotifications() async {
|
||||||
const androidInit = AndroidInitializationSettings('@mipmap/ic_launcher');
|
const androidInit = AndroidInitializationSettings('@mipmap/ic_launcher');
|
||||||
const iosInit = DarwinInitializationSettings(
|
const iosInit = DarwinInitializationSettings(
|
||||||
requestAlertPermission: false, // already requested via FirebaseMessaging
|
requestAlertPermission: false,
|
||||||
requestBadgePermission: false,
|
requestBadgePermission: false,
|
||||||
requestSoundPermission: false,
|
requestSoundPermission: false,
|
||||||
);
|
);
|
||||||
@@ -83,7 +86,6 @@ Future<void> _initLocalNotifications() async {
|
|||||||
onDidReceiveNotificationResponse: _onLocalNotificationTapped,
|
onDidReceiveNotificationResponse: _onLocalNotificationTapped,
|
||||||
);
|
);
|
||||||
|
|
||||||
// Android 8+ requires every notification to belong to a channel.
|
|
||||||
const channel = AndroidNotificationChannel(
|
const channel = AndroidNotificationChannel(
|
||||||
_localChannelId,
|
_localChannelId,
|
||||||
_localChannelName,
|
_localChannelName,
|
||||||
@@ -153,6 +155,12 @@ void _onLocalNotificationTapped(NotificationResponse response) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void _handleNotificationNavigation(Map<String, dynamic> data) {
|
void _handleNotificationNavigation(Map<String, dynamic> data) {
|
||||||
|
if (!_routerReady) {
|
||||||
|
_pendingNotificationData = data;
|
||||||
|
debugPrint('[Notification] router not ready, queued for later');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
final currentLocation =
|
final currentLocation =
|
||||||
appRouter.routerDelegate.currentConfiguration.uri.path;
|
appRouter.routerDelegate.currentConfiguration.uri.path;
|
||||||
if (!currentLocation.startsWith(AppRoutes.legacyDashboard)) return;
|
if (!currentLocation.startsWith(AppRoutes.legacyDashboard)) return;
|
||||||
|
|||||||
Reference in New Issue
Block a user