OneSignal / OneSignal-Flutter-SDK

OneSignal is a free push notification service for mobile apps. This plugin makes it easy to integrate your flutter app with OneSignal
https://www.onesignal.com
Other
620 stars 212 forks source link

OneSignal Flutter v2.6.2 not working with Firebase Cloud Messaging 8.0.0-dev.14 #348

Closed davidbrenner closed 2 years ago

davidbrenner commented 3 years ago

Description:

OneSignal Flutter v2.6.2 not working with Firebase Cloud Messaging 8.0.0-dev.14

Environment

dependencies:
  flutter:
    sdk: flutter
  firebase_core: "0.7.0"
  firebase_analytics: "^7.0.1"
  firebase_auth: "^0.20.0+1"
  firebase_crashlytics: "^0.4.0+1"
  firebase_messaging: "^8.0.0-dev.14"
  cloud_firestore: "^0.16.0"
  firebase_dynamic_links: ^0.7.0+1
  firebase_in_app_messaging: "^0.3.0+1"
  firebase_storage: "^7.0.0"
  onesignal_flutter: ^2.6.2
% flutter doctor
Doctor summary (to see all details, run flutter doctor -v):
[✓] Flutter (Channel stable, 1.22.6, on macOS 11.1 20C69 darwin-x64, locale en-US)

[✓] Android toolchain - develop for Android devices (Android SDK version 30.0.2)
[✓] Xcode - develop for iOS and macOS (Xcode 12.4)
[!] Android Studio (version 4.1)
    ✗ Flutter plugin not installed; this adds Flutter specific functionality.
    ✗ Dart plugin not installed; this adds Dart specific functionality.
[✓] VS Code (version 1.53.1)
[✓] Connected device (2 available)

! Doctor found issues in 1 category.

Steps to Reproduce Issue:

  1. Start with project with working FCM
  2. Install OneSiganal Flutter SDK following these instructions: https://documentation.onesignal.com/docs/flutter-sdk-setup
  3. Attempt to receive a push notification to a physical iOS device sent via FCM console

The message is received, but the FCM handlers are not called when the message is opened. Before installing OneSignal, this was working. Additionally, FCM was working with OneSignal on older builds of this app. As part of tracking down this issue, I created a new project and added anything involving notification-related code step-by-step. Once OneSignal was added and configured, FCM's handling broke.

We use both OneSignal and FCM APIs separately, but FCM is far more important to us than OneSignal, so our solution is going to be to just remove OneSignal. We would still like to use it if there is a solution.

Anything else:

N/A

KieranLafferty commented 3 years ago

I'm also experiencing this. The best solution to this would be to make swizzling optional. It's frustrating when frameworks implement swizzling and it breaks other dependencies and there is no way to turn it off

emawby commented 3 years ago

Hello can you try the steps listed here?

davidbrenner commented 3 years ago

We stopped using OneSignal because of this. If someone can confirm that solution works, I might be able to schedule some time into exploring this again, but for now I can't put more time into it.

emawby commented 3 years ago

Moving the steps into this issue as well for easier visibility.

If the application is subclassing FlutterAppDelegate (probably most common) the apps simply need to implement the UNUserNotificationCenter protocol in the AppDelegate.h file. @interface AppDelegate : FlutterAppDelegate <UNUserNotificationCenterDelegate>

set itself as the UNUserNotificationCenterDelegate in application:didFinishLaunchingWithOptions:

if (@available(iOS 10.0, *)) {
      [UNUserNotificationCenter currentNotificationCenter].delegate = (id<UNUserNotificationCenterDelegate>) self;
}

Finally in the protocol method implementations call Super. This calls the FlutterAppDelegate version of these methods.

- (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions))completionHandler {
    [super userNotificationCenter:center willPresentNotification:notification withCompletionHandler:completionHandler];
}

- (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)(void))completionHandler {
    [super userNotificationCenter:center didReceiveNotificationResponse:response withCompletionHandler:completionHandler];
}

If your Application is not subclassing FlutterAppDelegate as described in the Flutter doc here the app will do something similar but will call the method directly on the _lifeCycleDelegate instead of Super.

- (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions))completionHandler {
    [_lifeCycleDelegate userNotificationCenter:center willPresentNotification:notification withCompletionHandler:completionHandler];
}

- (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)(void))completionHandler {
    [_lifeCycleDelegate userNotificationCenter:center didReceiveNotificationResponse:response withCompletionHandler:completionHandler];
}
MohammedAlimoor commented 3 years ago

@emawby AppDelegate in swift ?

emawby commented 3 years ago

@MohammedAlimoor Your AppDelegate file may be in Swift or it maybe in AppDelegate.h and AppDelegate.m in Objective-C

jelenalecic commented 3 years ago

@emawby

This is mine AppDelegate.swift file:

import UIKit
import Flutter
import GoogleMaps

@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
  override func application(
    _ application: UIApplication,
    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
  ) -> Bool {
    GeneratedPluginRegistrant.register(with: self)
    if #available(iOS 10.0, *) {
        UNUserNotificationCenter.current().delegate = self
    }
    return super.application(application, didFinishLaunchingWithOptions: launchOptions)
  }

    override func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
        super.userNotificationCenter(center, willPresent: notification, withCompletionHandler: completionHandler)
    }

    override func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
        super.userNotificationCenter(center, didReceive: response, withCompletionHandler: completionHandler)
    }
}

...and it's not passing notifications to dart part.

when app is in the foreground, nothing happens, when it's in the background or terminated, notification arrives but the notification object does not get passed to the dart part.

console log displays this:

'Warning: UNUserNotificationCenter delegate received call to -userNotificationCenter:didReceiveNotificationResponse:withCompletionHandler: but the completion handler was never called.'

any ideas what might have gone wrong?

when oneSignal plugin gets removed from our futter app, everything works fine :)

emawby commented 3 years ago

@jelenalecic It doesn't look like your AppDelegate class specified that it is also a UNUserNotificationCenterDelegate on line 6

emawby commented 3 years ago

Closing this issue with the workaround posted in the thread.

tayseer9 commented 3 years ago

@jelenalecic you need to cast the current delegate to UNUserNotificationCenterDelegate as follow:

override func application(
    _ application: UIApplication,
    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
  ) -> Bool {
    GeneratedPluginRegistrant.register(with: self)
    if #available(iOS 10.0, *) {
        UNUserNotificationCenter.current().delegate = self as UNUserNotificationCenterDelegate
    }
    return super.application(application, didFinishLaunchingWithOptions: launchOptions)
  }

Then you have to swizzle the methods of the UNUserNotificationCenterDelegate as you need. In my case I wanted to trigger the callback of the FirebaseMessaging, and that only works for me after calling Messaging.messaging().appDidReceiveMessage(userInfo)

  override func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
    Messaging.messaging().apnsToken = deviceToken;
    super.application(application, didRegisterForRemoteNotificationsWithDeviceToken: deviceToken)
  }

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

    // Uncomment this line to receive notifications on foreground
    // completionHandler([[.alert, .sound]])
    super.userNotificationCenter(center, willPresent: notification, withCompletionHandler: completionHandler)
  }

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

    completionHandler()
    super.userNotificationCenter(center, didReceive: response, withCompletionHandler: completionHandler)
  }

  override func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any],
   fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
    Messaging.messaging().appDidReceiveMessage(userInfo)
    completionHandler(.noData)
    super.application(application, didReceiveRemoteNotification: userInfo, fetchCompletionHandler: completionHandler)
  }

Hope my solution work for you.

pictureframing commented 2 years ago

Hi! Unfortunately none of the solutions provided by @emawby (here) or @tayseer9 (here) worked for me. Same problem as mentioned by @jelenalecic. The notification is received but not passed to dart.

When I try to specify that AppDelegate is also UNUserNotificationCenterDelegate like @emawby mentioned:

@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate, UNUserNotificationCenterDelegate {
...
}

Compilation fails due to the error:

Redundant conformance of 'AppDelegate' to protocol 'UNUserNotificationCenterDelegate'

I have tried every single approach I found in both the OneSignal and the Firebase Messaging GitHub repos. None of them worked. As long as OneSignal is specified as dependency in pubspec.yaml, Firebase Messaging won't work.

I will attach my current AppDelegate.swift (inspired by @tayseer9). Am I missing something?

Flutter Doctor [✓] Flutter (Channel stable, 2.5.3, on macOS 11.5.2 20G95 darwin-x64, locale de-DE) [!] Android toolchain - develop for Android devices (Android SDK version 30.0.2) ✗ cmdline-tools component is missing Run `path/to/sdkmanager --install "cmdline-tools;latest"` See https://developer.android.com/studio/command-line for more details. ✗ Android license status unknown. Run `flutter doctor --android-licenses` to accept the SDK licenses. See https://flutter.dev/docs/get-started/install/macos#android-setup for more details. [✓] Xcode - develop for iOS and macOS [✓] Chrome - develop for the web [✓] Android Studio (version 3.6) [✓] VS Code (version 1.63.2) [✓] Connected device (2 available)
AppDelegate.swift import UIKit import Flutter import FirebaseMessaging @UIApplicationMain @objc class AppDelegate: FlutterAppDelegate, UNUserNotificationCenterDelegate { override func application( _ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? ) -> Bool { GeneratedPluginRegistrant.register(with: self) if #available(iOS 10.0, *) { UNUserNotificationCenter.current().delegate = self as UNUserNotificationCenterDelegate } return super.application(application, didFinishLaunchingWithOptions: launchOptions) } override func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) { Messaging.messaging().apnsToken = deviceToken; } override func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) { print("Push notification received on foreground"); let userInfo = notification.request.content.userInfo Messaging.messaging().appDidReceiveMessage(userInfo) super.userNotificationCenter(center, willPresent: notification, withCompletionHandler: completionHandler) // Uncomment this line to receive notifications on foreground // completionHandler([[.alert, .sound]]) } override func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) { print("Push notification received"); super.userNotificationCenter(center, didReceive: response, withCompletionHandler: completionHandler) completionHandler() } }
rserro commented 2 years ago

@pictureframing Did you manage to solve it? I have the same problem.

rserro commented 2 years ago

@emawby I have exactly the same problem. If onesignal_flutter is in the pubspec, FirebaseMessaging handlers do not work. Tried everything in this thread. At end, I have the same "Redundant..." problem as @picturefarming

pictureframing commented 2 years ago

Hi @rserro, no we were not able to solve it. The answer from the customer support team of OneSignal was that it just does not work. No further help from their side. We postponed the project we needed this for but will probably go with another solution then having both of the packages as dependencies.

rserro commented 2 years ago

Ok, thanks @pictureframing !

stevben commented 2 years ago

Same problem for us...One Signal is not providing solutions and this is not a priority...very disappointing

jkasten2 commented 2 years ago

Update, we were able to reproduce this bug and opened a bug report with FlutterFire. Feel free to monitor https://github.com/firebase/flutterfire/issues/8792 for more updates.

jkasten2 commented 2 years ago

Update, I have summited a PR to the FlutterFire SDK to accelerate the process in getting the issue fixed: https://github.com/firebase/flutterfire/pull/8822

jkasten2 commented 2 years ago

https://github.com/firebase/flutterfire/pull/8822 as been merged, this means it will be included in their next release. Closing this issue.

jkasten2 commented 2 years ago

Google has shipped the fix for this in firebase_messaging 11.4.2. The following change log entry relates to this: