Sending push notifications using Expo in background - react-native

Expo has Notification API for sending push notifications. However, how does sending push notifications work when app is in background? Can they be triggered from server or scheduled in advance?

Sending push notifications is done from your server so you are totally free in sending them whenever you want and schedule jobs to take care of it.
However you won't be able to handle the receiving of the notification on the client if the app is backgrounded and the user has not selected the notification. According to expo documentation:
You cannot handle push notifications in the background. This is a work
in progress.
But if the app is in foreground or the user has selected the notification, then a notification will be passed to the listener in your app.

We can handle push notifications in the background.
For this we have to dismission notification if AppState is 'active' and origin === 'received'.
Here is the full code.
import React from 'react';
import { Text, View, Vibration, AppState } from 'react-native';
import { Notifications } from 'expo';
export default class App extends React.Component {
constructor(props) {
super(props);
this.state = {
notification: {}
}
}
componentDidMount() {
this._notificationSubscription = Notifications.addListener(
this._handleNotification
);
}
_handleNotification = notification => {
if (AppState.currentState == 'active' && notification.origin === 'received') {
Notifications.dismissNotificationAsync(notification.notificationId);
} else {
Vibration.vibrate()
this.setState({ notification: notification });
}
};
render() {
return (
<View><Text>Push Notifications Sample</Text></View>
);
}
}

Related

Is there a way to make api calls and save data to asyncstorage in react native when the app is closed?

So is there a way to run background processes(Make an api call and save data using asyncStorage) once the application has been closed. If there is a way how does one go around the 30 seconds timeout imposed by ios .The app is live on both app store and play store
You can use react-native-background-task
import React from 'react'
import { Text } from 'react-native'
import BackgroundTask from 'react-native-background-task'
BackgroundTask.define(() => {
console.log('Hello from a background task')
BackgroundTask.finish()
})
class MyApp extends React.Component {
componentDidMount() {
BackgroundTask.schedule()
}
render() {
return <Text>Hello world</Text>
}
}

How to give push notification in react-native app when data arrived from native in background?

I send data native android and ıos to react-native. I give PushNotification when data arrived app in foreground. Data also send it from native when app in background. How to give PushNotification when react-native app in backgorund.
import { DeviceEventEmitter } from 'react-native';
import PushNotification from 'react-native-push-notification'
componentWillMount: function() {
DeviceEventEmitter.addListener('customEventName', function (e: Event) {
PushNotification.localNotification({
title: "My Notification Title", // (optional)
message: "My Notification Message", // (required)
});
});
}

Listening to notifications on background and start the app

As documented on react-native-firebase docs(https://rnfirebase.io/docs/v5.x.x/messaging/receiving-messages) we can register an headlessTask and listen to notifications while the application is on the background.
Sadly I haven't found a way of starting the app on foreground once a FCM notification is received on the background mode, is this possible?
Below is the code displayed at react-native-firebase for listening to notifications on the background
bgMessaging.js
// #flow
import firebase from 'react-native-firebase';
// Optional flow type
import type { RemoteMessage } from 'react-native-firebase';
export default async (message: RemoteMessage) => {
// handle your message
return Promise.resolve();
}
//This handler method must return a promise and resolve within 60 seconds.
index.js
import bgMessaging from './src/bgMessaging'; // <-- Import the file you created in (2)
// Current main application
AppRegistry.registerComponent('ReactNativeFirebaseDemo', () => bootstrap);
// New task registration
AppRegistry.registerHeadlessTask('RNFirebaseBackgroundMessage', () => bgMessaging); // <-- Add this line
Any help would be really helpfull
Use the following library to start your app when you receive the notification:
https://github.com/lvlrSajjad/react-native-launch-application
e.g In your ** bgMessaging** do:
//PackageName Must Be String For example "com.domain.application"
export default async (message: RemoteMessage) => {
SajjadLaunchApplication.open(".domain.application");
}

IOS Expo Push Notifications when app is in foreground

reading from the expo docs:
For iOS, you would be wise to handle push notifications that are
received while the app is foregrounded, because otherwise the user
will never see them. Notifications that arrive while the app are
foregrounded on iOS do not show up in the system notification list. A
common solution is to just show the notification manually. For
example, if you get a message on Messenger for iOS, have the app
foregrounded, but do not have that conversation open, you will see the
notification slide down from the top of the screen with a custom
notification UI.
What I don't understand is what is the best approach for that? is there an Expo API for showing such messages? or should I create an alert component of my own? It is not really clear from the docs.
Thanks.
This answer is outdated as of February 20, 2020. Please see https://stackoverflow.com/a/60344280/2441420 for how to show iOS Notification when your application is in the Foreground
There isn't an Expo API for showing those messages. You can use any 'toast' library of your choosing and display the notification message, but that should be all your code.
For example, this is how we are doing right now:
export default class HomeScreen extends React.Component {
componentDidMount() {
this.notificationSubscription = Notifications.addListener(
(notification) => this.handlePushNotification(notification),
);
}
handlePushNotification(notification) {
const { navigation } = this.props;
PushNotificationsService.handleNotification(notification, navigation);
}
(...)
import Toast from 'react-native-root-toast';
export default class PushNotificationsService {
static handleNotification(notification, navigation) {
if (notification.data.screen && notification.origin === 'selected') {
navigation.navigate(notification.data.screen);
}
Toast.show(notification.data.message);
}
}
Toast libraries include:
react-native-root-toast
react-native-easy-toast
react-native-simple-toast
Now you can just add that in one of your app entry point. The shouldShowAlert is what you want here
import * as Notifications from 'expo-notifications';
Notifications.setNotificationHandler({
handleNotification: async () => ({
shouldShowAlert: true,
shouldPlaySound: false,
shouldSetBadge: false,
}),
});
App.json :
{
"expo": {
"notification": {
"iosDisplayInForeground": true
}
}
DEMO
I'm not sure exactly when this was added to Expo, but as of Expo version 36 is easily doable.
To show Expo Push Notifications on iOS when your app is in the foreground, please do the following:
import { Vibration } from "react-native";
import { Notifications } from "expo";
import * as Permissions from "expo-permissions";
import Constants from "expo-constants";
registerForPushNotificationsAsync = async () => {
if (Constants.isDevice) {
const { status: existingStatus } = await Permissions.getAsync(
Permissions.NOTIFICATIONS
);
let finalStatus = existingStatus;
if (existingStatus !== "granted") {
const { status } = await Permissions.askAsync(
Permissions.NOTIFICATIONS
);
finalStatus = status;
}
if (finalStatus !== "granted") {
alert("Failed to get push token for push notification!");
return;
}
let token = await Notifications.getExpoPushTokenAsync();
console.log("Go to https://expo.io/notifications and copy the token below to easily send yourself a notification.");
console.warn("Notifications on iOS (and I believe Android) ONLY WORK ON A PHYSICAL DEVICE, not a simulator or emulator!!!")
console.log(token);
this.setState({ expoPushToken: token });
} else {
alert("Must use physical device for Push Notifications");
}
};
componentDidMount() {
this.registerForPushNotificationsAsync();
this._notificationSubscription = Notifications.addListener(
this._handleNotification
);
}
_handleNotification = async notification => {
if (notification.remote) {
Vibration.vibrate();
const notificationId = Notifications.presentLocalNotificationAsync({
title: "Follow #technoplato",
body: "To learn yourself goodly (also follow PewDiePie)",
ios: { _displayInForeground: true } // <-- HERE'S WHERE THE MAGIC HAPPENS
});
}
};
Quick and Easy Sanity Check
1) Go here: https://expo.io/notifications
2) Copy the token that is output to the terminal when your application is run.
3) Open your application on iOS.
4) Send a notification to yourself from https://expo.io/notifications and observe that it shows up even when your app is foregrounded.
Notes
Notifications WILL NOT BE RECEIVED ON AN IOS SIMULATOR
Expo makes Notifications ridiculously easy. I honestly can't believe it.
No idea why displayInForeground is false by default and not more prominent in the documentation. I'll submit a PR for it if I can.
Code originally found at this Snack: https://snack.expo.io/#documentation/pushnotifications?platform=ios
LocalNotification.ios._displayInForeground found here: https://docs.expo.io/versions/v36.0.0/sdk/notifications/#localnotification

How can I detect screen unlock with React Native?

Does anyone know a way in which I can detect when the user has opened their phone? To my understanding android.intent.USER_PRESENT is broadcast when the device is unlocked (e.g. correct password entered), however, I do not know how to detect the broadcast in with React native. Does anyone have a solution?
Look into AppState API in FB(Face Book)
It has 3 states on FB and 5 total. I only see 3 in FB but the other 2 may or may not be suppprted.
Active - The app is running in the foreground
background - The app is running in the background. The user is either in another app or on the home screen.
inactive - This is a state that occurs when transitioning between foreground & background, and during periods of inactivity such as entering the Multitasking view or in the event of an incoming call
Check out apples Docs for more on these.
You're going to have to test what state is hit when you the phone is in the lockscreen. I can't tell you what state to use because I have never tested the api out.
as you can see from the code below the test is done in a conditional statement
if (this.state.appState.match(/inactive|background/) && nextAppState === 'active')
I'm taking facebooks example here but attach the change event listiner in componentDidMount and remove in ComponentWillUnmount and the code will run accourding to the state.
import React, {Component} from 'react'
import {AppState, Text} from 'react-native'
class AppStateExample extends Component {
state = {
appState: AppState.currentState
}
componentDidMount() {
AppState.addEventListener('change', this._handleAppStateChange);
}
componentWillUnmount() {
AppState.removeEventListener('change', this._handleAppStateChange);
}
_handleAppStateChange = (nextAppState) => {
if (this.state.appState.match(/inactive|background/) && nextAppState === 'active') {
console.log('App has come to the foreground!')
}
this.setState({appState: nextAppState});
}
render() {
return (
<Text>Current state is: {this.state.appState}</Text>
);
}
}