React-native-firebase: 馃敟 Does RNFirebase support receiving notifications directly from APNs

Created on 16 Apr 2020  路  14Comments  路  Source: invertase/react-native-firebase


Issue



We've been using RNFirebase v6 successfully on android for some time now. For iOS, we were using a separate library as we send push notifications directly through APNs (not using FCM). However, in order to simplify our client side code, we've been exploring if it's possible to correctly process / handle push notifications sent directly via APNs using RNFirebase on the client.

We are able to successfully build and generate the APNS token on iOS, but the library doesn't seem to process the incoming notifications. The same notifications display correctly in the background, so it's not a push token issue.

Happy to provide more details if that helps!


Project Files






Javascript

Click To Expand

#### `package.json`:

"dependencies": {
    "@lingui/core": "2.9.1",
    "@react-native-community/async-storage": "1.6.1",
    "@react-native-firebase/app": "6.4.0",
    "@react-native-firebase/messaging": "6.4.0",
    "apollo-boost": "0.4.3",
    "graphql": "14.4.2",
    "graphql-tag": "2.10.1",
    "immer": "3.2.0",
    "immutable": "4.0.0-rc.12",
    "intl": "1.2.5",
    "jwt-decode": "2.2.0",
    "lodash.debounce": "4.0.8",
    "moment": "2.24.0",
    "react": "16.9.0",
    "react-native": "0.61.5",
    "react-native-android-open-settings": "1.3.0",
    "react-native-animatable": "1.3.2",
    "react-native-better-clipboard": "0.5.0",
    "react-native-branch": "2.3.3",
    "react-native-config": "0.12.0",
    "react-native-country-picker-modal": "0.8.0",
    "react-native-device-info": "2.3.2",
    "react-native-extra-dimensions-android": "1.2.5",
    "react-native-idfa": "4.1.0",
    "react-native-keep-awake": "4.0.0",
    "react-native-keyboard-aware-scroll-view": "0.8.0",
    "react-native-linear-gradient": "^2.5.6",
    "react-native-modal": "11.3.1",
    "react-native-permissions": "1.2.0",
    "react-native-rate": "1.1.7",
    "react-native-responsive-screen": "1.2.2",
    "react-native-version-info": "1.0.1",
    "react-redux": "7.1.0",
    "redux": "4.0.4",
    "redux-logger": "3.0.6",
    "redux-saga": "1.1.3",
    "redux-thunk": "2.3.0",
    "reselect": "4.0.0"
  }
#### `firebase.json` for react-native-firebase v6:
# N/A
### iOS
Click To Expand

#### `ios/Podfile`: - [ ] I'm not using Pods - [x] I'm using Pods and my Podfile looks like:

platform :ios, '9.0'
require_relative '../node_modules/@react-native-community/cli-platform-ios/native_modules'

target 'Rune' do
  # React core
  pod 'FBLazyVector', :path => "../node_modules/react-native/Libraries/FBLazyVector"
  pod 'FBReactNativeSpec', :path => "../node_modules/react-native/Libraries/FBReactNativeSpec"
  pod 'RCTRequired', :path => "../node_modules/react-native/Libraries/RCTRequired"
  pod 'RCTTypeSafety', :path => "../node_modules/react-native/Libraries/TypeSafety"
  pod 'React', :path => '../node_modules/react-native/'
  pod 'React-Core', :path => '../node_modules/react-native/'
  pod 'React-CoreModules', :path => '../node_modules/react-native/React/CoreModules'
  pod 'React-Core/DevSupport', :path => '../node_modules/react-native/'
  pod 'React-RCTActionSheet', :path => '../node_modules/react-native/Libraries/ActionSheetIOS'
  pod 'React-RCTAnimation', :path => '../node_modules/react-native/Libraries/NativeAnimation'
  pod 'React-RCTBlob', :path => '../node_modules/react-native/Libraries/Blob'
  pod 'React-RCTImage', :path => '../node_modules/react-native/Libraries/Image'
  pod 'React-RCTLinking', :path => '../node_modules/react-native/Libraries/LinkingIOS'
  pod 'React-RCTNetwork', :path => '../node_modules/react-native/Libraries/Network'
  pod 'React-RCTSettings', :path => '../node_modules/react-native/Libraries/Settings'
  pod 'React-RCTText', :path => '../node_modules/react-native/Libraries/Text'
  pod 'React-RCTVibration', :path => '../node_modules/react-native/Libraries/Vibration'
  pod 'React-Core/RCTWebSocket', :path => '../node_modules/react-native/'
  pod 'React-cxxreact', :path => '../node_modules/react-native/ReactCommon/cxxreact'
  pod 'React-jsi', :path => '../node_modules/react-native/ReactCommon/jsi'
  pod 'React-jsiexecutor', :path => '../node_modules/react-native/ReactCommon/jsiexecutor'
  pod 'React-jsinspector', :path => '../node_modules/react-native/ReactCommon/jsinspector'
  pod 'ReactCommon/jscallinvoker', :path => "../node_modules/react-native/ReactCommon"
  pod 'ReactCommon/turbomodule/core', :path => "../node_modules/react-native/ReactCommon"
  pod 'Yoga', :path => '../node_modules/react-native/ReactCommon/yoga'
  pod 'DoubleConversion', :podspec => '../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec'
  pod 'glog', :podspec => '../node_modules/react-native/third-party-podspecs/glog.podspec'
  pod 'Folly', :podspec => '../node_modules/react-native/third-party-podspecs/Folly.podspec'

  # Autolinking for packages
  use_native_modules!

  # Manually linked packages
  pod "Branch-SDK", path: "../node_modules/react-native-branch/ios"
end
#### `AppDelegate.m`:
/**
 * Copyright (c) 2015-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

#import "AppDelegate.h"

#import <React/RCTBridge.h>
#import <React/RCTBundleURLProvider.h>
#import <React/RCTRootView.h>
#import "RNBranch.h"  // Docs recommend using <react-native-branch/RNBranch.h> but XCode complains (probably because we use use_frameworks!
#import <PushKit/PushKit.h>
#import "ReactNativeConfig.h"
#import "RNCallKeep.h"
#import "RNBootSplash.h"
#import <Firebase.h>

@implementation AppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
  // Initialize the Branch Session (library for deep links)
  [RNBranch initSessionWithLaunchOptions:launchOptions isReferrable:YES];

  // Initialize Firebase
  if ([FIRApp defaultApp] == nil) {
    [FIRApp configure];
  }

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

  RCTRootView *rootView = [[RCTRootView alloc] initWithBridge:bridge
                                                   moduleName:@"Rune"
                                            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;
  [RNBootSplash initWithStoryboard:@"BootSplash" rootView:rootView]; // Initialize RNBootSplash
  self.window.rootViewController = rootViewController;
  [self.window makeKeyAndVisible];

  return YES;
}

- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge
{
#if DEBUG
  NSString *bundlerIPAddress = [ReactNativeConfig envFor:@"BUNDLER_IP_ADDRESS"];
  NSString *debugBundleUrl = [NSString stringWithFormat:@"%@%@%@", @"http://", bundlerIPAddress, @":8082/index.bundle?platform=ios&dev=true"];
  NSLog(@"%@", debugBundleUrl);
  return [NSURL URLWithString:debugBundleUrl];
#else
  return [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];
#endif
}

// Needed by Branch
- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options
{
  if (![RNBranch.branch application:app openURL:url options:options]) {
    // do other deep link routing for the Facebook SDK, Pinterest SDK, etc
  }
  return YES;
}

// Needed by Branch
- (BOOL)application:(UIApplication *)application continueUserActivity:(NSUserActivity *)userActivity restorationHandler:(void (^)(NSArray *restorableObjects))restorationHandler
{
  return [RNBranch continueUserActivity:userActivity];
}

@end


Android

Click To Expand

#### Have you converted to AndroidX? - [ ] my application is an AndroidX application? - [ ] I am using `android/gradle.settings` `jetifier=true` for Android compatibility? - [ ] I am using the NPM package `jetifier` for react-native compatibility? #### `android/build.gradle`:

// N/A
#### `android/app/build.gradle`:
// N/A
#### `android/settings.gradle`:
// N/A
#### `MainApplication.java`:
// N/A
#### `AndroidManifest.xml`:
<!-- N/A -->


Environment

Click To Expand

**`react-native info` output:**

System:
    OS: macOS 10.15.3
    CPU: (16) x64 Intel(R) Core(TM) i9-9880H CPU @ 2.30GHz
    Memory: 2.52 GB / 32.00 GB
    Shell: 3.2.57 - /bin/bash
  Binaries:
    Node: 12.7.0 - /usr/local/bin/node
    Yarn: 1.22.4 - ~/.yarn/bin/yarn
    npm: 6.14.4 - /usr/local/bin/npm
    Watchman: 4.9.0 - /usr/local/bin/watchman
  SDKs:
    iOS SDK:
      Platforms: iOS 13.4, DriverKit 19.0, macOS 10.15, tvOS 13.4, watchOS 6.2
    Android SDK:
      API Levels: 23, 25, 26, 27, 28
      Build Tools: 26.0.2, 27.0.3, 28.0.2, 28.0.3
      System Images: android-22 | Google APIs Intel x86 Atom, android-24 | Google APIs Intel x86 Atom, android-26 | Google APIs Intel x86 Atom_64, android-28 | Google Play Intel x86 Atom
  IDEs:
    Android Studio: 3.6 AI-192.7142.36.36.6241897
    Xcode: 11.4/11E146 - /usr/bin/xcodebuild
  npmPackages:
    react: 16.9.0 => 16.9.0 
    react-native: 0.61.5 => 0.61.5 
  npmGlobalPackages:
    create-react-native-app: 2.0.2
    react-native-cli: 2.0.1
    react-native-create-library: 3.1.2
    react-native-rename: 2.4.0
- **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` version you're using that has this issue:** - `6.4.0` - **`Firebase` module(s) you're using that has the issue:** - `Messaging` - **Are you using `TypeScript`?** - `N`




Messaging >= 6 Waiting for User Response

All 14 comments

I think you are really going to want to try the @next tag on the RNFBv6 versions so you get the benefit of a big pile of fixes that should be released as stable shortly: #3339 - users report problems similar to yours, which generated those fixes, and same users report success using the @next tag with that PR in it

@mikehardy thanks for the quick response! Awesome, I'll give the @next tag a try 馃槃

@mikehardy I tried the @next tag, but still face the same issue.

  • If a message is sent directly from APNs (no FCM involvement server side), it correctly displays a notification in the background, but doesn't trigger the onMessage handler in the foreground.
  • I'm making sure to call await messaging().registerDeviceForRemoteMessages() on every boot and it succeeds.
  • The same frontend code successfully receives messages in foreground on android though. These are indeed sent through FCM.

@Salakar did you try this with the pusher app?

@sanjaypojo have you followed the ios steps, specifically https://rnfirebase.io/messaging/usage/ios-setup#linking-apns-with-fcm ?

@Ehesp I've followed all steps except linking uploading the APNS auth key to FCM (since we send messages directly). I'm also only testing foreground messages. Would I still need to upload the auth key to FCM?

Interesting, when the device is in the foreground a direct websocket connection is used between the device and fcm rather than going via apns.

I'm not 100% sure how that works with apns... Maybe a method is missing from the delegate, I'd have to investigate.

@Ehesp ah didn't realize FCM used its own socket in the foreground on ios. I guess we need the onMessage callback to be invoked from something along the lines of this code block from the official docs:

func userNotificationCenter(_ center: UNUserNotificationCenter,
         willPresent notification: UNNotification,
         withCompletionHandler completionHandler: 
            @escaping (UNNotificationPresentationOptions) -> Void) {
    // pass to onMessage here
}

@Ehesp I just looked through the source code, and I'm guessing it doesn't work because the code seems to check for a gcm id before processing:

if (notification.request.content.userInfo[@"gcm.message_id"]) {

Hi, my iOS background notification is working well, but in foreground received notification, but failed to display it. Now using react-native-push-notification to display local notification.

 PushNotification.localNotification({
      title: title,
      message: body,
      bigText: body,
    });

"@react-native-firebase/app": "^6.4.0",
"@react-native-firebase/messaging": "^6.4.0",

@Ehesp just wanted to follow up to see if you think this will be solved / supported in the near future?

I'm not sure it should be really, the Messaging module should only interact with FCM messages otherwise it would absorb everything.

That being said, you should be able to put in your own handler into the AppDelegate file which should handle APNs messages & also FCM messages.

Thanks @Ehesp, that makes sense! Wanted to see if I understood correctly -- if there are two different handlers, is it safe to assume that they will both be invoked by incoming notifications?

Yeah this is the overall issue we've been having on iOS, if a user puts something in their AppDelegate, iOS only calls that and not any internal library ones.

We have implemented Swizzling to get around that, so it should work!

Awesome, thanks for clarifying :)

Was this page helpful?
0 / 5 - 0 ratings