Problem Description
I have a Flutter app with Firebase Cloud Messaging (FCM) that works perfectly in Debug mode but fails to display notifications visually in Release mode on iOS. Here’s what happens:
- ✅ Debug mode: Notifications appear correctly when app is closed/background
- ❌ Release mode: Notifications are received by the app (status 200) but never displayed visually when app is closed/background
- ✅ Firebase Console: Notifications sent directly from Firebase Console work perfectly in both modes
- ✅ App foreground: Notifications work in both Debug and Release when app is open
Current Configuration
iOS AppDelegate.swift
import UIKit
import Flutter
import Firebase
import UserNotifications
import FirebaseMessaging
@main
@objc class AppDelegate: FlutterAppDelegate {
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
FirebaseApp.configure()
if #available(iOS 10.0, *) {
UNUserNotificationCenter.current().delegate = self
let authOptions: UNAuthorizationOptions = [.alert, .badge, .sound]
UNUserNotificationCenter.current().requestAuthorization(
options: authOptions,
completionHandler: { granted, error in
print("🔔 Notification permission: \(granted)")
})
}
application.registerForRemoteNotifications()
GeneratedPluginRegistrant.register(with: self)
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
override func application(_ application: UIApplication,
didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
print("�� APNs device token: \(deviceToken.map { String(format: "%02.2hhx", $0) }.joined())")
Messaging.messaging().apnsToken = deviceToken
}
override func application(
_ application: UIApplication,
didReceiveRemoteNotification userInfo: [AnyHashable: Any],
fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void
) {
print("📱 Notification received in background: \(userInfo)")
completionHandler(.newData)
}
override func userNotificationCenter(
_ center: UNUserNotificationCenter,
willPresent notification: UNNotification,
withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void
) {
if #available(iOS 14.0, *) {
completionHandler([.banner, .sound, .badge])
} else {
completionHandler([.alert, .sound, .badge])
}
}
}
Info.plist
UIBackgroundModes
fetch
remote-notification
FirebaseAppDelegateProxyEnabled
Runner.entitlements
aps-environment
production
Firebase Function (Node.js)
const message = {
token: token,
notification: {
title: title,
body: body,
},
apns: {
headers: {
"apns-priority": "10",
"apns-push-type": "alert",
},
payload: {
aps: {
alert: {
title: title,
body: body,
},
sound: "default",
badge: 1,
},
},
},
};
Flutter Background Handler
@pragma('vm:entry-point')
Future backgroundMessageHandler(RemoteMessage remoteMessage) async {
await Firebase.initializeApp();
debugPrint('�� Background message received: ${remoteMessage.notification?.title}');
return Future.value(true);
}
Key Observations
- FCM tokens are valid (status 200 from Firebase Function)
- APNs configuration works (Firebase Console notifications work)
- Permissions are granted (notifications work when app is foreground)
- Background modes are enabled in Info.plist
- AppDelegate methods are called (logs show notifications are received)
Question
What could be causing iOS to receive FCM notifications in Release mode but not display them visually when the app is closed or in background? The fact that Firebase Console notifications work suggests the APNs configuration is correct, but there’s something specific about my custom Firebase Function payload or iOS configuration that’s preventing visual display in Release mode.
- ✅ Verified APNs environment is set to “production” in entitlements
- ✅ Confirmed
application.registerForRemoteNotifications()is called - ✅ Added
@pragma('vm:entry-point')to prevent tree shaking - ✅ Set
FirebaseAppDelegateProxyEnabledto false - ✅ Simplified APNs payload (removed
content-available: 1) - ✅ Verified Xcode Signing & Capabilities has Push Notifications enabled
- ✅ Tested with fresh FCM tokens instead of stored ones