7

I have created a push notification using react-native Firebase and react-native-push-notification. i have implement all types of notifications like local, schedule background and quit. But i have sent the push notification by FCM when my app in quit state. so i have shown an warning on console which is WARN No task registered for key ReactNativeFirebaseMessagingHeadlessTask. so how can i solve it.

code:

import React, {Fragment, useEffect} from 'react';
import {StyleSheet, View, Text, Button} from 'react-native';
import PushNotification from 'react-native-push-notification';

import messaging from '@react-native-firebase/messaging';

//1
const checkPermission = () => {
  messaging()
    .hasPermission()
    .then((enabled) => {
      if (enabled) {
        getToken();
      } else {
        requestPermission();
      }
    })
    .catch((error) => {
      console.log('error checking permisions ' + error);
    });
};

//2
const requestPermission = () => {
  messaging()
    .requestPermission()
    .then(() => {
      getToken();
    })
    .catch((error) => {
      console.log('permission rejected ' + error);
    });
};

//3
const getToken = () => {
  messaging()
    .getToken()
    .then((token) => {
      console.log('push token ' + token);
    })
    .catch((error) => {
      console.log('error getting push token ' + error);
    });
};

const NotificationTwo = () => {
  useEffect(() => {
    checkPermission();
    messaging().setBackgroundMessageHandler(async (remoteMessage) => {
      console.log('Message handled in the background!', remoteMessage);
    });
  });
  const calledLocalNotify = () => {
    PushNotification.localNotification({
      /* Android Only Properties */
      title: 'Hello world Local Notify', // (optional)
      message: 'Successfully!, Implement the Local Notifications', // (required)
    });
  };

  const calledLocalScheduleNotify = () => {
    PushNotification.localNotificationSchedule({
      //... You can use all the options from localNotifications
      message: 'Successfully!, Implement the Local Schedule Notifications', // (required)
      date: new Date(Date.now() + 60 * 1000), // in 60 secs
      allowWhileIdle: false, // (optional) set notification to work while on doze, default: false
    });
  };
  return (
    <View style={styles.container}>
      <Text>Push Notification</Text>
      <View style={styles.button}>
        <Button
          color="green"
          title="Local Notification"
          onPress={calledLocalNotify}
        />
      </View>
      <View style={styles.button}>
        <Button
          color="purple"
          title="Local Schedule Notification"
          onPress={calledLocalScheduleNotify}
        />
      </View>
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
  },
  button: {
    margin: 10,
  },
});

export default NotificationTwo;
Alex Chebotarsky
  • 481
  • 5
  • 19
vjtechno
  • 452
  • 1
  • 6
  • 16

4 Answers4

11

When the application is in a background or quit state, the onMessage handler will not be called when receiving messages. Instead, you need to setup a background callback handler via the setBackgroundMessageHandler method.

To setup a background handler, call the setBackgroundMessageHandler outside of your application logic as early as possible.

Although the library supports handling messages in background/quit states, the underlying implementation on how this works is different on Android & iOS.

On Android, a Headless JS task (an Android only feature) is created that runs separately to your main React component; allowing your background handler code to run without mounting your root component.

On iOS however, when a message is received the device silently starts your application in a background state. At this point, your background handler (via setBackgroundMessageHandler) is triggered, but your root React component also gets mounted. This can be problematic for some users since any side-effects will be called inside of your app (e.g. useEffects, analytics events/triggers etc). To get around this problem, you can configure your AppDelegate.m file (see instructions below) to inject a isHeadless prop into your root component. Use this property to conditionally render null ("nothing") if your app is launched in the background:

Try this on your index.js file in app root folder.

// index.js
import { AppRegistry } from 'react-native';
import messaging from '@react-native-firebase/messaging';

messaging().setBackgroundMessageHandler(async (remoteMessage) => {
  console.log('Message handled in the background!', remoteMessage);
});

function HeadlessCheck({ isHeadless }) {
  if (isHeadless) {
    // App has been launched in the background by iOS, ignore
    return null;
  }

  return <App />;
}

function App() {
  // Your application
}

AppRegistry.registerComponent('app', () => HeadlessCheck);

source

Alex Chebotarsky
  • 481
  • 5
  • 19
lonecruisader
  • 408
  • 5
  • 13
2

A complete workaround.

Add these lines in your /android/app/src/main/AndroidManifest.xml and /android/app/src/debug/AndroidManifest.xml Files

    ...
    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
    <uses-permission android:name="android.permission.VIBRATE"/>
    <uses-permission android:name="android.permission.WAKE_LOCK"/>
    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
     ....
    <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">
     ....
      <service android:name="com.emekalites.react.alarm.notification.ANService" android:enabled="true"/>
      <receiver android:name="com.emekalites.react.alarm.notification.ANAlarmReceiver" android:enabled="true"/>
      <receiver android:name="com.emekalites.react.alarm.notification.ANBootReceiver" android:enabled="true" android:exported="true">
          <intent-filter>
              <action android:name="android.intent.action.BOOT_COMPLETED"/>
              <action android:name="android.intent.action.QUICKBOOT_POWERON"/>
              <action android:name="com.htc.intent.action.QUICKBOOT_POWERON"/>
          </intent-filter>
      </receiver>
      ...
    </application>
    ....
</manifest>

Now if you're using FCM to trigger your Notification then follow these steps:

import React from 'react';
import ReactNativeAN from 'react-native-alarm-notification';
import {AppRegistry} from 'react-native';
import messaging from '@react-native-firebase/messaging';

messaging().setBackgroundMessageHandler(async remoteMessage => {
  const alarmNotifData = {
    title: 'My Notification Title',
    message: 'My Notification Message',
    channel: 'my_channel_id',
    small_icon: 'ic_launcher',
  };
  // trigger the alarm
  ReactNativeAN.sendNotification(alarmNotifData);
});

function HeadlessCheck({isHeadless}) {
  if (isHeadless) {
    // App has been launched in the background by iOS, ignore
    return null;
  }
  return <App />;
}

export default function App() {
  return (
      // your rest of the project
  );
}
AppRegistry.registerComponent('app', () => HeadlessCheck);

This code will work like a charm in every condition (App minimized, closed, phone locked etc). Now to stop the alarm.. you need to come with your own approach. But here are some useful function.

 ReactNativeAN.removeAllFiredNotifications();
 ReactNativeAN.stopAlarmSound();
 ReactNativeAN.deleteAlarm(alarmId);

Enjoy!! ✨

kartik tyagi
  • 6,256
  • 2
  • 14
  • 31
  • in which docs one can found this requirements – CodeBy Mar 17 '22 at 16:18
  • there is no particular docs which references this requirements. But if you're familiar with native App code, then this is quite a bit of hack. – kartik tyagi Mar 18 '22 at 17:59
  • @CodeBy, you can find the docs here: https://rnfirebase.io/messaging/usage. Also, after installing the library ( '@react-native-firebase/messaging), when you call it via messaging().setBackgroundMessageHandler(), press ctrl +click on the method (.setBackgroundMessaheHandler), you will be redirected to the inbuilt api docs/guides for this method, in you node_modules. As a rule, most good code owners will add code guides to their installed libraries – Okpo Sep 26 '22 at 11:59
0

This answer helped me. Basically edit your './index.js' to include the following.

import {AppRegistry} from 'react-native';
import messaging from '@react-native-firebase/messaging';

import App from './App';
import {name as appName} from './app.json';

// Kill state Notification Listener.
messaging().setBackgroundMessageHandler(async remoteMessage => {
  // Your code to handle notifications in killed state. For example
  console.log('Killed state notification.', remoteMessage)
});

AppRegistry.registerComponent(appName, () => App);
Manil Malla
  • 133
  • 8
0

For me this worked

/**
 * @format
 */

import {AppRegistry} from 'react-native';
import App from './App';
import messaging from '@react-native-firebase/messaging';
import {name as appName} from './app.json';

// Register background handler
messaging().setBackgroundMessageHandler(async remoteMessage => {
  console.log('Message handled in the background!', remoteMessage);
});

//KillState

messaging().getInitialNotification(async remoteMessage => {
  console.log('Message handled in the background!', remoteMessage);
});

AppRegistry.registerComponent(appName, () => App);

Also note before using messaging().getInitialNotification() :

* Beware of this [issue](https://github.com/invertase/react-native-firebase/issues/3469#issuecomment-660121376) when integrating with splash screen modules. If you are using
 * `react-native-splash-screen` we strongly recommend you migrate to `react-native-bootsplash`
Atul Tiwaree
  • 27
  • 1
  • 5