Skip to content

Not able to receive remote notification #401

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
CarloTamburrelli opened this issue Apr 7, 2023 · 4 comments
Open

Not able to receive remote notification #401

CarloTamburrelli opened this issue Apr 7, 2023 · 4 comments

Comments

@CarloTamburrelli
Copy link

CarloTamburrelli commented Apr 7, 2023

Hi, I'm totally lost. I can't receive push notifications via the IOS simulator but I can receive the notification in Android.
Here are the steps I took:

  • AppDelegate.h:
#import <React/RCTBridgeDelegate.h>
#import <UIKit/UIKit.h>
#import <UserNotifications/UNUserNotificationCenter.h>


@interface AppDelegate : UIResponder <UIApplicationDelegate, RCTBridgeDelegate, UNUserNotificationCenterDelegate>

@property (nonatomic, strong) UIWindow *window;

@end
  • AppDelegate.m:
#import "AppDelegate.h"

#import <React/RCTBridge.h>
#import <React/RCTBundleURLProvider.h>
#import <React/RCTRootView.h>
#import <FirebaseCore.h>
#import <React/RCTAppSetupUtils.h>
#import <UserNotifications/UserNotifications.h>
#import <RNCPushNotificationIOS.h>
#import <FBSDKCoreKit/FBSDKCoreKit.h>

#if RCT_NEW_ARCH_ENABLED
#import <React/CoreModulesPlugins.h>
#import <React/RCTCxxBridgeDelegate.h>
#import <React/RCTFabricSurfaceHostingProxyRootView.h>
#import <React/RCTSurfacePresenter.h>
#import <React/RCTSurfacePresenterBridgeAdapter.h>
#import <ReactCommon/RCTTurboModuleManager.h>

#import <react/config/ReactNativeConfig.h>

static NSString *const kRNConcurrentRoot = @"concurrentRoot";

@interface AppDelegate () <RCTCxxBridgeDelegate, RCTTurboModuleManagerDelegate> {
  RCTTurboModuleManager *_turboModuleManager;
  RCTSurfacePresenterBridgeAdapter *_bridgeAdapter;
  std::shared_ptr<const facebook::react::ReactNativeConfig> _reactNativeConfig;
  facebook::react::ContextContainer::Shared _contextContainer;
}
@end
#endif

@implementation AppDelegate

// Required for the register event.
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
{
 [RNCPushNotificationIOS didRegisterForRemoteNotificationsWithDeviceToken:deviceToken];
}
// 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];
}
// Required for the registrationError event.
- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error
{
 [RNCPushNotificationIOS didFailToRegisterForRemoteNotificationsWithError:error];
}
// Required for localNotification event
- (void)userNotificationCenter:(UNUserNotificationCenter *)center
didReceiveNotificationResponse:(UNNotificationResponse *)response
         withCompletionHandler:(void (^)(void))completionHandler
{
  [RNCPushNotificationIOS didReceiveNotificationResponse:response];
}

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
  [FIRApp configure];
  [[FBSDKApplicationDelegate sharedInstance] application:application didFinishLaunchingWithOptions:launchOptions];
  RCTAppSetupPrepareApp(application);

  RCTBridge *bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:launchOptions];

#if RCT_NEW_ARCH_ENABLED
  _contextContainer = std::make_shared<facebook::react::ContextContainer const>();
  _reactNativeConfig = std::make_shared<facebook::react::EmptyReactNativeConfig const>();
  _contextContainer->insert("ReactNativeConfig", _reactNativeConfig);
  _bridgeAdapter = [[RCTSurfacePresenterBridgeAdapter alloc] initWithBridge:bridge contextContainer:_contextContainer];
  bridge.surfacePresenter = _bridgeAdapter.surfacePresenter;
#endif

  NSDictionary *initProps = [self prepareInitialProps];
  UIView *rootView = RCTAppSetupDefaultRootView(bridge, @"nuovozizi", initProps);

  if (@available(iOS 13.0, *)) {
    rootView.backgroundColor = [UIColor systemBackgroundColor];
  } else {
    rootView.backgroundColor = [UIColor whiteColor];
  }

  self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
  UIViewController *rootViewController = [UIViewController new];
  rootViewController.view = rootView;
  self.window.rootViewController = rootViewController;
  [self.window makeKeyAndVisible];
  
  // Define UNUserNotificationCenter
  UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
  center.delegate = self;
  
  return YES;
}

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

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

/// This method controls whether the `concurrentRoot`feature of React18 is turned on or off.
///
/// @see: https://reactjs.org/blog/2022/03/29/react-v18.html
/// @note: This requires to be rendering on Fabric (i.e. on the New Architecture).
/// @return: `true` if the `concurrentRoot` feture is enabled. Otherwise, it returns `false`.
- (BOOL)concurrentRootEnabled
{
  // Switch this bool to turn on and off the concurrent root
  return true;
}

- (NSDictionary *)prepareInitialProps
{
  NSMutableDictionary *initProps = [NSMutableDictionary new];

#ifdef RCT_NEW_ARCH_ENABLED
  initProps[kRNConcurrentRoot] = @([self concurrentRootEnabled]);
#endif

  return initProps;
}

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

#if RCT_NEW_ARCH_ENABLED

#pragma mark - RCTCxxBridgeDelegate

- (std::unique_ptr<facebook::react::JSExecutorFactory>)jsExecutorFactoryForBridge:(RCTBridge *)bridge
{
  _turboModuleManager = [[RCTTurboModuleManager alloc] initWithBridge:bridge
                                                             delegate:self
                                                            jsInvoker:bridge.jsCallInvoker];
  return RCTAppSetupDefaultJsExecutorFactory(bridge, _turboModuleManager);
}

#pragma mark RCTTurboModuleManagerDelegate

- (Class)getModuleClassFromName:(const char *)name
{
  return RCTCoreModulesClassProvider(name);
}

- (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:(const std::string &)name
                                                      jsInvoker:(std::shared_ptr<facebook::react::CallInvoker>)jsInvoker
{
  return nullptr;
}

- (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:(const std::string &)name
                                                     initParams:
                                                         (const facebook::react::ObjCTurboModule::InitParams &)params
{
  return nullptr;
}

- (id<RCTTurboModule>)getModuleInstanceFromClass:(Class)moduleClass
{
  return RCTAppSetupDefaultModuleFromClass(moduleClass);
}

#endif

@end
  • I added also the capability in Xcode (Background Mode[remote notification] and Push notifications)

  • i subscribe with my bundle id the app on Firebase

  • I added the APNs token on Firebase

  • I added the GoogleService-info on the project

  • I register the APP ID (with my bundle id app) on the developer apple account

  • client part:

 PushNotification.configure({
      // Called when Token is generated.
      onRegister: function (token) {
        console.log('token:', token);
       // Register ur remote notificaiton to listen to
      },
      
      // Called when a remote or local notification is opened or received.
      onNotification: function (notification) {
        console.log('NOTIFICATION:----REMOTE', notification);
        console.log(notification.data.type);
        PushNotification.cancelAllLocalNotifications();
        console.log('NO Push', notification);
  
        //   .then((url) => console.log('Hello uRl', url))
        //   .catch((err) => console.log(err));
        // Do something with the notification.
        // Required on iOS only (see fetchCompletionHandler docs: https://reactnative.dev/docs/pushnotificationios)
        notification.finish(PushNotificationIOS.FetchResult.NoData);
      },
      // (optional) Called when Registered Action is pressed and invokeApp is false, if true onNotification will be called (Android)
      onAction: function (notification) {
        console.log('ACTION:', notification.action);
        console.log('NOTIFICATIONS:', notification);
  
        // PushNotification.getChannels(function (channel_ids) {
        //   console.log('Channel ID', channel_ids); // ['channel_id_1']
        // });
  
        // process the action
      },
  
      // (optional) Called when the user fails to register for remote notifications. Typically occurs when APNS is having issues, or the device is a simulator. (iOS)
      onRegistrationError: function (err) {
        console.log('THis is the error registering notification', err);
        console.error(err.message, err);
      },
  
      // IOS ONLY (optional): default: all - Permissions to register.
      permissions: {
        alert: true,
        badge: true,
        sound: true,
      },
  
      // Should the initial notification be popped automatically
      // default: true
      popInitialNotification: true,
  
      /**
       * (optional) default: true
       * - Specified if permissions (ios) and token (android and ios) will requested or not,
       * - if not, you must call PushNotificationsHandler.requestPermissions() later
       * - if you are not using remote notification or do not have Firebase installed, use this:
       *     requestPermissions: Platform.OS === 'ios'
       */
      requestPermissions: true,
    });

PS: is it sufficient to receive push notifications in the client part? Or i need to integrate another libs?

with this code I am able to take the user token:

token: {"os": "ios", "token": "80168a7e774afb1a7a4cf892b0..."}

Server side:

I use this token in the server part like this:

{
 "application": "com.company.app", (YOUR_APP_PACKAGE)
 "sandbox":true,
 "apns_tokens":[
     "80168a7e774afb1a7a4cf892b0...." // this is the client token
  ]
}

response:

{
  "results": [
      {
          "registration_token": "ejXQlECjCeI:APA91bE7oaUhaFnGyl77lFrySdEaWxocM0oj81uNezACX1wsZXiTyL4OYo5ssvFjjWYpFymMVyqBccboVcwTTW2rvykOmV_CABDM7rTIRCiJFl_9ngf7SrDSYoFouwNj69JSwlH.....",
          "apns_token": "80168a7e774afb1a7a4cf892b0...." // this is the client token
          "status": "OK"
      }
  ]
}

I use finally the registration token to send the push notification to the client:

{
 "registration_ids": ["ejXQlECjCeI:APA91bE7oaUhaFnGyl77lFrySdEaWxocM0oj81uNezACX1wsZXiTyL4OYo5ssvFjjWYpFymMVyqBccboVcwTTW2rvykOmV_CABDM7rTIRCiJFl_9ngf7SrDSYoFouwNj69JSwlH....."],
 "data": {
   "title": "Breaking News",
   "message": "New Story available."
 },
 "priority":"high"
}

response:

{
   "multicast_id": 7624604448339586269,
   "success": 1,
   "failure": 0,
   "canonical_ids": 0,
   "results": [
       {
           "message_id": "0:1680873164858645%c5375062f9fd7ecd"
       }
   ]
}

But, even if the the request was successfull, in the client side i never receive the push notification, never.

Where am I wrong? In which of these steps am I doing something wrong?

@vpawar3
Copy link

vpawar3 commented Apr 11, 2023

iOS simulator not supported to Push notification. If you want to test you need to check on real iOS device.

@CarloTamburrelli
Copy link
Author

CarloTamburrelli commented Apr 12, 2023

iOS simulator not supported to Push notification. If you want to test you need to check on real iOS device.

Ok thanks for the reply, I'll take a real device.

Can you tell me if the request from the server and client side with react native I make is correct? Thanks

@CarloTamburrelli
Copy link
Author

CarloTamburrelli commented Apr 30, 2023

Guys i managed to get the push notification working finally (with a real device), for IOS it was necessary to add the "notification" field, and using it as the "data" for android, so:

{
 "registration_ids": ["ejXQlECjCeI:APA91bE7oaUhaFnGyl77lFrySdEaWxocM0oj81uNezACX1wsZXiTyL4OYo5ssvFjjWYpFymMVyqBccboVcwTTW2rvykOmV_CABDM7rTIRCiJFl_9ngf7SrDSYoFouwNj69JSwlH....."],
 "data": {
   "title": "Breaking News",
   "message": "New Story available."
 }, 
"notification": { // only for ios devices
   "title": "Breaking News",
   "message": "New Story available."
 },
 "priority":"high"
}

This will trigger the onNotification on react native like a charm!

Very important: I use a M1 MacBook Air and also for the simulator the push notification are working (not just real device). The only problem so was the missing notification field in the request.

@ninjia0
Copy link

ninjia0 commented Oct 18, 2023

Guys i managed to get the push notification working finally (with a real device), for IOS it was necessary to add the "notification" field, and using it as the "data" for android, so:

{
 "registration_ids": ["ejXQlECjCeI:APA91bE7oaUhaFnGyl77lFrySdEaWxocM0oj81uNezACX1wsZXiTyL4OYo5ssvFjjWYpFymMVyqBccboVcwTTW2rvykOmV_CABDM7rTIRCiJFl_9ngf7SrDSYoFouwNj69JSwlH....."],
 "data": {
   "title": "Breaking News",
   "message": "New Story available."
 }, 
"notification": { // only for ios devices
   "title": "Breaking News",
   "message": "New Story available."
 },
 "priority":"high"
}

This will trigger the onNotification on react native like a charm!

Very important: I use a M1 MacBook Air and also for the simulator the push notification are working (not just real device). The only problem so was the missing notification field in the request.
where should i add this notification? i am using firebase console, there is no option to add notification?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants