react-native-push-notification / ios

React Native Push Notification API for iOS.
MIT License
749 stars 286 forks source link

addEventListener('notification', ...) is not triggering anything when app is in Foreground #151

Closed felire closed 4 years ago

felire commented 4 years ago

Bug report

Summary

Hi, I'm handling notification in Native way but I would like to add (using react-native-push-notification) an onNotification method that refresh the Dashboard of my app when a notification arrives. Now, I'm able to handle the method when I click on the notification, but not when it arrives. Is there a way of doing that?

Environment info

I'm using the last version of this library and the last version of react-native-push-notification.

Steps to reproduce

This is my code:

//React Native Notifications

// Required to register for notifications
- (void)application:(UIApplication *)application didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings
{
 [RNCPushNotificationIOS didRegisterUserNotificationSettings:notificationSettings];
}
// Required for the notification event. You must call the completion handler after handling the remote notification.
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
{
  [RNCPushNotificationIOS didReceiveRemoteNotification:userInfo fetchCompletionHandler:completionHandler];
}

// IOS 4-10 Required for the localNotification event.
- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification
{
 [RNCPushNotificationIOS didReceiveLocalNotification:notification];
}

// Finish React Natuve Notifications

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
  RCTBridge *bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:launchOptions];
  #if DEBUG
  InitializeFlipper(application);
  #ifdef FB_SONARKIT_ENABLED
  [[FlipperReactPerformancePlugin sharedInstance] setBridge:bridge];
  #endif
  #endif
  RCTRootView *rootView = [[RCTRootView alloc] initWithBridge:bridge
                                                   moduleName:@"wallet"
                                            initialProperties:nil];

  rootView.backgroundColor = [[UIColor alloc] initWithRed:1.0f green:1.0f blue:1.0f alpha:1];

  self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
  UIViewController *rootViewController = [UIViewController new];
  rootViewController.view = rootView;
  self.window.rootViewController = rootViewController;
  [self.window makeKeyAndVisible];

  // Environment
  NSString *apiEnvironment = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"FPAY_API_ENVIRONMENT"];
  [Core callSetEnviroment:apiEnvironment];
  // Firebase & Fabric
  [FIRApp configure];
  [Fabric with:@[[Crashlytics class]]];
  [Fabric.sharedSDK setDebug:YES];
  // Token Push
  [self registerToPushNotifications:application];
  // First launch
  if (![[NSUserDefaults standardUserDefaults] boolForKey:@"FirstTime"]) {
    [[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"FirstTime"];
    [[NSUserDefaults standardUserDefaults] synchronize];
    NSLog(@"FIRST LAUNCH APP");
  }
  // Firebase Analytics
  [FIRAnalytics setAnalyticsCollectionEnabled:YES];
  // Splash
  [RNSplashScreen show];

  // Define UNUserNotificationCenter
  UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
  center.delegate = self;

  return YES;
}

- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge
{
#if DEBUG
  return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index" fallbackResource:nil];
#else
  return [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];
#endif
}

- (void)applicationWillEnterForeground:(UIApplication *)application {
    [UIApplication sharedApplication].applicationIconBadgeNumber = 0;
}

- (void)applicationDidBecomeActive:(UIApplication *)application {
    if(self.firstTime)
    self.firstTime = NO;

    [[FIRInstanceID instanceID] instanceIDWithHandler:^(FIRInstanceIDResult * _Nullable result,
                                                        NSError * _Nullable error) {
      if (error != nil) {
        NSLog(@"Error fetching remote instance ID: %@", error);
      } else {
        NSLog(@"Remote instance ID token: %@", result.token);
      }
    }];
  //TODO: uncoment for test refresh token
//  [Login refreshToken];
}

// With "FirebaseAppDelegateProxyEnabled": NO
- (void)application:(UIApplication *)application
    didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
    [FIRMessaging messaging].APNSToken = deviceToken;
    [RNCPushNotificationIOS didRegisterForRemoteNotificationsWithDeviceToken:deviceToken];
}

-(void)registerToPushNotifications:(UIApplication *)application
{
    [FIRMessaging messaging].delegate = self;
    [UNUserNotificationCenter currentNotificationCenter].delegate = self;
    UNAuthorizationOptions authOptions =
    UNAuthorizationOptionAlert
    | UNAuthorizationOptionSound
    | UNAuthorizationOptionBadge;
    [[UNUserNotificationCenter currentNotificationCenter] requestAuthorizationWithOptions:authOptions completionHandler:^(BOOL granted, NSError * _Nullable error) {
    }];
    [application registerForRemoteNotifications];
}

- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error {
    NSLog(@"APP_PUSH Error in registration. Error: %@", error);
    [RNCPushNotificationIOS didFailToRegisterForRemoteNotificationsWithError:error];
}

- (void)messaging:(FIRMessaging *)messaging didReceiveRegistrationToken:(NSString *)fcmToken {
    NSLog(@"FCM registration token: %@", fcmToken);
    // Notify about received token.
    NSDictionary *dataDict = [NSDictionary dictionaryWithObject:fcmToken forKey:kGCMMessageIDKey];
    [[NSNotificationCenter defaultCenter] postNotificationName:@"FCMToken" object:nil userInfo:dataDict];
    //Save identifier for push in userDefaults
    [[NSUserDefaults standardUserDefaults] setObject:fcmToken forKey:@"FCMToken"];
    [[NSUserDefaults standardUserDefaults] synchronize];
    // TODO: If necessary send token to application server.
    // Note: This callback is fired at each app startup and whenever a new token is generated.
}

- (void)applicationReceivedRemoteMessage:(FIRMessagingRemoteMessage *)remoteMessage {
    NSLog(@"APP_PUSH 2 %@", remoteMessage.appData);
}

- (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler{

    NSDictionary *userInfo = notification.request.content.userInfo;
    //Foreground
    NSLog(@"APP_PUSH from foreground %@", userInfo);
    [[FIRMessaging messaging] appDidReceiveMessage:userInfo];
    completionHandler(UNAuthorizationOptionSound | UNAuthorizationOptionAlert | UNAuthorizationOptionBadge | UNNotificationPresentationOptionAlert);
}

- (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)(void))completionHandler
    {
     NSLog( @"Handle push from background or closed" );
     // if you set a member variable in didReceiveRemoteNotification, you  will know if this is from closed or background
     NSLog(@"%@", response.notification.request.content.userInfo);
      [RNCPushNotificationIOS didReceiveNotificationResponse:response];
      completionHandler();
}

- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url
            options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options
{
  return [RCTLinkingManager application:app openURL:url options:options];
}

// Universal Links
- (BOOL)application:(UIApplication *)application continueUserActivity:(nonnull NSUserActivity *)userActivity
 restorationHandler:(nonnull void (^)(NSArray<id<UIUserActivityRestoring>> * _Nullable))restorationHandler
{
 return [RCTLinkingManager application:application
                  continueUserActivity:userActivity
                    restorationHandler:restorationHandler];
}

@end
export const configPushNotifications = () => {
  PushNotification.configure({
    onNotification: function (notification) {
      Alert.alert('pressed in noti');
      // process the notification

      // (required) Called when a remote is received or opened, or local notification is opened
      notification.finish(PushNotificationIOS.FetchResult.NoData);
    },
    senderID: senderId,
    permissions: {
      alert: true,
      badge: true,
      sound: true,
    },
    popInitialNotification: true,
    requestPermissions: true,
  });
};

Describe what you expected to happen:

  1. I expected that when I receive in notification, the alert display.
felire commented 4 years ago

I will close it, I could fixed with this code:

- (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler{

    NSDictionary *userInfo = notification.request.content.userInfo;
    //Foreground
    NSLog(@"APP_PUSH from foreground %@", userInfo);
    [[FIRMessaging messaging] appDidReceiveMessage:userInfo];

   [RNCPushNotificationIOS didReceiveRemoteNotification:userInfo
   fetchCompletionHandler:^void (UIBackgroundFetchResult result){}];
   completionHandler(UNNotificationPresentationOptionAlert);
}
arnaudambro commented 4 years ago

What is FIRMessaging ?

arnaudambro commented 4 years ago

I removed FIRMessaging

//Called when a notification is delivered to a foreground app.
- (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler{

    NSDictionary *userInfo = notification.request.content.userInfo;
    //Foreground
    NSLog(@"APP_PUSH from foreground %@", userInfo);

   [RNCPushNotificationIOS didReceiveRemoteNotification:userInfo
   fetchCompletionHandler:^void (UIBackgroundFetchResult result){}];
   completionHandler(UNNotificationPresentationOptionAlert);
}
alexking commented 2 years ago

Please note that without this change the javascript handlers will not be notified when the app is in the foreground. This should probably be added to the readme?

codal-hkrishnani commented 2 years ago

@alexking I tried with & w/o this piece of code but still i am not getting any notification while app is in foreground.

AhmedAbuelenin commented 2 years ago

@arnaudambro

I removed FIRMessaging

//Called when a notification is delivered to a foreground app.
- (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler{

    NSDictionary *userInfo = notification.request.content.userInfo;
    //Foreground
    NSLog(@"APP_PUSH from foreground %@", userInfo);

   [RNCPushNotificationIOS didReceiveRemoteNotification:userInfo
   fetchCompletionHandler:^void (UIBackgroundFetchResult result){}];
   completionHandler(UNNotificationPresentationOptionAlert);
}

Your code fixed the foreground triggering problem but if app is in background the listener won't trigger the callback function If you have a solution for this issue, that will be great.

I am using the latest updates of this lib react-native-community/push-notification-ios: 1.10.1 react-native-push-notification: 8.1.1 react-native: 0.67.3

arnaudambro commented 2 years ago

@AhmedAbuelenin I'm not sure about what you're saying : as far as I remember it's working good on my apps. I will check again as soon as I have to go to push notifications again...