From b358174646acebcfc3310aebb4c3035af437cf9f Mon Sep 17 00:00:00 2001 From: Jude Kwashie Date: Mon, 7 Sep 2026 01:18:01 +0000 Subject: [PATCH 1/2] fix(messaging,ios): register for APNs after Dart Firebase.initializeApp() When Firebase is initialized from Dart without a bundled GoogleService-Info.plist, FIRApp does not exist at launch so isAutoInitEnabled reads as NO and APNs registration is skipped. Re-run the auto-init check once the default app is configured, and keep temporary APNS-REG logs so reporters can confirm registration is requested. --- .../FLTFirebaseMessagingPlugin.m | 55 +++++++++++++++++-- 1 file changed, 50 insertions(+), 5 deletions(-) diff --git a/packages/firebase_messaging/firebase_messaging/ios/firebase_messaging/Sources/firebase_messaging/FLTFirebaseMessagingPlugin.m b/packages/firebase_messaging/firebase_messaging/ios/firebase_messaging/Sources/firebase_messaging/FLTFirebaseMessagingPlugin.m index c2534c0bd5b8..10df8ddd7057 100644 --- a/packages/firebase_messaging/firebase_messaging/ios/firebase_messaging/Sources/firebase_messaging/FLTFirebaseMessagingPlugin.m +++ b/packages/firebase_messaging/firebase_messaging/ios/firebase_messaging/Sources/firebase_messaging/FLTFirebaseMessagingPlugin.m @@ -47,6 +47,11 @@ @implementation FLTFirebaseMessagingPlugin { BOOL _notificationHandlingSetup; BOOL _applicationObserverRegistered; + // Set once APNs registration has been requested because FCM auto-init is enabled, so the + // auto-init check is not re-run (and registerForRemoteNotifications not re-issued) on every + // Firebase app initialization. + BOOL _apnsRegistrationRequested; + #if TARGET_OS_OSX // Tracks when plugin registration occurred after the macOS launch notification. BOOL _missedApplicationDidFinishLaunchingNotification; @@ -273,6 +278,40 @@ - (void)registerForRemoteNotifications { #endif } +// Registers for APNs if FCM auto-init is enabled. Registration is deferred while auto-init is +// disabled so the APNs token cannot trigger FCM registration before the user opts in (see +// `messagingSetAutoInitEnabled:`, which registers once they do). +// +// `[FIRMessaging messaging]` requires a configured default FIRApp. When Firebase is initialized +// from Dart (`Firebase.initializeApp(options:)` with no GoogleService-Info.plist / native +// `FirebaseApp.configure()`), the default app does not exist yet at launch, so `[FIRMessaging +// messaging]` is nil and `isAutoInitEnabled` reads as NO. In that case the check is skipped here +// and re-run from `pluginConstantsForFIRApp:` once Dart has configured the app. +// +// Safe to call repeatedly: APNs registration is only requested once per process. +- (void)registerForRemoteNotificationsIfAutoInitEnabled { + if (_apnsRegistrationRequested) { + NSLog(@"APNS-REG skip: already requested"); + return; + } + // Checked via FIRApp.allApps rather than `[FIRApp defaultApp]` / `[FIRMessaging messaging]` so + // a not-yet-configured app does not log the misleading "default Firebase app has not yet been + // configured" (I-COR000003) warning during launch. + if ([FLTFirebasePlugin firebaseAppNamed:@"[DEFAULT]"] == nil) { + NSLog(@"APNS-REG skip: no default FIRApp"); + return; + } + if (![FIRMessaging messaging].isAutoInitEnabled) { + NSLog(@"APNS-REG skip: auto-init disabled"); + return; + } + _apnsRegistrationRequested = YES; + NSLog(@"APNS-REG requesting registerForRemoteNotifications"); + [self registerForRemoteNotifications]; + // Forward an APNs token that may have arrived before Firebase was configured. + [self ensureAPNSTokenSetting]; +} + #ifdef __FF_NOTIFICATIONS_SUPPORTED_PLATFORM - (void)configureNotificationCenterDelegate { // Set UNUserNotificationCenter but preserve original delegate if necessary. @@ -416,11 +455,9 @@ - (void)setupNotificationHandlingWithRemoteNotification:(nullable NSDictionary * // We automatically register for remote notifications as // application:didReceiveRemoteNotification:fetchCompletionHandler: will not get called unless // registerForRemoteNotifications is called early on during app initialization, calling this from - // Dart would be too late. Defer registration when auto-init is disabled so the APNs token cannot - // trigger FCM registration before the user opts in. - if ([FIRMessaging messaging].isAutoInitEnabled) { - [self registerForRemoteNotifications]; - } + // Dart would be too late. Registration is skipped when auto-init is disabled, or deferred to + // `pluginConstantsForFIRApp:` when Firebase has not been configured natively yet. + [self registerForRemoteNotificationsIfAutoInitEnabled]; } - (void)markInitialNotificationGatheredAfterDelay { @@ -597,6 +634,7 @@ - (void)application:(NSApplication *)application - (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken { #endif + NSLog(@"APNS-REG didRegister tokenBytes=%lu", (unsigned long)deviceToken.length); FIRMessaging *messaging = [FIRMessaging messaging]; if (!messaging.isAutoInitEnabled) { _apnsToken = deviceToken; @@ -617,6 +655,7 @@ - (void)application:(NSApplication *)application - (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error { #endif + NSLog(@"APNS-REG didFail %@", error); NSLog(@"%@", error.localizedDescription); } @@ -785,6 +824,7 @@ - (void)messagingSetAutoInitEnabled:(id)arguments BOOL enabled = [arguments[@"enabled"] boolValue]; messaging.autoInitEnabled = enabled; if (enabled) { + _apnsRegistrationRequested = YES; [self registerForRemoteNotifications]; [self ensureAPNSTokenSetting]; } @@ -915,6 +955,11 @@ - (void)didReinitializeFirebaseCore:(void (^)(void))completion { } - (NSDictionary *_Nonnull)pluginConstantsForFIRApp:(FIRApp *)firebase_app { + // Called by firebase_core right after `Firebase.initializeApp()` has configured the app. For + // apps initialized from Dart this is the first point where `[FIRMessaging messaging]` exists, + // so re-run the auto-init check that was skipped during launch. + NSLog(@"APNS-REG pluginConstantsForFIRApp name=%@", firebase_app.name); + [self registerForRemoteNotificationsIfAutoInitEnabled]; return @{ @"AUTO_INIT_ENABLED" : @([FIRMessaging messaging].isAutoInitEnabled), }; From 062b83a47e1731f9c32fdab1c78b2e3a847fbb4e Mon Sep 17 00:00:00 2001 From: Jude Kwashie Date: Mon, 7 Sep 2026 01:22:16 +0000 Subject: [PATCH 2/2] fix(messaging,ios): remove temporary APNs registration NSLogs --- .../firebase_messaging/FLTFirebaseMessagingPlugin.m | 7 ------- 1 file changed, 7 deletions(-) diff --git a/packages/firebase_messaging/firebase_messaging/ios/firebase_messaging/Sources/firebase_messaging/FLTFirebaseMessagingPlugin.m b/packages/firebase_messaging/firebase_messaging/ios/firebase_messaging/Sources/firebase_messaging/FLTFirebaseMessagingPlugin.m index 10df8ddd7057..c18e79319566 100644 --- a/packages/firebase_messaging/firebase_messaging/ios/firebase_messaging/Sources/firebase_messaging/FLTFirebaseMessagingPlugin.m +++ b/packages/firebase_messaging/firebase_messaging/ios/firebase_messaging/Sources/firebase_messaging/FLTFirebaseMessagingPlugin.m @@ -291,22 +291,18 @@ - (void)registerForRemoteNotifications { // Safe to call repeatedly: APNs registration is only requested once per process. - (void)registerForRemoteNotificationsIfAutoInitEnabled { if (_apnsRegistrationRequested) { - NSLog(@"APNS-REG skip: already requested"); return; } // Checked via FIRApp.allApps rather than `[FIRApp defaultApp]` / `[FIRMessaging messaging]` so // a not-yet-configured app does not log the misleading "default Firebase app has not yet been // configured" (I-COR000003) warning during launch. if ([FLTFirebasePlugin firebaseAppNamed:@"[DEFAULT]"] == nil) { - NSLog(@"APNS-REG skip: no default FIRApp"); return; } if (![FIRMessaging messaging].isAutoInitEnabled) { - NSLog(@"APNS-REG skip: auto-init disabled"); return; } _apnsRegistrationRequested = YES; - NSLog(@"APNS-REG requesting registerForRemoteNotifications"); [self registerForRemoteNotifications]; // Forward an APNs token that may have arrived before Firebase was configured. [self ensureAPNSTokenSetting]; @@ -634,7 +630,6 @@ - (void)application:(NSApplication *)application - (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken { #endif - NSLog(@"APNS-REG didRegister tokenBytes=%lu", (unsigned long)deviceToken.length); FIRMessaging *messaging = [FIRMessaging messaging]; if (!messaging.isAutoInitEnabled) { _apnsToken = deviceToken; @@ -655,7 +650,6 @@ - (void)application:(NSApplication *)application - (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error { #endif - NSLog(@"APNS-REG didFail %@", error); NSLog(@"%@", error.localizedDescription); } @@ -958,7 +952,6 @@ - (NSDictionary *_Nonnull)pluginConstantsForFIRApp:(FIRApp *)firebase_app { // Called by firebase_core right after `Firebase.initializeApp()` has configured the app. For // apps initialized from Dart this is the first point where `[FIRMessaging messaging]` exists, // so re-run the auto-init check that was skipped during launch. - NSLog(@"APNS-REG pluginConstantsForFIRApp name=%@", firebase_app.name); [self registerForRemoteNotificationsIfAutoInitEnabled]; return @{ @"AUTO_INIT_ENABLED" : @([FIRMessaging messaging].isAutoInitEnabled),