react-native-firebase icon indicating copy to clipboard operation
react-native-firebase copied to clipboard

[🐛] (Automated/Scheduled) Push Notifications NOT working in iOS

Open nl-danish opened this issue 1 year ago • 1 comments

Issue

Hi @mikehardy,

Addressing the previous old issues i've raised (https://github.com/invertase/react-native-firebase/issues/7784 ,https://github.com/invertase/react-native-firebase/issues/7589 ,https://github.com/invertase/react-native-firebase/issues/7783)

We have now upgraded our react native firebase packages, we've changed our AppDeletegate file according to the doc, and we've also cross checked APNs key and cross checked sending Manual notification to our iOS project from Dashboard and Postman cURL request, this works fine.

Basically, we've tried to skimmed through all the documentation and issues we could find, but still we are failing with our push notifications for our iOS devices which used to send earlier from our backend server whenever any new thing (shows or articles) are published, another thing to note is where our Notification type is message.

Please, could anyone guide us what's happening wrong? Please, let us know, we're in a dead loop of no solutions.

This is our notification block that we're sending from backend,

 send_notification.delay({
                'device_token': token_detail['device_token'],
                'title': notification_info[token_detail['language']]['title'],
                'message': notification_info[token_detail['language']]['message'],
                'data_message': {
                    'podcast_id': meta_data['episode_id'],
                    'event_type': 'new_podcast_published',
                    'icon_url': meta_data['image']
                },
                'extra_notification_kwargs': {
                    'image': meta_data['image']
                },
                'message_icon': meta_data['image']
            })

And, this is the function

def send_notification(params):
    """
    Send notification to user device
    """
    logger.info(params)
    push_notification_service.notify_single_device(registration_id=params['device_token'], message_title=params['title'],
                                                   message_body=params['message'], data_message=params['data_message'], low_priority=False, sound='Default', content_available=True, android_channel_id='default-channel-id', extra_notification_kwargs=params['extra_notification_kwargs'], message_icon=params['message_icon'], extra_kwargs={'mutable_content': True})

Thanks.


Project Files

Javascript

Click To Expand

package.json:

    "@react-native-firebase/analytics": "^15.3.0",
    "@react-native-firebase/app": "^15.3.0",
    "@react-native-firebase/crashlytics": "^15.3.0",
    "@react-native-firebase/in-app-messaging": "^15.3.0",
    "@react-native-firebase/messaging": "^15.3.0",

firebase.json:

{
  "react-native": {
    "messaging_android_notification_channel_id": "high-priority",
    "crashlytics_auto_collection_enabled": true,
    "crashlytics_debug_enabled": false
  }
}

iOS

Click To Expand

ios/Podfile:

  • [ ] I'm not using Pods
  • [x] I'm using Pods and my Podfile looks like:
require_relative '../node_modules/react-native/scripts/react_native_pods'
require_relative '../node_modules/@react-native-community/cli-platform-ios/native_modules'

$RNFirebaseAsStaticFramework = true


platform :ios, '11.0'

target 'NewsLaundry' do
  use_frameworks!

  config = use_native_modules!

  use_react_native!(
    :path => config[:reactNativePath],
    # to enable hermes on iOS, change `false` to `true` and then install pods
    :hermes_enabled => false,
  )

  # Permissions
  permissions_path = '../node_modules/react-native-permissions/ios'
  pod 'Permission-LocationAlways', :path => "#{permissions_path}/LocationAlways/Permission-LocationAlways.podspec"
  pod 'Permission-LocationWhenInUse', :path => "#{permissions_path}/LocationWhenInUse/Permission-LocationWhenInUse.podspec"
  pod 'Permission-PhotoLibrary', :path => "#{permissions_path}/PhotoLibrary"
  pod 'react-native-onesignal', :path => '../node_modules/react-native-onesignal'
  # React Native Version Check (for iOS app updates)
  pod 'react-native-version-check', :path => '../node_modules/react-native-version-check'
  pod 'react-native-segmented-control', :path => '../node_modules/@react-native-segmented-control/segmented-control'
  pod 'ReactNativeMoEngage', :path => '../node_modules/react-native-moengage'
  pod 'ReactNativeMoEngage', :path => '../node_modules/react-native-moengage'
  pod 'react-native-voice', :path => '../node_modules/@react-native-voice/voice'
  pod 'GoogleUtilities'

  target 'NewsLaundryTests' do
    use_frameworks!

    inherit! :complete
    # Pods for testing
  end

  # Enables Flipper.
  #
  # Note that if you have use_frameworks! enabled, Flipper will not work and
  # you should disable the next line.
  # use_flipper!()

  pre_install do |installer|
    Pod::Installer::Xcode::TargetValidator.send(:define_method, :verify_no_static_framework_transitive_dependencies) {}
  
    installer.pod_targets.each do |pod|
      if pod.name.eql?('RNPermissions') || pod.name.start_with?('Permission-')
        def pod.build_type;
          Pod::BuildType.static_library
        end
      end
    end
  end

  post_install do |installer|
    react_native_post_install(installer)
  end
end

target 'ImageNotification' do
  use_frameworks!
  pod 'Firebase/Messaging', '~> 9.4.0' # Version should match the podfile.lock version Refer https://rnfirebase.io/messaging/ios-notification-images
  pod 'GoogleUtilities'
end

target 'OneSignalNotificationServiceExtension' do
  use_frameworks!
  pod 'OneSignalXCFramework', '>= 3.4.3', '< 4.0'
  pod 'GoogleUtilities'
end

AppDelegate.m:

#import "AppDelegate.h"

#import "RNSplashScreen.h"
#import <React/RCTBridge.h>
#import <React/RCTBundleURLProvider.h>
#import <React/RCTRootView.h>
#import <React/RCTLinkingManager.h>
#import <Firebase.h>
#import <RNBackgroundDownloader.h>
#import <RNFBMessagingModule.h>
#import <FBSDKCoreKit/FBSDKCoreKit.h>
#import <CodePush/CodePush.h>
#import <ReactNativeMoEngage/MoEngageInitializer.h>
#import <MoEngageSDK/MoEngageSDK.h>
#import "Orientation.h"

@implementation AppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
    center.delegate = self;
    
    // Request authorization for notifications
    UNAuthorizationOptions authOptions = UNAuthorizationOptionAlert | UNAuthorizationOptionSound | UNAuthorizationOptionBadge;
    [center requestAuthorizationWithOptions:authOptions
                          completionHandler:^(BOOL granted, NSError * _Nullable error) {
                              // ...
                          }];

    // Register for remote notifications
    [application registerForRemoteNotifications];
    
    if ([FIRApp defaultApp] == nil) {
        [FIRApp configure];
    }

    // Set FIRMessaging delegate
    [FIRMessaging messaging].delegate = self;

    [[FIRMessaging messaging] tokenWithCompletion:^(NSString *token, NSError *error) {
  if (error != nil) {
    NSLog(@"Error getting FCM registration token: %@", error);
  } else {
    NSLog(@"FCM registration token: %@", token);
    // self.fcmRegTokenMessage.text = token;
  }
}];


    [[FBSDKApplicationDelegate sharedInstance] application:application didFinishLaunchingWithOptions:launchOptions];

    RCTBridge *bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:launchOptions];
    NSDictionary *appProperties = [RNFBMessagingModule addCustomPropsToUserProps:nil withLaunchOptions:launchOptions];
    RCTRootView *rootView = [[RCTRootView alloc] initWithBridge:bridge
                                                     moduleName:@"NewsLaundry"
                                              initialProperties:appProperties];

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

    [[MoEngageInitializer sharedInstance] initializeDefaultInstance:launchOptions];

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

    [FIRMessaging messaging].autoInitEnabled = YES;

    // [RNSplashScreen show];
    return YES;
}

- (UIInterfaceOrientationMask)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window {
    while ([[UIDevice currentDevice] isGeneratingDeviceOrientationNotifications]) {
        [[UIDevice currentDevice] endGeneratingDeviceOrientationNotifications];
    }
    return [Orientation getOrientation];
}

- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
    // Pass in UIBackgroundFetchResult based on whether operation was successful or has failed
    completionHandler(UIBackgroundFetchResultNewData);
}

- (void)application:(UIApplication*)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData*)deviceToken {
    [FIRMessaging messaging].APNSToken = deviceToken;
    [[MoEngageSDKMessaging sharedInstance] setPushToken:deviceToken];
}

- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error {
    [[MoEngageSDKMessaging sharedInstance] didFailToRegisterForPush];
}

- (void)messaging:(FIRMessaging *)messaging didReceiveRegistrationToken:(NSString *)fcmToken {
    NSLog(@"FCM registration token: %@", fcmToken);
    // Notify about received token.
    NSDictionary *dataDict = [NSDictionary dictionaryWithObject:fcmToken forKey:@"token"];
    [[NSNotificationCenter defaultCenter] postNotificationName:
     @"FCMToken" object:nil userInfo:dataDict];
    // 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)userNotificationCenter:(UNUserNotificationCenter *)center
didReceiveNotificationResponse:(UNNotificationResponse *)response
         withCompletionHandler:(void (^)())completionHandler {
    // Call only if MoEngageAppDelegateProxyEnabled is NO
    [[MoEngageSDKMessaging sharedInstance] userNotificationCenter:center didReceive:response];
    // Custom Handling of notification if Any
    completionHandler();
}

- (void)userNotificationCenter:(UNUserNotificationCenter *)center
       willPresentNotification:(UNNotification *)notification
         withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler {
    // This is to only to display Alert and enable notification sound
    completionHandler((UNNotificationPresentationOptionSound | UNNotificationPresentationOptionAlert));
}

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

- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge {
#if DEBUG
    return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index" fallbackResource:nil];
#else
    return [CodePush bundleURL];
#endif
}

- (void)application:(UIApplication *)application handleEventsForBackgroundURLSession:(NSString *)identifier completionHandler:(void (^)(void))completionHandler {
    [RNBackgroundDownloader setCompletionHandlerWithIdentifier:identifier completionHandler:completionHandler];
}

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

- (BOOL)application:(UIApplication *)application shouldSaveSecureApplicationState:(NSCoder *)coder {
    return YES;
}

- (BOOL)application:(UIApplication *)application shouldRestoreSecureApplicationState:(NSCoder *)coder {
    return YES;
}

@end


Environment

Click To Expand

react-native info output:

 System:
OS: macOS 13.3.1
CPU: (8) arm64 Apple M1
Memory: 113.25 MB / 8.00 GB
Shell: 5.9 - /bin/zsh
Binaries:
Node: 18.16.0 - /opt/homebrew/opt/node@18/bin/node
Yarn: 1.22.19 - /opt/homebrew/bin/yarn
npm: 9.5.1 - /opt/homebrew/opt/node@18/bin/npm
Watchman: 2023.05.22.00 - /opt/homebrew/bin/watchman
Managers:
CocoaPods: 1.12.1 - /Users/appName/.rvm/gems/ruby-2.7.6/bin/pod
SDKs:
iOS SDK:
Platforms: DriverKit 22.1, iOS 16.1, macOS 13.0, tvOS 16.1, watchOS 9.1
Android SDK: Not Found
IDEs:
Android Studio: 2022.2 AI-222.4459.24.2221.9971841
Xcode: 14.1/14B47b - /usr/bin/xcodebuild
Languages:
Java: 11.0.19 - /usr/bin/javac
npmPackages:
@react-native-community/cli: Not Found
react: ^17.0.2 => 17.0.2
react-native: ^0.66.5 => 0.66.5
react-native-macos: Not Found
npmGlobalPackages:
react-native: Not Found
  • Platform that you're experiencing the issue on:
    • [ x] iOS
    • [ ] Android
    • [ ] iOS but have not tested behavior on Android
    • [ ] Android but have not tested behavior on iOS
    • [ ] Both
 "@react-native-firebase/analytics": "^15.3.0"
"@react-native-firebase/app": "^15.3.0"
"@react-native-firebase/crashlytics": "^15.3.0"
"@react-native-firebase/in-app-messaging": "^15.3.0"
"@react-native-firebase/messaging": "^15.3.0"
"react-native": "^0.66.5"
  • Are you using TypeScript?
    • `No

nl-danish avatar May 17 '24 11:05 nl-danish

It appears there is no "notification" key in the FCM you are sending. Those are unreliable and I would expect they won't be delivered. You're at the mercy of Apple and any changes they make to iOS (which changes in my experience just reduce delivery of data-only message further)

Please test after modifying your send method to include a notification key and report results

mikehardy avatar May 17 '24 11:05 mikehardy

Hello 👋, to help manage issues we automatically close stale issues.

This issue has been automatically marked as stale because it has not had activity for quite some time.Has this issue been fixed, or does it still require attention?

This issue will be closed in 15 days if no further activity occurs.

Thank you for your contributions.

github-actions[bot] avatar Jun 14 '24 11:06 github-actions[bot]