Home > Enterprise >  Flutter - Firebase_messaging migrating from v7 to v11 - onMessage not being called
Flutter - Firebase_messaging migrating from v7 to v11 - onMessage not being called

Time:05-30

I need some help in migrating my project. Basically project is a bit old now, its running for almost 3 years and until now it was built with flutter 1.22.6. Now i am trying to migrate it to v2.10.3 and migration is almost done. Last not working piece is iOS Push Notifications.

Old version is running on firebase_messaging v.7.0.3 and it's working just fine. Upgrading flutter demands version 9.0.0 or higher.

I've done basic code migration and Android is OK, but on iOS my onMessage handler is never being called. Push is being delivered and notification is being displayed correctly when app is in background. But when its in foreground, or i will click that notification, app comes into the foreground, but callbacks are not being triggered.

The only thing i see in logs is error like: nw_endpoint_handler_set_adaptive_read_handler [C6.1 216.58.212.42:443 ready channel-flow (satisfied (Path is satisfied), viable, interface: en0, ipv4, dns)] unregister notification for read_timeout failed

OFC i've looked through most of topics on stack and other places, but none of these solutions worked for me. I'm not using any other plugins, such as flutter_local_notifications or similar, which could cause faults.

Most important pieces of code:

flutter doctor

Doctor summary (to see all details, run flutter doctor -v):
[✓] Flutter (Channel unknown, 2.10.3, on macOS 11.6 20G165 darwin-x64, locale
    pl-PL)
[✓] Android toolchain - develop for Android devices (Android SDK version
    33.0.0-rc3)
[✓] Xcode - develop for iOS and macOS (Xcode 13.2)
[✓] Chrome - develop for the web
[✓] Android Studio (version 4.2)
[✓] VS Code (version 1.67.1)
[✓] Connected device (1 available)
[✓] HTTP Host Availability

pubspec.yaml

  firebase_core: 1.16.0
  firebase_messaging: 11.3.0
  google_ml_kit: 0.7.3

AppDelegate.swift

override func application(
        _ application: UIApplication,
        didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?
    ) -> Bool {
        disableCache();
        FirebaseConfiguration.shared.setLoggerLevel(.min)
        FirebaseApp.configure()
        self.SetupPushNotification(application: application)
    
    func SetupPushNotification(application: UIApplication) -> () {
        if #available(iOS 10, *){ UNUserNotificationCenter.current().requestAuthorization(options: [.alert,.sound,.badge])
        {(granted,error) in
            if granted{
                DispatchQueue.main.async {
                    application.registerForRemoteNotifications()
                }
            } else {
                print("User Notification permission denied: \(error?.localizedDescription ?? "error")")
            }
        }
        }
    }
    
    override func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
        NotificationDeviceToken.sharedInstance.setToken(token: tokenString(deviceToken))
     }

    override func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
        print("Failed to register for remote notifications: \(error.localizedDescription)")
    }
    
    override func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any]) {
        print(userInfo)
     }

     func tokenString(_ deviceToken:Data) -> String{
         let bytes = [UInt8](deviceToken)
         var token = ""
         for byte in bytes{
             token  = String(format: "x",byte)
         }
         return token 
     }

main.dart

void startApp(AppConfig config) async {
  // add this, and it should be the first line in main method
  WidgetsFlutterBinding.ensureInitialized();
  await Firebase.initializeApp();
  ...
}

app.dart

  void init(BuildContext context, AppCubit cubit,
      SubscriptionManager subscriptionManager) {
    await FirebaseMessaging.instance.getToken();
    FirebaseMessaging.onMessage.listen((map) {
      _log.debug('onMessage: ${map.data}');
      final push = Push(map.data, PushType.onMessage);
      _streamController.add(push);
      return Future<bool>.value(true);
    });

    FirebaseMessaging.onMessageOpenedApp.listen((map) {
      _log.debug('onMessageOpenedApp: ${map.data}');
      _startAppFromPush = true;
      final push = Push(map.data, PushType.onLaunch);
      _streamController.add(push);
      return Future<bool>.value(true);
    });
  }

Info.plist

...
<key>FirebaseAppDelegateProxyEnabled<key/>
<false/>
...

Any help will be appreciated. Thanks in advance.

CodePudding user response:

Looks like I've found solutions.

I've found an issue opened in github flutterfire project. One of topics was very similar to my trouble. https://github.com/firebase/flutterfire/issues/4300

The thing is that every push sent from FCM gets additional field in payload called gcm.message_id. Notifications from APNS do not get this field.

Plugin firebase_messaging starting from version 9 up to now is validating this field and if push does not contain it, callbacks onMessage and onMessageOpenedApp are not being triggered.

If You are facing similar trouble You have 2 options:

  • add missing field in Your APNS message payload
  • create Your own fork with firebase_messaging plugin and modify FLTFirebaseMessagingPlugin in 2 places, where proper if statements are located.

I hope this will be useful to some of You. I've spent a lot of time researching this issue.

  • Related