Closed 7patricia closed 4 years ago
Hi there! I think this has all the information I'd expect - and even had the syntax highlighting, thank you. I can't see anything obvious unfortunately. One tiny thing (0-1% chance it will actually change anything) is that firebase ios sdk is at 6.14.0 now.
The notification handler in case getInitialNotification has a notification was omitted so I'm not sure what it's doing but I'll trust it's successfully differentiating between success and failure
Seems like you could just include the messaging pod vs chaining it as a dependency for the notification pod, but I'm not the best at iOS dev so I'm not certain there
One question - is this a remote cloud message with a notification payload that generates the notification, or is it a notification you generate in your app? It might be useful to show the actual JSON you post to the server via a script? At the very least it will make testing it for you even easier
I have a script that posts JSON totally different from what you want but looks like this, for reference, and I can then see what JSON is being sent to the mobile app:
(base) mike@kunashir:~/work/Kullki/ksocialscore/packages (onboarding) % cat public-app/publish/test-silent-push.sh
#!/bin/bash
PROD_SERVER_KEY="<SERVER KEY FROM THE FIREBASE CONSOLE HERE, OMITTED>"
#SERVER_KEY=$DEV_SERVER_KEY
SERVER_KEY=$PROD_SERVER_KEY
curl -X POST \
--header "Authorization: key=$SERVER_KEY" \
--Header "Content-Type: application/json" https://fcm.googleapis.com/fcm/send -d "{\"to\":\"/topics/AppInfo\",\"collapse_key\": \"AppInfo\",\"content_available\": true, \"priority\": \"high\", \"data\":{\"IconCheck\":\"Testing Icon\"}}"
My only solid troubleshooting tip is that the docs don't indicate your code:
if ([FIRApp defaultApp] == nil) {
[FIRApp configure];
}
if (launchOptions) { //launchOptions is not nil
NSDictionary *userInfo = [launchOptions valueForKey:UIApplicationLaunchOptionsRemoteNotificationKey];
NSDictionary *apsInfo = [userInfo objectForKey:@"aps"];
if (apsInfo) { //apsInfo is not nil
NSLog(@"apsInfo %@", apsInfo);
[[RNFirebaseNotifications instance] didReceiveRemoteNotification:userInfo fetchCompletionHandler:nil];
}
}
[RNFirebaseNotifications configure];
they prescribe:
[FIRApp configure];
[RNFirebaseNotifications configure];
...and nothing else. All the other stuff looks well thought out, so I don't submit this as a possible fix, but what happens if you remove everything except the two lines for configure?
@mikehardy Thanks for the quick response!
I edited the issue adding the information about the type of messages I am sending, and also the missing notification handler.
but what happens if you remove everything except the two lines for configure?
I just tested this and the problem still persists. I also updated Firebase sdk to 6.14.0
:thinking: sorry none of that seemed to positively affect it. I'm afraid I don't have any great ideas, but to me this seems like the consequence of mixing data messages (which would otherwise be "messaging" module and known as silent-push) and notification messages
I use a different design where I send data-only messages 100% of the time from firebase, then in my handler I do the necessary local notification API calls to display and handle notifications.
This still may not be on target, but with a data-only style you could put the data you want into async-storage then pop the local notification, and if the user clicks it when the app launches you could check async-storage to see if there is anything important in there.
This is also potentially important because in the case where the user sees the app notification but for some reason clicks the app icon instead of the notification, there is no extra data passed either - https://stackoverflow.com/a/12202161/9910298 - an edge case but something to think about maybe
Thinking even a bit further (I looked into this more because it will affect my work project as well) - if you rely on data-only messages from FCM then then in the case the user has force-closed the app, the message won't be delivered until the app is reopened, which is undesirable: https://facebook.github.io/react-native/docs/pushnotificationios#getdata
The solution to that according to the internet ifor iOS is to not use FCM but to use APNS directly - per https://facebook.github.io/react-native/docs/pushnotificationios#getdata - with the apn module https://www.npmjs.com/package/apn - so you the device will definitely get silent-push notifications
This all may be totally off target but then I'd do:
Then it should handle all app states, including if the user opens via app icon or not, with data always available via either server-fetch on startup or async-storage
But that does all seem terribly complicated. Unfortunately that's my typical experience with mobile messaging :man_shrugging:
Sooo... after hours and hours of trying to fixing it, trying to send different payloads on the notification, debugging... Turns out it just doesn't work when you have your app in debug mode (which I always had) for some reason. 🤷♀ Thank you @mikehardy for your help, hope this helps others that might face the same issue.
oh my that isn't what I was thinking at all. Can anyone else verify this (I'll try myself as well). If this is the case a PR to the docs (there's an edit button on the top right of each page) might save lots of others the pain
@7patricia @mikehardy can confirm that this happens during 'debug' mode
Thanks for confirming @mstankov I will PR docs now. @7patricia great work isolating this, sorry it burnt a lot of your time
Any comments / suggestions / other places it should be welcome on https://github.com/invertase/react-native-firebase-docs/pull/246
Going to close this as with v5.x.x in maintenance mode a documentation fix is worth more to me (for stability) than code change as long as it's clear (and I think it is?)
Hello, With my first experience on React Native app development (iOS/Android), integrate PushNotification seems to be difficult because some concepts have to be understood but simple in reality. After some troubles using Firebase to send PushNotifications (alerts in my case, not silents), everything works fine with Android, but nothing received on iOS, and after reading lots of @mikehardy answers (special thanks Mike !), I've decided to not use Firebase for iOS and directly send request to APNs to deliver my PushNotifications on iOS. Using react-native-push-notification and @react-native-community/push-notification-ios plugins, everything works fine. PN events are catched by onNotification function. One point of attention, on iOS, when user is using app when a PN is received (foreground mode), nothing is shown on iPhone (tested on iOS 13.3.1). So you just have to catch this event in onNotification method and display yourself this notification in your app. Note : react-native-push-notification and @react-native-community/push-notification-ios generate DEVICE_TOKEN (not FCM_TOKEN (which is generated by react-native-firebase plugin)), it's ok between Android <-> Firebase and ok between iOS <-> APNs, nothing else. Note 2 : sorry for my poor english I hope it helps,
Hey there @seb-montana - thanks for posting up what worked for you. Just to be clear, since my most recent messages involving messaging and silent push to iOS involved a theory - but no proof - that in the "iOS app was force-closed, then you send a silent message to it" case, the app successfully woke up after receiving a direct-to-APNS silent message and called your onNotification, allowing you to show a local notification (or similar)? That is the one case where - if I understand correctly - FCM simply does not handle things. Hearing a positive confirmation of someone that tested it and it works would help me and others. Thanks!
@mikehardy indeed it would! @seb-montana your english is perfectly fine. Please confirm whether a direct APNS notification (silent, ak.a. data-only) wakes up the device while the app is killed (dead), it would be of great help :)
I've just tried to send silent notification directly using APNs (apns doc). Nothing received on my app when is in background or killed. I only receive notification on foreground mode. My app use react-native-push-notification and @react-native-community/push-notification-ios
Maybe try this plugin : react-native-notifications I realise my configuration is out of this topic based on Firebase.
Hm - based on this tutorial I would expect your iOS remote notification handler to receive the push assuming background notifications are enabled and you set content_available to 1 https://www.raywenderlich.com/8164-push-notifications-tutorial-getting-started.
Your configuration is only sort-of off-topic, as the current understanding (which we're looking to confirm) is that FCM has a specific gap on iOS and we're looking for how to recommend people handle it. So I'm interested at least :-)
Further research (I do a bit more every time this discussion perks up) indicates it app force-close on Apple may simply be impossible:
However, the system does not automatically launch your app if the user has force-quit it. In that situation, the user must relaunch your app or restart the device before the system attempts to launch your app automatically again.
https://developer.apple.com/documentation/uikit/uiapplicationdelegate/1623013-application
If that's the case then I would expect FCM silent push messages to be as robust as any solution if the capabilities, permissions, app listener registration, token handling and message JSON are all lined up correctly, and the app is in any state except force-closed.
I'had missed one header in my configuration of my APNs post request, so after add "apns-priority: 5" (in addition to "apns-push-type: background" and "apns-expiration: 0") based on this reply => my app receives notification when it is in background mode. => my app receives notification when it is killed too and app is launched in background by the system without user interaction. So is it ok ?
I'had missed one header in my configuration of my APNs post request, so after add "apns-priority: 5" (in addition to "apns-push-type: background" and "apns-expiration: 0") based on this reply => my app receives notification when it is in background mode. => my app receives notification when it is killed too and app is launched in background by the system without user interaction. So is it ok ?
Yup, this is great! Thank you!
very interesting! perhaps that's why FCM->APNS->Device has a problem vs APNS->Device, I know FCM->APNS translates 'content_available' to 'content-available' but I'm not sure it lets the 'apns-push-type' and 'apns-expiration' stuff through. This seems like the key to the puzzle, thanks again for reporting back @seb-montana - @mstankov have you now tested this and you are saying it works for you as well? Can anyone post the complete JSON they send to APNS plus some simple test script (like using curl or similar) that shows how to post it to the APNS server? I'd love to test it myself but have never posted to anything but FCM
that's my shell script (using .pem file - if you prefer use .p8 key, combine this script with this resource) :
shell-apns-send-silent-notification-pem.sh.txt
About headers
@seb-montana a pile of internet points for you 😄 🏅 - thank you for those!
Issue
Hi! I am having a problem with the
notifications
library. I need to get the notification data in order to open my application in a specific page. Everything is working fine in Android for every app state, but in iOS, when the app is closed and I click the notification,getInitialNotification
method is not returning notification data. It is triggered, but the value isundefined
. When the app is in foreground or background everything is ok.I'm sending remote cloud notifications that look like this:
Any ideas on what it might be?
I'm using v5.6.0, but I forked it and done some changes:
P.S: I didn't fill out the Android project files part of the issues since my problem is only in iOS, but please let me know if that would be helpful.
Project Files
Javascript
Click To Expand
#### `package.json`: ```json { "name": "myPackageName", "version": "1.0.0", "private": true, "description": "My app", "author": "My app", "main": "index.js", "dependencies": { (...) "react-native": "0.61.5", "react-native-firebase": "git+ssh://git@github.com/my-org/react-native-firebase#mybranch", (...) }, "devDependencies": { "@babel/core": "7.6.2", "@babel/runtime": "7.6.2", "babel-core": "7.0.0-bridge.0", "babel-jest": "24.9.0", "chai": "4.2.0", "detox": "14.0.3", "eslint-plugin-detox": "1.0.0", "jest": "24.9.0", "mailosaur": "5.0.8", "react-devtools-core": "3.4.3", "react-test-renderer": "16.9.0", "reactotron-react-native": "2.0.0", "relay-compiler": "1.6.2", "stylelint": "10.1.0" }, "resolutions": { "react-devtools-core": "3.4.3" }, "rnpm": { "assets": [ "./src/lib/assets/fonts" ] }, "detox": { "configurations": { "android": { "binaryPath": "android/app/build/outputs/apk/debug/app-debug.apk", "build": "pushd android && ./gradlew assembleDebug assembleAndroidTest -DtestBuildType=debug && popd", "name": "device", "session": { "sessionId": "manualsession", "server": "ws://localhost:8099" }, "type": "android.emulator" }, "ios": { "binaryPath": "ios/build/Build/Products/Debug-iphonesimulator/MyApp.app", "build": "xcodebuild -workspace ios/Wallet.xcworkspace -UseNewBuildSystem=NO -scheme Wallet -configuration Debug -sdk iphonesimulator -derivedDataPath ios/build ", "name": "iPhone 8", "type": "ios.simulator" } }, "test-runner": "jest" } } ``` ### `index.js` ```json export class Application extends Component { constructor(props) { super(props); } componentDidMount() { this.removeNotificationListener = firebase.notifications().onNotification(received => { if (received && get(received, '_data.displayInForeground') !== 'false') { const notification = new firebase.notifications.Notification() .setBody(get(received, '_body')) .setData(get(received, '_data')) .setNotificationId(get(received, '_notificationId')) .setTitle(get(received, '_title')); if (Platform.OS === 'android') { const channel = new firebase.notifications.Android.Channel( 'my-channel', 'My Channel', firebase.notifications.Android.Importance.Max ).setDescription('My notifications channel'); firebase.notifications().android.createChannel(channel); notification.android.setColor(styles.colors.p06); notification.android.setChannelId('my-channel'); notification.android.setPriority(firebase.notifications.Android.Priority.Max); notification.android.setSmallIcon('ic_notifications'); } firebase.notifications().displayNotification(notification); } }); this.removeNotificationOpenedListener = firebase.notifications().onNotificationOpened(notification => { this.handleNotificationOpened(notification); }); firebase .notifications() .getInitialNotification() .then(notification => { if (notification) { this.handleNotificationOpened(notification); } }); } componentWillUnmount() { this.removeNotificationOpenedListener(); this.removeNotificationListener(); } handleNotificationOpened(notification) { if (notification && get(notification, 'notification._data.url')) { this.setUser({ notification }); if (PlatformUtils.isIOS) { const navigation = get(NavigatorInstance.navigator, '_navigation'); Navigation.navigate(navigation, 'splash'); } } } } ``` #### `firebase.json` for react-native-firebase v6: ```json # N/A ``` ### iOS
---
### Android
---
## Environment
---
Think `react-native-firebase` is great? Please consider supporting all of the project maintainers and contributors by donating via our [Open Collective](https://opencollective.com/react-native-firebase/donate) where all contributors can submit expenses. [[Learn More]](https://invertase.io/oss/react-native-firebase/contributing/donations-expenses)
- 👉 Check out [`React Native Firebase`](https://twitter.com/rnfirebase) and [`Invertase`](https://twitter.com/invertaseio) on Twitter for updates on the library.
Click To Expand
#### `ios/Podfile`: - [ ] I'm not using Pods - [x] I'm using Pods and my Podfile looks like: ```json platform :ios, '9.0' require_relative '../node_modules/@react-native-community/cli-platform-ios/native_modules' source 'https://github.com/CocoaPods/Specs.git' use_frameworks! target "Wallet" do pod 'JumioMobileSDK/Netverify', '3.3.1' # Required by react native. pod 'DoubleConversion', :podspec => '../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec' pod 'FBLazyVector', :path => "../node_modules/react-native/Libraries/FBLazyVector" pod 'FBReactNativeSpec', :path => "../node_modules/react-native/Libraries/FBReactNativeSpec" pod 'Firebase/Core', '~> 6.13.0' pod 'Firebase/Messaging', '~> 6.13.0' pod 'Folly', :podspec => '../node_modules/react-native/third-party-podspecs/Folly.podspec' pod 'glog', :podspec => '../node_modules/react-native/third-party-podspecs/glog.podspec' pod 'RCTRequired', :path => "../node_modules/react-native/Libraries/RCTRequired" pod 'RCTTypeSafety', :path => "../node_modules/react-native/Libraries/TypeSafety" pod 'React-Core', :path => '../node_modules/react-native/' pod 'React-Core/DevSupport', :path => '../node_modules/react-native/' pod 'React-Core/RCTWebSocket', :path => '../node_modules/react-native/' pod 'React-CoreModules', :path => '../node_modules/react-native/React/CoreModules' 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 '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', :path => '../node_modules/react-native/' 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' end post_install do |installer| rnfirebase = installer.pods_project.targets.find { |target| target.name == 'RNFirebase' } rnfirebase.build_configurations.each do |config| config.build_settings['HEADER_SEARCH_PATHS'] = '$(inherited) ${PODS_ROOT}/Headers/Public/**' end end use_native_modules! ``` ```ruby # N/A ``` #### `AppDelegate.m`: ```objc /** * Copyright (c) 2015-present, Facebook, Inc. * All rights reserved. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. */ #import "AppDelegate.h" #import
#import
#import
#import
#import
#import "RNSplashScreen.h"
#import "RNFirebaseNotifications.h"
#import "RNFirebaseMessaging.h"
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url
sourceApplication:(NSString *)sourceApplication annotation:(id)annotation
{
return [RCTLinkingManager application:application openURL:url
sourceApplication:sourceApplication annotation:annotation];
}
- (void)applicationWillEnterForeground:(UIApplication *)application
{
[[self.window.rootViewController.view viewWithTag:999] removeFromSuperview];
}
// Only if your app is using [Universal Links](https://developer.apple.com/library/prerelease/ios/documentation/General/Conceptual/AppSearch/UniversalLinks.html).
- (BOOL)application:(UIApplication *)application continueUserActivity:(NSUserActivity *)userActivity
restorationHandler:(void (^)(NSArray * _Nullable))restorationHandler
{
return [RCTLinkingManager application:application
continueUserActivity:userActivity
restorationHandler:restorationHandler];
}
- (void)applicationDidEnterBackground:(UIApplication *)application
{
UIBlurEffect *effect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleRegular];
UIVisualEffectView *bluredView = [[UIVisualEffectView alloc] initWithEffect:effect];
bluredView.frame = self.window.rootViewController.view.bounds;
bluredView.tag = 999;
[self.window.rootViewController.view addSubview:bluredView];
}
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
if ([FIRApp defaultApp] == nil) {
[FIRApp configure];
}
if (launchOptions) { //launchOptions is not nil
NSDictionary *userInfo = [launchOptions valueForKey:UIApplicationLaunchOptionsRemoteNotificationKey];
NSDictionary *apsInfo = [userInfo objectForKey:@"aps"];
if (apsInfo) { //apsInfo is not nil
NSLog(@"apsInfo %@", apsInfo);
[[RNFirebaseNotifications instance] didReceiveRemoteNotification:userInfo fetchCompletionHandler:nil];
}
}
[RNFirebaseNotifications configure];
RCTBridge *bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:launchOptions];
RCTRootView *rootView = [[RCTRootView alloc] initWithBridge:bridge moduleName:@"Wallet" initialProperties:nil];
rootView.backgroundColor = [UIColor blackColor];
self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
if (@available(iOS 13.0, *)) {
self.window.overrideUserInterfaceStyle = UIUserInterfaceStyleLight;
}
UIViewController *rootViewController = [UIViewController new];
rootViewController.view = rootView;
self.window.rootViewController = rootViewController;
[self.window makeKeyAndVisible];
// [RNSplashScreen show];
[RNSplashScreen showSplash:@"LaunchScreen" inRootView:rootView];
UNUserNotificationCenter.currentNotificationCenter.delegate = self;
[UIApplication sharedApplication].applicationIconBadgeNumber = 0;
return YES;
}
- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification {
[[RNFirebaseNotifications instance] didReceiveLocalNotification:notification];
}
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(nonnull NSDictionary *)userInfo
fetchCompletionHandler:(nonnull void (^)(UIBackgroundFetchResult))completionHandler{
[[RNFirebaseNotifications instance] didReceiveRemoteNotification:userInfo fetchCompletionHandler:completionHandler];
}
- (void)application:(UIApplication *)application didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings {
[[RNFirebaseMessaging instance] didRegisterUserNotificationSettings:notificationSettings];
}
- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge
{
#if DEBUG
return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index" fallbackResource:nil];
#else
return [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];
#endif
}
- (void)userNotificationCenter:(UNUserNotificationCenter* )center willPresentNotification:(UNNotification* )notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler {
completionHandler(UNNotificationPresentationOptionAlert);
}
@end
```
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? - [X] I am using the NPM package `jetifier` for react-native compatibility? #### `android/build.gradle`: ```groovy // N/A ``` #### `android/app/build.gradle`: ```groovy // N/A ``` #### `android/settings.gradle`: ```groovy // N/A ``` #### `MainApplication.java`: ```java // N/A ``` #### `AndroidManifest.xml`: ```xml ```
Click To Expand
**`react-native info` output:** ``` warn Your project is using deprecated "rnpm" config that will stop working from next release. Please use a "react-native.config.js" file to configure the React Native CLI. Migration guide: https://github.com/react-native-community/cli/blob/master/docs/configuration.md warn The following packages use deprecated "rnpm" config that will stop working from next release: - react-native-sentry: https://github.com/getsentry/react-native-sentry Please notify their maintainers about it. You can find more details at https://github.com/react-native-community/cli/blob/master/docs/configuration.md#migration-guide. info Fetching system and libraries information... System: OS: macOS 10.15.2 CPU: (12) x64 Intel(R) Core(TM) i7-9750H CPU @ 2.60GHz Memory: 55.24 MB / 32.00 GB Shell: 5.7.1 - /bin/zsh Binaries: Node: 10.17.0 - /usr/local/opt/node@10/bin/node Yarn: 1.21.0 - /usr/local/bin/yarn npm: 6.11.3 - /usr/local/opt/node@10/bin/npm SDKs: iOS SDK: Platforms: iOS 13.2, DriverKit 19.0, macOS 10.15, tvOS 13.2, watchOS 6.1 Android SDK: API Levels: 28, 29 Build Tools: 28.0.3, 29.0.2 IDEs: Android Studio: 3.5 AI-191.8026.42.35.6010548 Xcode: 11.3/11C29 - /usr/bin/xcodebuild npmPackages: react: 16.9.0 => 16.9.0 react-native: 0.61.5 => 0.61.5 ``` - **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:** - `v5.6.0` - **`Firebase` module(s) you're using that has the issue:** - `Notifications` - **Are you using `TypeScript`?** - `N`