This is a similar issue to this one: https://github.com/invertase/react-native-firebase/issues/4005. However, I don't use react-native-bootsplash or react-native-splash-screen. I use firebase together with react-native-push-notification
I register callbacks on onNotificationOpenedApp and getInitialNotification. However, when I open the app from push notification, callbacks are never called.
I also register onMessage and setBackgroundMessageHandler. They work.
messaging().setBackgroundMessageHandler(remoteMessage => {
return new Promise((resolve, reject) => {
if (isAndroid()) {
console.log('handle');
NotificationService.handleNotification(remoteMessage, resolve);
} else {
resolve();
}
});
});
messaging().onNotificationOpenedApp(remoteMessage => {
console.log(
'Notification caused app to open from background state:',
remoteMessage,
);
});
messaging().onMessage(m => console.log('onMessage'));
messaging()
.getInitialNotification()
.then(remoteMessage => {
if (remoteMessage) {
console.log(
'Notification caused app to open from quit state:',
remoteMessage,
);
}
});
Click To Expand
#### `package.json`:
{
"name": "some_app",
"version": "5.2.2",
"private": true,
"scripts": {
"postinstall": "patch-package && npx jetify && cd ./node_modules/@twipemobilesolutions/twipe-app-react-native-iap && npm install && npm run build",
"start": "react-native start",
"run:android": "react-native run-android",
"run:ios": "react-native run-ios",
"lint": "tslint --project .",
"lint:fix": "yarn lint --fix",
"storybook": "start-storybook --config-dir ./src/components/storybook -p 7007",
"storybook:android": "yarn storybook & ENVFILE=./src/components/storybook/storybook.env react-native run-android",
"storybook:ios": "yarn storybook & ENVFILE=./src/components/storybook/storybook.env react-native run-ios",
"test": "TZ=UTC jest",
"test:win": "test.cmd",
"tmg-ttg-ios": "yarn install && cd ios && pod install && cd .. && scripts/run.sh ios tmg ttg",
"tmg-ttg-android": "yarn install && scripts/run.sh android tmg ttg"
},
"dependencies": {
"@react-native-community/async-storage": "^1.6.2",
"@react-native-community/netinfo": "^4.1.1",
"@react-native-community/push-notification-ios": "1.2.0",
"@react-native-community/slider": "2.0.7",
"@react-native-firebase/analytics": "7.6.8",
"@react-native-firebase/app": "8.4.6",
"@react-native-firebase/crashlytics": "8.4.11",
"@react-native-firebase/messaging": "7.9.1",
"@twipemobilesolutions/twipe-app-background": "git+ssh://[email protected]/twipemobilesolutions/twipe-app-background.git#1.1.3",
"@twipemobilesolutions/twipe-app-react-native-iap": "git+ssh://[email protected]/twipemobilesolutions/twipe-app-react-native-iap.git#f438d6d219c728a4f1cde43180c46772ea359faa",
"@twipemobilesolutions/twipe-app-rn-fetch-blob": "git+ssh://[email protected]/twipemobilesolutions/twipe-app-rn-fetch-blob.git#f62b61bdbb72605700a2ed87ec3c0ffd8a11c2fe",
"@types/react-native-mail": "^3.0.0",
"@types/react-native-push-notification": "^3.0.7",
"@types/sinon": "^7.0.13",
"axios": "0.18.1",
"axios-auth-refresh": "^1.0.7",
"axios-retry": "^3.1.2",
"babel-plugin-idx": "^2.4.0",
"date-fns": "^2.7.0",
"date-fns-tz": "^1.0.10",
"deep-object-diff": "^1.1.0",
"filesize": "^5.0.3",
"humps": "^2.0.1",
"i18n-js": "^3.3.0",
"idx": "^2.5.6",
"iso8601-duration": "^1.2.0",
"lodash": "^4.17.11",
"patch-package": "^6.1.2",
"postinstall-postinstall": "^2.0.0",
"react": "16.8.6",
"react-native": "0.60.0",
"react-native-background-fetch": "^2.7.1",
"react-native-config": "^0.11.7",
"react-native-device-info": "^5.3.1",
"react-native-exception-handler": "^2.10.8",
"react-native-fs": "2.15.2",
"react-native-gesture-handler": "^1.5.0",
"react-native-get-random-values": "^1.4.0",
"react-native-image-zoom-viewer": "^2.2.26",
"react-native-inappbrowser-reborn": "^3.0.0",
"react-native-inset-shadow": "^1.0.2",
"react-native-keyboard-aware-scroll-view": "^0.9.1",
"react-native-localize": "^1.1.4",
"react-native-mail": "^4.1.0",
"react-native-material-textfield": "^0.16.1",
"react-native-orientation-locker": "^1.1.6",
"react-native-progress": "^3.6.0",
"react-native-push-notification": "^3.1.9",
"react-native-rate": "^1.1.10",
"react-native-safe-area-context": "^3.1.8",
"react-native-safe-area-view": "^2.0.0",
"react-native-svg": "^9.8.4",
"react-native-swiper": "^1.5.14",
"react-native-webview": "^10.10.2",
"react-native-zip-archive": "^5.0.1",
"react-navigation": "^4.0.10",
"react-navigation-stack": "^1.7.3",
"react-redux": "^7.1.0",
"recyclerlistview": "^2.0.12",
"redux": "^4.0.2",
"redux-act": "^1.7.7",
"redux-devtools-extension": "^2.13.8",
"redux-persist": "^5.10.0",
"redux-persist-filesystem-storage": "^2.1.0",
"redux-saga": "^1.0.5",
"reselect": "^4.0.0",
"shallow-equal": "^1.2.0",
"styled-components": "^4.3.2",
"uuid": "^8.1.0",
"yarn": "^1.19.2"
},
"devDependencies": {
"@babel/core": "^7.5.0",
"@babel/runtime": "^7.5.2",
"@react-native-community/cli": "^2.9.0",
"@react-native-community/eslint-config": "^0.0.5",
"@storybook/addon-actions": "^5.1.9",
"@storybook/addon-info": "^5.1.9",
"@storybook/addon-knobs": "^5.1.9",
"@storybook/addon-links": "^5.1.9",
"@storybook/addon-ondevice-knobs": "^5.1.9",
"@storybook/addon-storyshots": "^5.1.9",
"@storybook/addons": "^5.1.9",
"@storybook/react-native": "^5.1.9",
"@storybook/react-native-server": "^5.1.9",
"@types/axios": "^0.14.0",
"@types/humps": "^1.1.2",
"@types/i18n-js": "^3.0.1",
"@types/jest": "^24.0.15",
"@types/lodash": "^4.14.136",
"@types/node": "^12.6.2",
"@types/react": "^16.8.23",
"@types/react-native": "^0.60.0",
"@types/react-native-material-textfield": "^0.16.0",
"@types/react-navigation": "^3.0.7",
"@types/react-redux": "^7.1.1",
"@types/react-test-renderer": "^16.8.2",
"@types/redux-logger": "^3.0.7",
"@types/redux-persist": "^4.3.1",
"@types/rn-fetch-blob": "^1.2.1",
"@types/storybook__addon-knobs": "^5.0.2",
"@types/storybook__addon-storyshots": "^4.0.1",
"@types/storybook__react": "^4.0.2",
"@types/styled-components": "^4.1.16",
"@types/uuid": "^3.4.5",
"@welldone-software/why-did-you-render": "^3.3.8",
"axios-mock-adapter": "^1.17.0",
"babel-jest": "^24.8.0",
"babel-loader": "^8.0.6",
"babel-plugin-transform-remove-console": "^6.9.4",
"eslint": "^6.0.1",
"husky": ">=1",
"jest": "^24.8.0",
"jetifier": "^1.6.1",
"lint-staged": ">=8",
"metro-react-native-babel-preset": "^0.55.0",
"prettier": "1.18.2",
"react-docgen-typescript-loader": "^3.1.0",
"react-dom": "16.8.6",
"react-native-asset": "github://femiveys/react-native-asset.git#d052f2371aa035017379031f7709d4fb5a71cd0f",
"react-storybook-addon-props-combinations": "^1.1.0",
"react-test-renderer": "16.8.6",
"redux-logger": "^3.0.6",
"redux-saga-test-plan": "^4.0.0-rc.3",
"sinon": "^7.3.2",
"ts-jest": "^24.0.2",
"tslint": "^5.18.0",
"tslint-config-prettier": "^1.18.0",
"tslint-config-standard": "^8.0.1",
"tslint-plugin-prettier": "^2.0.1",
"tslint-react": "^4.0.0",
"tslint-react-native": "^0.0.7",
"typescript": "^3.5.3"
},
"resolutions": {
"react-native-safe-area-view": "^2.0.0"
},
"husky": {
"hooks": {
"pre-commit": "lint-staged"
}
},
"lint-staged": {
"*.{ts, tsx, css, json, md}": [
"prettier --write",
"git add"
],
"*.{ts, tsx}": [
"yarn lint --fix",
"git add"
]
}
}
#### `firebase.json` for react-native-firebase v6:
{
"crashlytics_auto_collection_enabled": true,
"crashlytics_debug_enabled": true,
"crashlytics_ndk_enabled": false,
"react-native": {
"messaging_android_headless_task_timeout": 180000
}
}
### Android
#### 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`:
buildscript {
ext {
buildToolsVersion = "28.0.3"
minSdkVersion = 21
compileSdkVersion = 28
targetSdkVersion = 28
supportLibVersion = "28.0.0"
}
repositories {
google()
jcenter()
maven {
url 'https://maven.fabric.io/public'
}
}
dependencies {
classpath("com.android.tools.build:gradle:3.4.1")
classpath 'com.google.gms:google-services:4.2.0'
classpath 'io.fabric.tools:gradle:1.28.1'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
allprojects {
repositories {
mavenLocal()
maven {
// All of React Native (JS, Obj-C sources, Android binaries) is installed from npm
url("$rootDir/../node_modules/react-native/android")
}
maven {
// Android JSC is installed from npm
url("$rootDir/../node_modules/jsc-android/dist")
}
google()
jcenter()
}
}
#### `android/app/build.gradle`:
buildscript {
repositories {
}
dependencies {
}
}
apply plugin: "com.android.application"
apply plugin: 'io.fabric'
repositories {
}
project.ext.envConfigFiles = [
tmgttgdebug: "clients/1/1/client.env",
tmgttgrelease: "clients/1/ttg1client.env",
]
apply from: project(':react-native-config').projectDir.getPath() + "/dotenv.gradle"
import com.android.build.OutputFile
#### `android/settings.gradle`:
rootProject.name = 'some_project'
include ':rn-fetch-blob'
project(':rn-fetch-blob').projectDir = new File(rootProject.projectDir, '../node_modules/rn-fetch-blob/android')
include ':react-native-push-notification'
project(':react-native-push-notification').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-push-notification/android')
include ':react-native-background-fetch'
project(':react-native-background-fetch').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-background-fetch/android')
include ':react-native-orientation-locker'
project(':react-native-orientation-locker').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-orientation-locker/android')
include ':react-native-gesture-handler'
project(':react-native-gesture-handler').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-gesture-handler/android')
include ':react-native-config'
project(':react-native-config').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-config/android')
apply from: file("../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesSettingsGradle(settings)
include ':app'
#### `MainApplication.java`:
package com.some_application;
import android.app.Application;
import android.content.Context;
import androidx.multidex.MultiDex;
import com.facebook.react.PackageList;
import com.facebook.react.ReactApplication;
import com.facebook.react.ReactNativeHost;
import com.facebook.react.ReactPackage;
import com.facebook.soloader.SoLoader;
import java.util.List;
public class MainApplication extends Application implements ReactApplication {
private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) {
@Override
public boolean getUseDeveloperSupport() {
return BuildConfig.DEBUG;
}
@Override
protected List<ReactPackage> getPackages() {
@SuppressWarnings("UnnecessaryLocalVariable")
List<ReactPackage> packages = new PackageList(this).getPackages();
// Packages that cannot be autolinked yet can be added manually here, for example:
// packages.add(new MyReactNativePackage());
return packages;
}
@Override
protected String getJSMainModuleName() {
return "index";
}
};
@Override
public ReactNativeHost getReactNativeHost() {
return mReactNativeHost;
}
@Override
public void onCreate() {
setTheme(R.style.AppTheme);
super.onCreate();
SoLoader.init(this, /* native exopackage */ false);
}
@Override
protected void attachBaseContext(Context context) {
super.attachBaseContext(context);
MultiDex.install(this);
}
}
#### `AndroidManifest.xml`:
<manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" package="com.some_application">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<application
android:name=".MainApplication"
android:label="@string/app_name"
android:icon="@mipmap/ic_launcher"
android:roundIcon="@mipmap/ic_launcher_round"
android:allowBackup="false"
android:theme="@style/AppTheme.Launcher"
android:usesCleartextTraffic="true"
android:hardwareAccelerated="true"
>
<meta-data android:name="com.dieam.reactnativepushnotification.notification_channel_name"
android:value="YOUR NOTIFICATION CHANNEL NAME"/>
<meta-data android:name="com.dieam.reactnativepushnotification.notification_channel_description"
android:value="YOUR NOTIFICATION CHANNEL DESCRIPTION"/>
<!-- Change the resource name to your App's accent color - or any other color you want -->
<meta-data android:name="com.dieam.reactnativepushnotification.notification_color"
android:resource="@android:color/white"/>
<receiver android:name="com.dieam.reactnativepushnotification.modules.RNPushNotificationPublisher" />
<receiver android:name="com.dieam.reactnativepushnotification.modules.RNPushNotificationBootEventReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
<receiver android:name = "com.amazon.device.iap.ResponseReceiver"
android:permission = "com.amazon.inapp.purchasing.Permission.NOTIFY" >
<intent-filter>
<action android:name = "com.amazon.inapp.purchasing.NOTIFY" android:permission = "com.amazon.inapp.purchasing.Permission.NOTIFY"/>
</intent-filter>
</receiver>
<service android:name="com.dieam.reactnativepushnotification.modules.RNPushNotificationRegistrationService"/>
<service
android:name="com.dieam.reactnativepushnotification.modules.RNPushNotificationListenerService"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>
<activity
android:name=".MainActivity"
android:label="@string/app_name"
android:configChanges="keyboard|keyboardHidden|orientation|screenSize"
android:windowSoftInputMode="adjustResize">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name="com.facebook.react.devsupport.DevSettingsActivity" />
</application>
</manifest>
Click To Expand
**`react-native info` output:**
System:
OS: macOS 10.15.7
CPU: (16) x64 Intel(R) Core(TM) i9-9880H CPU @ 2.30GHz
Memory: 1.51 GB / 32.00 GB
Shell: 5.7.1 - /bin/zsh
Binaries:
Node: 12.18.4 - ~/n/bin/node
Yarn: 1.19.2 - ~/Documents/projects/app/node_modules/.bin/yarn
npm: 6.14.6 - ~/n/bin/npm
Watchman: 4.9.0 - /usr/local/bin/watchman
SDKs:
iOS SDK:
Platforms: iOS 14.2, DriverKit 20.0, macOS 11.0, tvOS 14.2, watchOS 7.1
Android SDK:
API Levels: 28, 29, 30
Build Tools: 28.0.3, 29.0.2, 30.0.2
System Images: android-29 | Intel x86 Atom, android-29 | Intel x86 Atom_64, android-29 | Google APIs Intel x86 Atom, android-30 | Google APIs Intel x86 Atom, android-30 | Google Play Intel x86 Atom
IDEs:
Android Studio: 4.1 AI-201.8743.12.41.6858069
Xcode: 12.2/12B45b - /usr/bin/xcodebuild
npmPackages:
@react-native-community/cli: ^2.9.0 => 2.9.0
react: 16.8.6 => 16.8.6
react-native: 0.60.0 => 0.60.0
- **Platform that you're experiencing the issue on**:
- [ ] iOS
- [ ] Android
- [ ] **iOS** but have not tested behavior on Android
- [ x] **Android** but have not tested behavior on iOS
- [ ] Both
- **`react-native-firebase` version you're using that has this issue:**
- 7.9.1
- **`Firebase` module(s) you're using that has the issue:**
- messaging
- **Are you using `TypeScript`?**
- Yes, 3.5.
React Native Firebase and Invertase on Twitter for updates on the library.handlers aren't async?
regardless - why wouldn't you use the notification packages' notification handling? That's what it's for! The notification functionality in this module is the absolute most bare implementation possible and I would expect a full featured local notification package to be far superior. I use notifee hooks for my initial notification work, for instance
@mikehardy Thanks for response. What do you mean by "handlers aren't async"? According to docs we should pass there a function.
you should pass an async function: https://rnfirebase.io/reference/messaging#getInitialNotification
@mikehardy I'm looking at the signature of getInitialNotification:
getInitialNotification(): Promise<RemoteMessage | null>;
You pass nothing to this function. It returns a Promise that resolves with RemoteMessage or null
onNotificationOpenedApp: https://rnfirebase.io/reference/messaging#onNotificationOpenedApp
onNotificationOpenedApp(listener: (message: RemoteMessage) => any): () => void;
You pass as a listener a function (synchronous) that returns any.
The examples from docs about notifications (https://rnfirebase.io/messaging/notifications)
messaging().onNotificationOpenedApp(remoteMessage => {
console.log(
'Notification caused app to open from background state:',
remoteMessage.notification,
);
navigation.navigate(remoteMessage.data.type);
});
// Check whether an initial notification is available
messaging()
.getInitialNotification()
.then(remoteMessage => {
if (remoteMessage) {
console.log(
'Notification caused app to open from quit state:',
remoteMessage.notification,
);
setInitialRoute(remoteMessage.data.type); // e.g. "Settings"
}
setLoading(false);
});
I'm confused why do you suggest passing an async function to getInitialNotification or onNotificationOpenedApp.
Sorry I think I've gotten confused with the various startup hooks (messages, notifications, links)
Here's what I do in a bootstrap sequence prior to registering the root component in AppRegistry
notifee.onForegroundEvent((event: Event) => {
EventStreamService.logEvent('NOTIFICATION_FOREGROUND', UserStore.getUser()?.kullkiId);
console.log('NotificationStore::onForegroundEvent listener', JSON.stringify(event, null, 2));
if (event.type === EventType.PRESS) {
console.log('NotificationStore::onForegroundEvent - notification pressed');
if (event.detail.notification) {
this.handleNotification(event.detail.notification);
}
}
});
notifee
.getInitialNotification()
.then((notification) => {
if (notification !== undefined && notification !== null) {
console.log(
`NotificationStore::startup - notifee initial notification: ${JSON.stringify(
notification,
null,
2
)}`
);
NotificationStore.initialNotification = notification.notification;
this.trigger();
EventStreamService.logEvent('NOTIFICATION_OPEN_INITIAL', UserStore.getUser()?.kullkiId);
}
})
.catch((err) => console.log('NotificationStore::startup - getInitialNotification error', err))
.finally(() => console.log('NotificationStore::startup async link fetch finished.'));
firebase
.messaging()
.onNotificationOpenedApp(async (message: FirebaseMessagingTypes.RemoteMessage) => {
console.log(
`NotificationStore::startup - firebase initial notification: ${JSON.stringify(
message,
null,
2
)}`
);
});
@mikehardy It makes no difference. It can be an async or sync function. In any case, it doesn't work for me.
What I figured out:
onNotificationOpenedApp is registeredonNotificationOpenedApp listener is not calledgetInitialNotification is called with this previous notification