I am getting push notification from firebase but when I sent it using the "https://fcm.googleapis.com/fcm/send" on android in react native using react-native-firebase library, I do not get any notification on android. However I am able to display the message on the console using "onMessage" method. But how I can get notification in the notification bar. My message is data-only therefore I also created bgMessaging.js for handling background message and here also I am able to display message on console but not on notification.
How I can fix this issue and display the message on the notification bar with data-only messages.
Below is my code
bgMessaging.js
import firebase from 'react-native-firebase';
// Optional flow type
import type { RemoteMessage } from 'react-native-firebase';
export default async (message: RemoteMessage) => {
// handle your message
console.log("message")
console.log(message)
// senName = message.data.senderName;
// senUid = message.data.senderUid;
// const notification = new
// firebase.notifications.Notification()
// .setNotificationId('notificationId')
// .setTitle(message.data.title)
// .setBody(message.data.body)
// .android.setChannelId('channel_id_foreground')
// .android.setSmallIcon('ic_launcher');
// firebase.notifications().displayNotification(notification);
return Promise.resolve();
}
index.js(following lines added at the end)
AppRegistry.registerHeadlessTask('RNFirebaseBackgroundMessage', () => bgMessaging); // <-- Add this line
App.js
componentDidMount() {
this.messageListener = firebase.messaging().onMessage((message: RemoteMessage) => {
//process data message
console.log(message);
});
}
AndroidManifest.xml
<service android:name="io.invertase.firebase.messaging.RNFirebaseBackgroundMessagingService" />
<service android:name="io.invertase.firebase.messaging.RNFirebaseMessagingService">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>
<service android:name="io.invertase.firebase.messaging.RNFirebaseInstanceIdService">
<intent-filter>
<action android:name="com.google.firebase.INSTANCE_ID_EVENT"/>
</intent-filter>
</service>
<service android:name=".MyTaskService" />
I've had the exact same problem, I've received the data-only messages but couldn't display the notification.
I found out that in order to display notifications for 8+ Android Version you need to create an Android Channel first, Code:
// Create Channel first.
const channel = new firebase.notifications.Android.Channel(
"general-channel",
"General Notifications",
firebase.notifications.Android.Importance.Default
).setDescription("General Notifications");
firebase.notifications().android.createChannel(channel);
// Build your notification
const notification = new firebase.notifications.Notification()
.setTitle(...)
.setBody(...)
.setNotificationId("notification-action")
.setSound("default")
.setData(message.data)
.android.setChannelId("general-channel")
.android.setPriority(firebase.notifications.Android.Priority.Max);
// Display the notification (with debug)
firebase
.notifications()
.displayNotification(notification)
.catch(err => console.error(err));
You can also do things when the notification is displayed:
firebase.notifications().onNotificationDisplayed(notification => { ... })
Or when it is received by the phone:
firebase.notifications().onNotification(notification => { ... })
If you want to get the notification that triggered the app opening, use the following:
firebase.notifications().getInitialNotification().then(notification => { ... })
refer the document here https://rnfirebase.io/docs/v4.3.x/notifications/receiving-notifications
App.js
async componentDidMount() {
this.getToken();
this.createNotificationListeners();
}
async createNotificationListeners() {
this.notificationListener = firebase.notifications().onNotification((notification) => {
const { title, body, data } = notification;
notification
.android.setChannelId('channel')
.android.setSmallIcon('icon')
.android.setAutoCancel(true)
.android.setPriority(firebase.notifications.Android.Priority.Max)
.setSound('default');
firebase.notifications().displayNotification(notification);
});
}
Firebase v6 will not show notification when the app is in foreground state
refer to this: https://rnfirebase.io/messaging/usage
You can use 3rd party libraries like react-native-push-notification. In react-native-push-notification, you need to create a channel first. Please follow this documentation
https://github.com/zo0r/react-native-push-notification#channel-management-android
After the channel created, include it when you want to show the notification. Like This:
import messaging from '#react-native-firebase/messaging';
...
messaging().onMessage(async (remoteMessage) => {
console.log('Auth.js / Message handled in app!', remoteMessage)
PushNotification.localNotification({
message: remoteMessage.notification.body,
title: remoteMessage.notification.title,
bigPictureUrl: remoteMessage.notification.android.imageUrl,
smallIcon: remoteMessage.notification.android.imageUrl,
channelId: 'channel-id',
});
});
Related
I am implementing FCM notifications in an Ionic React application. I am having trouble navigating to another page to display the notification details.
I have created a FCMService class in my react App, and initialising this in the index.ts file.
// FCMService.ts
export default class FCMService {
public static Instance: FCMService;
private _store: Store<IAppState>;
constructor(store: Store<IAppState>) {
this._store = store;
}
public static Initalise(store: Store<IAppState>) {
if (!FCMService.Instance) {
FCMService.Instance = new FCMService(store);
FCMService.Instance.InitaliseFCM();
FCMService.Instance._store.subscribe(() => { console.log(store.getState()) });
} else {
console.debug("FCM service already intialised. Please use FCMService.Instance");
}
}
private InitaliseFCM() {
// Request permission to use push notifications
// iOS will prompt user and return if they granted permission or not
// Android will just grant without prompting
PushNotifications.requestPermission().then(result => {
console.log(result);
if (result.granted) {
// Register with Apple / Google to receive push via APNS/FCM
PushNotifications.register();
} else {
// Show some error
}
});
// On success, we should be able to receive notifications
PushNotifications.addListener('registration', (token: PushNotificationToken) => {
console.log(token);
localStorage.setItem("FCM_TOKEN", token.value);
}
);
// Some issue with our setup and push will not work
PushNotifications.addListener('registrationError',
(error: any) => {
console.log(error);
}
);
// Show us the notification payload if the app is open on our device
PushNotifications.addListener('pushNotificationReceived',
(notification: PushNotification) => {
console.log(notification);
let data = notification.notification.data as INotificationData;
}
);
// Method called when tapping on a notification
PushNotifications.addListener('pushNotificationActionPerformed',
(notification: PushNotificationActionPerformed) => {
console.log(notification);
let data = notification.notification.data as INotificationData;
this._store.dispatch(setNotificationActionCreator(data));
}
);
}
}
and then the index.ts
const store = configureStore();
interface MainProps {
store: Store<IAppState>;
}
FCMService.Initalise(store);
ReactDOM.render(<Provider store={store}><App /> </Provider>, document.getElementById('root'));
serviceWorker.unregister();
I even tried using the Redux store to save the notification on Tap - and then that would publish the notification change event (which might of worked - if I could access the useHistory() hook in the App.tsx file)
This was my attempt at navigating via Redux store in App.tsx
const App: React.FC<IProps> = ({ getCompanies, getUser, notification }) => {
console.log('app');
console.log(process.env);
const history = useHistory();
if(notification){
history.push(`/page/plot-position/{notification.id}`);
}
return (
<IonApp>
<IonReactRouter>
<IonSplitPane contentId="main" when="false">
<Menu />
<IonRouterOutlet id="main">
<Route path="/login" component={LoginPage} exact />
<PrivateRoute path="/page/plot-position/:notificationId/" component={PlotPositionPage} exact />
<Redirect from="/" to="/login" exact />
</IonRouterOutlet>
</IonSplitPane>
</IonReactRouter>
</IonApp>
);
};
const mapStateToProps = (store: IAppState) => {
return {
user: store.user.user as UserDTO,
notification: store.notificationState.notification
};
};
const mapDispatchToProps = (dispatch: any) => {
return {
getCompanies: () => dispatch(getCompaniesStartActionCreator()),
getUser: () => dispatch(getUserStartActionCreator())
}
};
export default connect(mapStateToProps, mapDispatchToProps)(App);
It looks like your navigation works, but you're having trouble passing the notification object through to the page? You can pass the object through history state.
To access the useHistory hook you would need to make your FCMService a custom hook.
const useFCMService = (): void => {
const history = useHistory();
React.useEffect(() => {
// Method called when tapping on a notification
PushNotifications.addListener('pushNotificationActionPerformed',
(action: PushNotificationActionPerformed) => {
const notification = action.notification.data as INotificationData;
history.push({ pathname: '/page/plot-position/', state: { notification } });
}
);
}, []);
}
And then include your useFCMService custom hook in your App component.
const App: React.FC<IProps> = ({ getCompanies, getUser }) => {
useFCMService();
...
};
Deep linking provides us a way to do this: Using both an action to open the application and an action at opening the application we can enroute the user to the correct destination.
Opening the application
Here we will create an action to open the url when the user taps on the push notification; to do this less use a listener:
const {PushNotifications, App} = Plugins
***
PushNotifications.addListener(
"pushNotificationActionPerformed",
(notification: PushNotificationActionPerformed) =>{
const data = notification.notification.data;
if (data.packageNumber) App.openUrl({url: `com.company.appname://tabs/package-details/${data.packageNumber}`})
else App.openUrl({url:'/tabs'})
}
)
com.company.app:// is of capital importance since the app must reach the application must reach an existing given url, otherwise the following action(catching the url) won't be triggers since it waits a complete true from the App.openUrl function; as we are opening an internal url, this must begin with the apps given name in the capacitor config page(see the following example where we can realize how use the local url).
In this way we are adding a function to open the application in an specific route.
Redirecting the user
Here, we will complete the application's part from the deep linking tutorial: we create a new listener component who handles the appOpenUrl events and redirects to the user and we will put it on the main App file inside of its respective IonRouter:
const AppUrlListener: React.FC<any> = () => {
let history = useHistory();
useEffect(() => {
App.addListener('appUrlOpen', (data: any) => {
const slug = data.url.split(':/').pop();
if (slug) {
history.push(slug);
}
});
}, []);
return null;
};
Don't forget the route in router must begin with /, and since the application url contains :/, we split the url here and we get the second part, the slug; we push it on the history, triggering the router and getting the normal behaviour when you entering in a new route.
We will add this component inside of the router:
<IonReactRouter>
<IonSplitPane contentId="main">
<Menu />
<AppUrlListener />
<IonRouterOutlet id="main">
Now, the application will be listening the appOpenUrl event, and when it gets a new of this events, it will push the gotten url to the history, redirecting the user to that route.
I'm usnig fcm for notification in nodejs. So I made this And when I push message from nodejs to android, I got message well. When the app is running, I can get the small Icon image. But when the app is not running, I got the notification with no image. how can I get the push message with image when the app is in background? here is my nodejs code
let pushMsg = req.body.pushMsg;
let groupName = req.body.groupName;
console.log(groupName)
var condition = "'"+groupName+"' in topics"; //"'all' in topics || 'industry-tech' in topics";
var message = {
notification: {
title: 'schedule updated',
body: pushMsg,
image:'./upload/haiilogo.png'
},
condition: condition
};
admin.messaging().send(message)
.then((response) => {
console.log('Successfully sent message:', response);
})
.catch((error) => {
console.log('Error sending message:', error);
});
I solved. I added manifest to default icon like this
<meta-data android:name="com.google.firebase.messaging.default_notification_icon"
android:resource="#drawable/haiilogo" />
I feel like the docs at react-native-fcm are a bit of a mess and I am having a hard time figuring this out.
I currently have a production app and my android users are telling me they are not receiving notifications for events where they should be. So this is stressing me out a lot right now. On iOS everything seems fine.
In the react-native-fcm example app you can see the following:
//FCM.createNotificationChannel is mandatory for Android targeting >=8. Otherwise you won't see any notification
componentDidMount() {
FCM.createNotificationChannel({
id: 'default',
name: 'Default',
description: 'used for example',
priority: 'high'
})
}
Do I need to call FCM.createNotificationChannel()?? I mainly use remote notifications so is this relevant in any way?
Here is MY setup:
import FCM, {
FCMEvent,
NotificationType,
RemoteNotificationResult,
WillPresentNotificationResult,
} from 'react-native-fcm';
FCM.on(FCMEvent.Notification, async (notif) => {
// there are two parts of notif. notif.notification contains the notification payload, notif.data contains data payload
FCM.presentLocalNotification({
id: "new_message", // (optional for instant notification)
title: notif.fcm.title, // as FCM payload
body: notif.fcm.body, // as FCM payload (required)
sound: "default", // as FCM payload
priority: "high", // as FCM payload
click_action: "com.myapp.MyCategory", // as FCM payload - this is used as category identifier on iOS.
badge: 10, // as FCM payload IOS only, set 0 to clear badges
number: 10, // Android only
ticker: "My Notification Ticker", // Android only
auto_cancel: true, // Android only (default true)
large_icon: "ic_launcher", // Android only
icon: "ic_launcher", // as FCM payload, you can relace this with custom icon you put in mipmap
color: "blue", // Android only
vibrate: 300, // Android only default: 300, no vibration if you pass 0
wake_screen: true, // Android only, wake up screen when notification arrives
group: "group", // Android only
picture: "https://google.png", // Android only bigPicture style
ongoing: false, // Android only
my_custom_data:'my_custom_field_value', // extra data you want to throw
lights: true, // Android only, LED blinking (default false)
});
if(Platform.OS ==='ios'){
//optional
//iOS requires developers to call completionHandler to end notification process. If you do not call it your background remote notifications could be throttled, to read more about it see https://developer.apple.com/documentation/uikit/uiapplicationdelegate/1623013-application.
//This library handles it for you automatically with default behavior (for remote notification, finish with NoData; for WillPresent, finish depend on "show_in_foreground"). However if you want to return different result, follow the following code to override
//notif._notificationType is available for iOS platfrom
switch(notif._notificationType){
case NotificationType.Remote:
notif.finish(RemoteNotificationResult.NewData) //other types available: RemoteNotificationResult.NewData, RemoteNotificationResult.ResultFailed
break;
case NotificationType.NotificationResponse:
notif.finish();
break;
case NotificationType.WillPresent:
notif.finish(WillPresentNotificationResult.All) //other types available: WillPresentNotificationResult.None
break;
}
}
});
FCM.on(FCMEvent.RefreshToken, (token) => {
try {
const { currentUser } = firebase.auth();
let updates = {};
updates[`/allUsers/serviceUsers/${currentUser.uid}/userInfo/fcmToken`] = token;
return firebase.database().ref().update(updates).catch(err => console.log('fcm refresh error', err))
} catch (e) {
console.log('couldnt update fcm refresh token', e)
}
});
const store = createStore(reducers, {}, applyMiddleware(ReduxThunk));
class App extends Component {
componentWillMount() {
let config = {configgg}
!firebase.apps.length ? firebase.initializeApp(config) : firebase.app();
FCM.requestPermissions();
}
render() {
return (
<Provider store={store}>
<Router/>
</Provider>
);
}
}
export default App;
I mainly use remote notifications and it is critical for my app for it to work. Is there anything I am missing in my setup?
Any hint or suggestions will help me out a lot! Thanks!
EDIT:
Found this in adb logcat when receiving a notification (that did not show up)
NotificationService: No Channel found for pkg=com.lisdoworker, channelId=null, id=0, tag=GCM-Notification:9015992, opPkg=com.lisdoworker, callingUid=10487, userId=0, incomingUserId=0, notificationUid=10487, notification=Notification(channel=null pri=0 contentView=null vibrate=null sound=null defaults=0x0 flags=0x10 color=0x00000000 vis=PRIVATE)
Does this have to do with FCM.createNotificationChannel()??
Yeah, apparently createNotificationChannel was added in version 16 to support Android 8 and it is barely documented.
I am unable to get notification in Foreground on Android 8 only. Also unable to get control on Background notification. But on Android version below 8 working fine with current implementation.
Steps followed:-
Installing react-native-firebase plugin version 5.0.0 into application.
Created project on firebase console and added google_service.json file into android/app folder.
In AndroidManifest added below code:-
<service android:name="io.invertase.firebase.messaging.RNFirebaseMessagingService">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>
<service android:name="io.invertase.firebase.messaging.RNFirebaseInstanceIdService>
<intent-filter>
<action android:name="com.google.firebase.INSTANCE_ID_EVENT"/>
</intent-filter>
</service>
<service android:name="io.invertase.firebase.messaging.RNFirebaseBackgroundMessagingService"/>
<receiver android:name="io.invertase.firebase.notifications.RNFirebaseNotificationReceiver"/>
<receiver android:enabled="true" android:exported="true" android:name="io.invertase.firebase.notifications.RNFirebaseNotificationsRebootReceiver">
<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"/>
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</receiver>
<meta-data android:name="com.google.firebase.messaging.default_notification_icon" android:resource="#mipmap/ic_launcher"/>
<meta-data android:name="com.google.firebase.messaging.default_notification_channel_id" android:value="test_app"/>
Below function is added on App.js page and calling in componentDidMountMethod():-
performNotificationOperations(){
this.messageListener = firebase.messaging().onMessage((message: RemoteMessage) => {
console.log("Message",message);
alert("Notification Message Arrived");
if(this.state.isLogin){
const notification = new firebase.notifications.Notification()
.setNotificationId(message.messageId)
.setTitle(message.data.show_name)
.setBody(message.data.description)
.setData(message.data)
.android.setChannelId('test_app')
.android.setBigPicture(message.data.showImage)
.android.setPriority(firebase.notifications.Android.Priority.High);
firebase.notifications().displayNotification(notification).catch(err => alert("Error On Message"));
}
});
this.notificationListener = firebase.notifications().onNotification((notification: Notification) => {
console.log("Notification=>",notification);
alert("Notification Arrived");
if(this.state.isLogin){
notification.android.setChannelId('test_app')
notification.android.setBigPicture(notification._data.showImage);
notification.android.setPriority(firebase.notifications.Android.Priority.High)
firebase.notifications().displayNotification(notification).catch(err => alert("Error On Notification"));
}
});
this.notificationOpenedListener = firebase.notifications().onNotificationOpened((notificationOpen: NotificationOpen) => {
console.log(notificationOpen,"Opened listener");
console.log(notificationOpen.notification._data.type,"notificationOpen");
firebase.notifications().removeDeliveredNotification(notificationOpen.notification._notificationId)
if(this.state.isLogin){
if(notificationOpen.notification._data.type==='show'){
Navigate.forward('myshowdetails', this._navigator, {show:notificationOpen.notification._data});
}else if(notificationOpen.notification._data.type==='episode'){
this.playEpisode(notificationOpen.notification._data.episodeToken);
Navigate.forward('myshowdetails', this._navigator, {show:notificationOpen.notification._data});
}
}
});
firebase.notifications().getInitialNotification()
.then((notificationOpen: NotificationOpen) => {
if (notificationOpen) {
alert('Initial Notification');
console.log(notificationOpen,"notificationOpen");
console.log(notificationOpen.notification._data.type,"notificationOpen");
firebase.notifications().removeDeliveredNotification(notificationOpen.notification._notificationId)
if(this.state.isLogin){
alert('IS LOGIN TRUE');
if(notificationOpen.notification._data.type==='show'){
Navigate.forward('showdetails', this._navigator, {show:notificationOpen.notification._data});
}else if(notificationOpen.notification._data.type==='episode'){
this.playEpisode(notificationOpen.notification._data.episodeToken);
Navigate.forward('showdetails', this._navigator, {show:notificationOpen.notification._data});
}
}
}
});
firebase.messaging().getToken().then(token => {
console.log("GCM Token====>>>>>>>>",token);
Global.GCM_TOKEN=token;
// alert(token);
if(Global.IS_USER_LOGIN){
Util.saveFCMToken(token);
}
});
}
Added bgMessage.js file to handle data messages and registered Headless JS service using AppRegistery.
// #flow
import firebase from 'react-native-firebase';
// Optional flow type
import type { RemoteMessage } from 'react-native-firebase';
import type { Notification,NotificationOpen} from 'react-native-firebase';
export default async (message: RemoteMessage) => {
// handle your message
// console.log("Message=>",message);
alert("Message Arrived");
const notification = new firebase.notifications.Notification()
.setNotificationId(message.messageId)
.setTitle(message.data.show_name)
.setBody(message.data.description)
.setData(message.data)
.android.setChannelId('podpitara_app')
.android.setBigPicture(message.data.showImage)
.android.setPriority(firebase.notifications.Android.Priority.High);
firebase.notifications().displayNotification(notification).catch(err => alert("Error in Background"));
return Promise.resolve();
}
Headless JS service call:-
AppRegistry.registerHeadlessTask('RNFirebaseBackgroundMessage', () =>
bgMessaging);
Additional Information:-
Platform - Android
node-version - v8.6.0
react-native - 0.57.0
react-native-firebase - 0.5.0
Problems facing
Unable to receive notification in Foreground in case of Android 8 only.
In case of background/minimized state, want to show notification with big picture, but not getting control from where I can handle displaying notification.
In case of debug mode application displaying image peroperly int notification tray, but in case of release its not showing image.
Please let me know, What I am doing wrong.
Got it to work.
It's because from Android 8 you need to create a channel
// Build a channel
const channel = new firebase.notifications.Android.Channel('test-channel', 'Test Channel', firebase.notifications.Android.Importance.Max)
.setDescription('My apps test channel');
// Create the channel
firebase.notifications().android.createChannel(channel);
https://rnfirebase.io/docs/v4.2.x/notifications/android-channels
I was only using
android.setChannelId(message.data.channelId)
Now it shows while the app is in the foreground.
My full function is like this
const newNotification = new firebase.notifications.Notification()
.android.setChannelId(message.data.channelId)
.setNotificationId(message.messageId)
.setTitle(message.data.title)
.setBody(message.data.body)
.setSound("default")
.setData(message.Data)
.android.setAutoCancel(true)
.android.setSmallIcon('ic_notification')
.android.setCategory(firebase.notifications.Android.Category.Alarm)
// Build a channel
const channelId = new firebase.notifications.Android.Channel(message.data.channelId, channelName, firebase.notifications.Android.Importance.Max);
// Create the channel
firebase.notifications().android.createChannel(channelId);
firebase.notifications().displayNotification(newNotification)
Hope this will help you
This worked for me
componentDidMount()
{
const channel = new firebase.notifications.Android.Channel(
'channelId',
'Channel Name',
firebase.notifications.Android.Importance.Max
).setDescription('A natural description of the channel');
firebase.notifications().android.createChannel(channel);
this.notificationListener = firebase.notifications().onNotification((notification) => {
if (Platform.OS === 'android') {
const localNotification = new firebase.notifications.Notification()
.setNotificationId(notification.notificationId)
.setTitle(notification.title)
.setSubtitle(notification.subtitle)
.setBody(notification.body)
.setData(notification.data)
.android.setSmallIcon("app_icon_name") // use mipmap icon name(have not tried drawable icon)
.android.setChannelId('channelId')
.android.setColor('#ffffff') // you can set a color here
.android.setPriority(firebase.notifications.Android.Priority.High);
firebase.notifications()
.displayNotification(localNotification)
.catch(err => console.error(err));
} });
}
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