firebase / flutterfire

🔥 A collection of Firebase plugins for Flutter apps.
https://firebase.google.com/docs/flutter/setup
BSD 3-Clause "New" or "Revised" License
8.5k stars 3.92k forks source link

🐛 [firebase_messaging] [iOS] Can't handle messages on the flutter side when method swizzling is disabled #6399

Closed HiromiSakurai closed 2 years ago

HiromiSakurai commented 3 years ago

Bug report

Describe the bug Can't listen to and handle messages on the flutter side when method swizzling is disabled. We need to be able to handle messages on the flutter side even when method swizzling is disabled.

Steps to reproduce

Steps to reproduce the behavior:

  1. Implement fcm as described in the documentation and make sure it can receive and handle messages with flutter

    FirebaseMessaging.onMessage.listen((RemoteMessage message) {
      // Make sure that this callback function is invoked
      print('$message');
    });
  2. Disable method swizzling on the iOS platform side and implement delegate methods by myself.

Change Info.plist

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

Implement delegate methods

UNUserNotificationCenter.current().delegate = self
extension AppDelegate : UNUserNotificationCenterDelegate {

  func userNotificationCenter(_ center: UNUserNotificationCenter,
                              willPresent notification: UNNotification,
    withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
    let userInfo = notification.request.content.userInfo

    // With swizzling disabled you must let Messaging know about the message, for Analytics
    Messaging.messaging().appDidReceiveMessage(userInfo)

    print(userInfo)

    completionHandler([[.alert, .sound]])
  }

  func userNotificationCenter(_ center: UNUserNotificationCenter,
                              didReceive response: UNNotificationResponse,
                              withCompletionHandler completionHandler: @escaping () -> Void) {
    let userInfo = response.notification.request.content.userInfo

    // With swizzling disabled you must let Messaging know about the message, for Analytics
    Messaging.messaging().appDidReceiveMessage(userInfo)
    print(userInfo)

    completionHandler()
  }
}
  1. Make sure that it can receive fcm messages and the delegate method which I implemented is invoked.

  2. See incorrect behavior that it cannot handle messages with flutter.

    FirebaseMessaging.onMessage.listen((RemoteMessage message) {
    // Not invoked here.
    print('$message');
    });

Expected behavior

We can listen to and handle messages received through fcm with flutter even when method swizzling is disabled on the iOS platform side.


Additional context

We have to disable method swizzling to implement third party plugin like intercom.

And if we don't implement the delegate methods myself to get the analytics data, we can't check the message open rate in the firebase console.


Flutter doctor

Run flutter doctor and paste the output below:

Click To Expand ``` Doctor summary (to see all details, run flutter doctor -v): [✓] Flutter (Channel unknown, 2.2.1, on macOS 11.2.3 20D91 darwin-x64, locale ja-JP) [✓] Android toolchain - develop for Android devices (Android SDK version 30.0.3) [✓] Xcode - develop for iOS and macOS [✓] Chrome - develop for the web [✓] Android Studio (version 4.1) [✓] VS Code (version 1.56.2) [✓] Connected device (2 available) • No issues found! ```

Flutter dependencies

Run flutter pub deps -- --style=compact and paste the output below:

Click To Expand ``` Dart SDK 2.13.1 Flutter SDK 2.2.1 firebase_messaging_example 0.0.0 dependencies: - firebase_core 1.3.0 [firebase_core_platform_interface firebase_core_web flutter meta] - firebase_messaging 10.0.2 [firebase_core firebase_core_platform_interface firebase_messaging_platform_interface firebase_messaging_web flutter meta] - flutter 0.0.0 [characters collection meta typed_data vector_math sky_engine] - flutter_local_notifications 3.0.3 [flutter platform flutter_local_notifications_platform_interface timezone] - http 0.13.3 [async http_parser meta path pedantic] dev dependencies: - drive 0.1.0 [test_api flutter_test flutter_driver stack_trace universal_platform flutter] - flutter_driver 0.0.0 [file flutter flutter_test fuchsia_remote_debug_protocol path meta vm_service webdriver archive async boolean_selector characters charcode clock collection crypto matcher platform process source_span stack_trace stream_channel string_scanner sync_http term_glyph test_api typed_data vector_math] - test 1.16.8 [analyzer async boolean_selector collection coverage http_multi_server io js node_preamble package_config path pedantic pool shelf shelf_packages_handler shelf_static shelf_web_socket source_span stack_trace stream_channel typed_data web_socket_channel webkit_inspection_protocol yaml test_api test_core] dependency overrides: - firebase_core 1.3.0 [firebase_core_platform_interface firebase_core_web flutter meta] - firebase_core_platform_interface 4.0.1 [collection flutter meta plugin_platform_interface] - firebase_core_web 1.1.0 [firebase_core_platform_interface flutter flutter_web_plugins js meta] - firebase_messaging 10.0.2 [firebase_core firebase_core_platform_interface firebase_messaging_platform_interface firebase_messaging_web flutter meta] - firebase_messaging_platform_interface 3.0.2 [firebase_core flutter meta plugin_platform_interface] - firebase_messaging_web 2.0.2 [firebase_core firebase_core_web firebase_messaging_platform_interface flutter flutter_web_plugins js meta] - plugin_platform_interface 2.0.0 [meta] transitive dependencies: - _fe_analyzer_shared 22.0.0 [meta] - analyzer 1.7.1 [_fe_analyzer_shared cli_util collection convert crypto glob meta package_config path pub_semver source_span watcher yaml pedantic] - archive 3.1.2 [crypto path] - args 2.1.1 - async 2.6.1 [meta collection] - boolean_selector 2.1.0 [source_span string_scanner] - characters 1.1.0 - charcode 1.2.0 - cli_util 0.3.0 [meta path] - clock 1.1.0 - collection 1.15.0 - convert 3.0.0 [typed_data] - coverage 1.0.3 [args logging package_config path source_maps stack_trace vm_service] - crypto 3.0.1 [collection typed_data] - fake_async 1.2.0 [clock collection] - file 6.1.0 [meta path] - flutter_local_notifications_platform_interface 2.0.0+1 [flutter plugin_platform_interface] - flutter_test 0.0.0 [flutter test_api path fake_async clock stack_trace vector_math async boolean_selector characters charcode collection matcher meta source_span stream_channel string_scanner term_glyph typed_data] - flutter_web_plugins 0.0.0 [flutter js characters collection meta typed_data vector_math] - fuchsia_remote_debug_protocol 0.0.0 [process vm_service file meta path platform] - glob 2.0.1 [async collection file path pedantic string_scanner] - http_multi_server 3.0.1 [async] - http_parser 4.0.0 [charcode collection source_span string_scanner typed_data] - io 1.0.0 [meta path string_scanner] - js 0.6.3 - logging 1.0.1 - matcher 0.12.10 [stack_trace] - meta 1.3.0 - mime 1.0.0 - node_preamble 2.0.0 - package_config 2.0.0 [path] - path 1.8.0 - pedantic 1.11.0 - platform 3.0.0 - pool 1.5.0 [async stack_trace] - process 4.2.1 [file path platform] - pub_semver 2.0.0 [collection] - shelf 1.1.4 [async collection http_parser path stack_trace stream_channel] - shelf_packages_handler 3.0.0 [path shelf shelf_static] - shelf_static 1.0.0 [convert http_parser mime path shelf] - shelf_web_socket 1.0.1 [shelf stream_channel web_socket_channel] - sky_engine 0.0.99 - source_map_stack_trace 2.1.0 [path stack_trace source_maps] - source_maps 0.10.10 [source_span] - source_span 1.8.1 [collection path term_glyph] - stack_trace 1.10.0 [path] - stream_channel 2.1.0 [async] - string_scanner 1.1.0 [charcode source_span] - sync_http 0.3.0 - term_glyph 1.2.0 - test_api 0.3.0 [async boolean_selector collection meta path source_span stack_trace stream_channel string_scanner term_glyph matcher] - test_core 0.3.19 [analyzer async args boolean_selector collection coverage glob io meta package_config path pedantic pool source_map_stack_trace source_maps source_span stack_trace stream_channel vm_service yaml matcher test_api] - timezone 0.5.9 [path] - typed_data 1.3.0 [collection] - universal_platform 0.1.3 - vector_math 2.1.0 - vm_service 6.2.0 - watcher 1.0.0 [async path pedantic] - web_socket_channel 2.1.0 [async crypto stream_channel] - webdriver 3.0.0 [archive matcher path stack_trace sync_http] - webkit_inspection_protocol 1.0.0 [logging] - yaml 3.1.0 [collection source_span string_scanner] ```

entaku0818 commented 3 years ago

👍

HikaruAndo commented 3 years ago

Me too😱

markusaksli-nc commented 3 years ago

Somewhat related to https://github.com/FirebaseExtended/flutterfire/issues/4970

russellwheatley commented 3 years ago

Hey folks, as far as I'm aware, the Firebase iOS SDK messaging package which firebase_messaging plugin wraps around will not function properly if you disable swizzling. Rather than trying to change something that this library has no control over, it might be worth looking at ways to remove this property FirebaseAppDelegateProxyEnabled from your Info.plist.

For instance, I've had a look at the intercom package for iOS and cannot find a reference that indicates swizzling has to be disabled for it to work. I did, however, find a reference that documents its use in push notifications. Have you tried removing the FirebaseAppDelegateProxyEnabled property, @HiromiSakurai?

HiromiSakurai commented 2 years ago

@russellwheatley First of all, let me thank you for your very helpful advice.


the Firebase iOS SDK messaging package which firebase_messaging plugin wraps around will not function properly if you disable swizzling

I thought there was no problem to disable method swizzling because the changelog stated the following. Thank you for providing accurate information.

https://pub.dev/packages/firebase_messaging/changelog

スクリーンショット 2021-07-06 18 33 07

One thing I have to apologize for is that we don't actually use intercom, I use the SDK of Channel Talk, a customer support tool that is widely used in Asia. https://developers.channel.io/docs/ios-push-notification

Unfortunately, this sdk does not support method swizzling. We currently manage to use this SDK, although it is functionally incomplete.

What I want to know now is that is there any plan to support that in the future? I think there will be teams like us in the future who will want to disable method swizzling.

Thank you for your thoughtful commitment.

ben-xD commented 2 years ago

@HiromiSakurai, From the migration-guide.mdx / migration guide file:

  • Messaging only: If you previously added the FirebaseAppDelegateProxyEnabled key with a false value to your Info.plist to disable swizzling; you can now remove it, the plugin now supports multiple delegates and will internally forward to any other plugins that may have previously registered a delegate.
  • Additionally, swizzling is now no longer used on iOS and the plugin calls addApplicationDelegate on the FlutterPlugin Registrar instead. It is required for macOS however as the macOS registrar does not support addApplicationDelegate.
naiadelali commented 2 years ago

+1 - up