After migrating a Flutter iOS app to make use of UISceneDelegation (by way of FlutterSceneDelegate in Information.plist), FirebaseMessaging.onMessage in Dart by no means fires for foreground messages. Background banners seem appropriately by way of APNs, however the Dart layer receives nothing — no onMessage, no onMessageOpenedApp logs, and no getInitialMessage information.
What works:
-
FCM token is generated and non-null
-
Push notification banners seem when the app is backgrounded
-
didRegisterForRemoteNotificationsWithDeviceTokenfires appropriately -
UNUserNotificationCenterwillPresent fires appropriately (confirmed by way of Swift print) -
Messaging.messaging().appDidReceiveMessage(userInfo)is known as efficiently from willPresent
What breaks:
-
FirebaseMessaging.onMessageby no means fires in Dart -
FirebaseMessaging.onMessageOpenedAppby no means fires in Dart -
No Dart-side logs seem for any incoming notification
-
Root Trigger (Identified): When utilizing
FlutterImplicitEngineDelegate, plugins are registered by way of:func didInitializeImplicitFlutterEngine(_ engineBridge: FlutterImplicitEngineBridge) { GeneratedPluginRegistrant.register(with: engineBridge.pluginRegistry) }, After GeneratedPluginRegistrant.register runs, FLTFirebaseMessagingPlugin is predicted to set itself as Messaging.messaging().delegate. Nevertheless, printing the delegate instantly after registration reveals: print(Messaging.messaging().delegate) // → nil
This didn’t happen earlier than the UIScene migration, when GeneratedPluginRegistrant.register(with: self) was known as in didFinishLaunchingWithOptions and FlutterAppDelegate (which lives for the app’s lifetime) held the plugins strongly.
That is my appdelegate.swift file:
import Flutter
import Firebase
import UserNotifications
import flutter_local_notifications
@fundamental
@objc class AppDelegate: FlutterAppDelegate, FlutterImplicitEngineDelegate {
override func software(
_ software: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
FirebaseApp.configure()
UNUserNotificationCenter.present().delegate = self
let authOptions: UNAuthorizationOptions = [.alert, .badge, .sound]
UNUserNotificationCenter.present().requestAuthorization(choices: authOptions) { _, _ in }
software.registerForRemoteNotifications()
// GeneratedPluginRegistrant.register(with: self)
return tremendous.software(software, didFinishLaunchingWithOptions: launchOptions)
}
func didInitializeImplicitFlutterEngine(_ engineBridge: FlutterImplicitEngineBridge) {
// That is required to make any communication accessible within the motion isolate.
FlutterLocalNotificationsPlugin.setPluginRegistrantCallback { (registry) in
GeneratedPluginRegistrant.register(with: registry)
}
GeneratedPluginRegistrant.register(with: engineBridge.pluginRegistry)
}
override func software(_ software: UIApplication,
didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Knowledge) {
Messaging.messaging().apnsToken = deviceToken
// print("✅ APNs token: (deviceToken.map { String(format: "%02x", $0) }.joined())")
tremendous.software(software, didRegisterForRemoteNotificationsWithDeviceToken: deviceToken)
}
// override func software(_ software: UIApplication,
// didReceiveRemoteNotification userInfo: [AnyHashable : Any],
// fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
// Messaging.messaging().appDidReceiveMessage(userInfo)
// completionHandler(.newData)
// }
}
And that is my data.plist file:
UIApplicationSceneManifest
UIApplicationSupportsMultipleScenes
UISceneConfigurations
UIWindowSceneSessionRoleApplication
UISceneClassName
UIWindowScene
UISceneDelegateClassName
FlutterSceneDelegate
UISceneConfigurationName
flutter
UISceneStoryboardFile
Major
CFBundleDevelopmentRegion
$(DEVELOPMENT_LANGUAGE)
CFBundleDisplayName
Bongo Funds
CFBundleExecutable
$(EXECUTABLE_NAME)
CFBundleIdentifier
$(PRODUCT_BUNDLE_IDENTIFIER)
CFBundleInfoDictionaryVersion
6.0
CFBundleName
bongo_pay
CFBundlePackageType
APPL
CFBundleShortVersionString
$(FLUTTER_BUILD_NAME)
CFBundleSignature
????
UIBackgroundModes
remote-notification
FirebaseAppDelegateProxyEnabled
NSAppTransportSecurity
NSAllowsArbitraryLoads
CFBundleVersion
$(FLUTTER_BUILD_NUMBER)
NSLocationWhenInUseUsageDescription
We want your location to offer higher service.
NSLocationAlwaysAndWhenInUseUsageDescription
This app makes use of notifications
NSLocationAlwaysUsageDescription
We want your location even when the app is within the background.
NSUserTrackingUsageDescription
This app makes use of notifications
LSRequiresIPhoneOS
UILaunchStoryboardName
LaunchScreen
UIMainStoryboardFile
Major
NSFaceIDUsageDescription
This app requires Face ID authentication to safe your private information and guarantee solely you'll be able to entry your account.
NSCameraUsageDescription
We want entry to your digital camera to take pictures.
NSPhotoLibraryUsageDescription
We want entry to your photograph library to add photographs.
NSAppleMusicUsageDescription
This app doesn't use Apple Music however requires restricted media library entry for system options.
UISupportedInterfaceOrientations
UIInterfaceOrientationPortrait
UIInterfaceOrientationLandscapeLeft
UIInterfaceOrientationLandscapeRight
UISupportedInterfaceOrientations~ipad
UIInterfaceOrientationPortrait
UIInterfaceOrientationPortraitUpsideDown
UIInterfaceOrientationLandscapeLeft
UIInterfaceOrientationLandscapeRight
CADisableMinimumFrameDurationOnPhone
UIApplicationSupportsIndirectInputEvents
io.flutter.embedded_views_preview
NSMicrophoneUsageDescription
We want entry to your microphone for video or audio seize in net pages.
NSPhotoLibraryAddUsageDescription
We want entry to save lots of photographs to your photograph library.
UIFileSharingEnabled
LSSupportsOpeningDocumentsInPlace
UIStatusBarHidden
