README: Local Notification Tutorial, How To, Notes, Usage (not relevant to remote/push notifications)
See original GitHub issueI understand this is not technically an issue, but the amount of hours I’ve spent crawling over all the posts in this repo, I wanted to give back and potentially help some other people out. I didn’t want this to be lost in the sea of unmerged PRs. Any and all feedback would be greatly appreciated. I’m hoping to catch the attention of a contributor so we can get this merged into official docs!!
version notes:
"react-native": "0.51.0",
"react-native-push-notification": "3.0.2",
"react-native-navigation": "1.1.323",
"react-redux": "5.0.6",
"redux": "3.7.2",
Initial set up and installation
- on android, it is not necessary, in fact it may break your app, to use
compile ('com.google.android.gms:play-services-gcm:8.1.0') {
force = true;
}
in the dependencies
section of your android/app/build.gradle
local notifications will run fine without it. I do not have push notifications set up, but I image it is quite necessary for push(remote) notifications
- if you are installing for the first time or have been struggling to get this to work. My advice is to skip the
react-native link react-native-push-notification
step in the instructions and manually link everything yourself. Don’t forget to edit theheader search path
in your xcode project as well so the#import <React/RCTPushNotificationManager.h>
will be able to find the correct file. This is step 3 in the facebook react native docs.
Here is how I got my local notifications to work. My project doesn’t use push notifications. I use moment instead of the javascript date, but use moment().toDate() as per the momentjs docs to get the javascript object to pass back into this library.
this example only schedules a local notification for 3 seconds after it was initially created
Some notes
when adding id to the notification so that you can potentially cancel it later.
-
In android, the id is added to the root level of the notification object, meaning the same level in the object in which the message and date are. That id has to not only be of
type String
, but it has to ALSO be a stringified number. -
In ios, the id must go into the userInfo object. The value of id must also be of
type String
, but does not necessarily have to be a stringified number (I haven’t tested that case). However, most likely if you are developing for both ios and android, it would be better practice to keep ids the same across platforms.
To solve this issue, I created a constants file that mapped a string such as 'someNotificationId'
to a stringified number such as '111'
to keep cross-platform notifications consistent, and I used a helper function to perform that mapping for me. I will include the constant and helper function down below as well. This allows you to develop with a text string for the id that you pass into a helper function which turns it into a predetermined stringified number that you can black box away once you set up that mapping.
receiving notifications
-
On android, the user will the receive local notifications alert (the one the comes down from the top of the phone) whether the app is in the foreground or background, however, the onNotification function will not fire until the notification is tapped. Then onNotification is fired and you can do what you want with the payload. onNotification is not fired on receipt of the notification, regardless of whether the app is in the foreground or background. From what I’ve read in these docs and android docs, this is intended behavior.
-
On ios, the user will only receive the local notification alert if the app is in the background. It will not show up if the app is foregrounded. The difference between ios and android is in the onNotification callback. On ios, if the app is in the foreground and it receives a notification, onNotification will be fired and you can do something with the payload. I opted to show it as a toast within the app, so the notification still gets delivered. onNotification will still be fired if the app is in the foreground and the user taps on a delivered notification. onNotification will not be called if the app is in the background and the notification has been delivered but has not been interacted with by the user.
passing a payload with the notification
-
On android, there are 2 requirements. The first is that you must
JSON.stringify(payload)
the payload. I have only used objects as the payload, so I am unsure as to if other types of payloads are supported. The second is that to attach it the notification, you must add it to thedata
key in the root level of the notification object, on the same level as the ‘id’ key as shown in the example above. -
On ios, the payload does not need to be stringified and can be added to the userInfo object. I opted to explicitly specify the
id
property in userInfo and spread the payload object. For those unsure about the spread operator usage. Here is a quick example:
const obj1 = {fruit: 'apple'};
const obj2 = {veggie: 'broccoli'};
const obj3 = {...obj1, ...obj2};
console.log(obj3); // will show {fruit: 'apple', veggie: 'broccoli'}
console.log({
meat: 'chicken',
...obj3,
}; // will show {meat: 'chicken', fruit: 'apple', veggie: 'broccoli'}
Both on ios and android the payload will show up under the data
key inside the notification object returned by onNotification. You can then process the payload however you like.
cancelling notifications
- simply call
cancelLocalNotifications({id: yourNotificationId})
. The only gotcha is that on iOS you need to specify another property on the notification object called number and set it to an integer value (I chose0
arbitrarily). I do not know what is does at this time or why it works, only that if you don’t have thenumber
property on the notification object, you cannot cancel the notification.
scheduling notifcations
- on both ios and android, the date property must be a
Javascript Date object
. You can convert a moment to aDate object
using the moment().toDate() function
constructing the notification object
this refers to the notification object before dispatching it with PushNotification.localNotificationSchedule(notification)
- I have found the you don’t need to fork the code for Platform specific things like userInfo (is only on ios) and data is used by android. You can construct it to be platform agnostic and the appropriate OS will take the properties that it needs and can use.
note about the code below
I have wrapped this libraries functions with my own to make the API more reusable for my needs, you may find that it works for you, otherwise adjust it to your liking. But the construction of the notification object and the dispatching of the notification should all be exceedingly similar
export function scheduleLocalNotification(message, date, id, payload) {
//message: type String
//date: type String format 'YYYY-MM-DD HH:mm' (NOTIFICATION_DATE_TIME_FORMAT)
//construct the notification parameters
// const fireDate = moment(date, NOTIFICATION_DATE_TIME_FORMAT).toDate();
const fireDate = moment()
.add(3, 'seconds')
.toDate();
const notification = {
id: createPushId(id), //for android cancel notification (must be stringified number)
message,
number: 0, //necessary for iOS cancellation (not sure why)
date: fireDate,
//for ios only
userInfo: {
id: createPushId(id), //for ios cancel notfication (can be any string)
...payload,
},
//for android only
data: JSON.stringify(payload),
};
//schedule the notification
PushNotification.localNotificationSchedule(notification);
}
export function createPushId(pushType) {
return NOTIFICATION_TYPE_TO_ID[pushType];
}
export const NOTIFICATION_TYPE_TO_ID = {
fruit: '111',
meat: '222',
veggies: '333',
};
so i can now call anywhere inside my RN app
scheduleLocalNotification(
'This is a test message',
'2018-03-24 15:45',
'fruit',
{foo: 'bar'}
)
and it will be dispatched as a notification that will fire at 3:45PM on march 24, 2018. It will have the id
of 'fruit'
or technically '111'
because of the mapping and the payload is {foo: 'bar'}
.
you can cancel it by calling
PushNotification.cancelLocalNotifications({id: createPushId('fruit')})
Issue Analytics
- State:
- Created 6 years ago
- Reactions:46
- Comments:15 (1 by maintainers)
This should be added in a doc or readme file in the repo !
Damn this is very useful! Is there any way to make android behave like iOS in the sense that you only get local push notifications if the app is in the background?