React Native Local iOS and Android Notifications

November 14th, 2019

Introduction

My requirements were simple I needed to incorporate Local notifications that I could schedule to to appear at a later time for both iOS and Android. I also needed these notifications to still display even if the app was closed. After some research I found that react-native-push-notification was my best bet. However, I found that this was a bit tricky to get up and running, but at long last I was successful. My struggle is your lucky day.

Full App Repo: https://github.com/edmondso006/ReactNativeLocalNotifications

Installation

We are actually going to have to install two packages because the react-native-push-notification package utilizes push-notifications-ios in order to send iOS notifications. These packages also support Push Notifications but that is out of scope of this tutorial.

    npm install --save react-native-push-notification
    npm install --save @react-native-community/push-notification-ios

Since we are going to be using native features on the device we need to Manually Link these packages. To do that run the following commands. Linking allows you to use the native features of the device!

    react-native link react-native-push-notification
    react-native link @react-native-community/push-notification-ios

iOS Setup

Since we install a native module it is a good idea to run pod install in the iOS directory. This will give you access to the module we install through npm in xCode

    cd ios
    pod install

Since we want to use both local and scheduled notifications we need to add some Objective-C code in the AppDelegate.m file of the application. For this you are going to want to navigate to the iOS directory in your app folder and open the .xcworkspace file. ( Notifications/ios/Notifications.xcworkspace ). Then open the AppDelegate.m .

First import the module that we installed through npm.

    #import <RNCPushNotificationIOS.h>

Then add the following code into the body.

    // Required to register for notifications
    - (void)application:(UIApplication *)application didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings
    {
      [RNCPushNotificationIOS didRegisterUserNotificationSettings:notificationSettings];
    }
    // Required for the register event.
    - (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
    {
      [RNCPushNotificationIOS didRegisterForRemoteNotificationsWithDeviceToken:deviceToken];
    }
    // Required for the notification event. You must call the completion handler after handling the remote notification.
    - (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
    fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
    {
      [RNCPushNotificationIOS didReceiveRemoteNotification:userInfo fetchCompletionHandler:completionHandler];
    }
    // Required for the registrationError event.
    - (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error
    {
      [RNCPushNotificationIOS didFailToRegisterForRemoteNotificationsWithError:error];
    }
    // Required for the localNotification event.
    - (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification
    {
      [RNCPushNotificationIOS didReceiveLocalNotification:notification];
    }

Now is a good time to try and build the project in xCode. If you did everything correctly you should have a successful build. If not make sure that you ran pod install in the iOS directory of your application. Thats it for the iOS Setup!

Android Setup

Since we are going to want to use local scheduled notifications we are going to need to add some code to the android/app/src/main/AndroidManifest.xml file. Outside of the <application> tag but within the <manifest> tag add the following code:

    <uses-permission android:name="android.permission.WAKE_LOCK" />
    <permission
       android:name="${applicationId}.permission.C2D_MESSAGE"
       android:protectionLevel="signature" />
    <uses-permission android:name="${applicationId}.permission.C2D_MESSAGE" />
    <uses-permission android:name="android.permission.VIBRATE" />
    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>

Then add the following code within the <application> tag:

    <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"/>
    
    <!-- < Only if you're using GCM or localNotificationSchedule() > -->
    <receiver   android:name="com.google.android.gms.gcm.GcmReceiver"
                android:exported="true"
                android:permission="com.google.android.c2dm.permission.SEND" >
            <intent-filter>
            <action android:name="com.google.android.c2dm.intent.RECEIVE" />
            <category android:name="${applicationId}" />
            </intent-filter>
    </receiver>
    
    <!-- < Only if you're using GCM or localNotificationSchedule() > -->
    <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>
    <service android:name="com.dieam.reactnativepushnotification.modules.RNPushNotificationRegistrationService"/>
    
    <!-- < Only if you're using GCM or localNotificationSchedule() > -->
    <service
             android:name="com.dieam.reactnativepushnotification.modules.RNPushNotificationListenerServiceGcm"
             android:exported="false" >
            <intent-filter>
             <action android:name="com.google.android.c2dm.intent.RECEIVE" />
        </intent-filter>
    </service>
     <!-- </ Only if you're using GCM or localNotificationSchedule() > -->
    
    <service
        android:name="com.dieam.reactnativepushnotification.modules.RNPushNotificationListenerService"
        android:exported="false" >
        <intent-filter>
                <action android:name="com.google.firebase.MESSAGING_EVENT" />
        </intent-filter>
    </service>

And finally, create the file `android/app/src/res/values/colors.xml` and add the following:

    <resources>
        <color name="white">#FFF</color>
    </resources>

That's it for the Android Setup!

Putting it all together!

In order to keep things simple and clean let's create a file call NotificationService.js . This file is where all of our Notification code will go. Add the following to that file:

    import PushNotification from 'react-native-push-notification';
    
    export default class NotificationService {
        //onNotificaitn is a function passed in that is to be called when a
        //notification is to be emitted.
      constructor(onNotification) {
        this.configure(onNotification);
        this.lastId = 0;
      }
    
      configure(onNotification) {
        PushNotification.configure({
          onNotification: onNotification,
    
          // IOS ONLY (optional): default: all - Permissions to register.
          permissions: {
            alert: true,
            badge: true,
            sound: true
          },
    
          popInitialNotification: true,
        });
      }
    
        //Appears right away 
      localNotification() {
        this.lastId++;
        PushNotification.localNotification({
          title: "Local Notification", 
          message: "My Notification Message", 
          playSound: false, 
          soundName: 'default', 
          actions: '["Yes", "No"]'
        });
      }
    
        //Appears after a specified time. App does not have to be open.
      scheduleNotification() {
        this.lastId++;
        PushNotification.localNotificationSchedule({
          date: new Date(Date.now() + (30 * 1000)), //30 seconds
          title: "Scheduled Notification", 
          message: "My Notification Message",
          playSound: true, 
          soundName: 'default', 
        });
      }
    
      checkPermission(cbk) {
        return PushNotification.checkPermissions(cbk);
      }
    
      cancelNotif() {
        PushNotification.cancelLocalNotifications({id: ''+this.lastId});
      }
    
      cancelAll() {
        PushNotification.cancelAllLocalNotifications();
      }
    }

Note: This is the absolute basics. Consult the Github repos for more information

Add the following to your app.js

    import React, { Component } from 'react';
    
    import {
      SafeAreaView,
      StyleSheet,
      ScrollView,
      View,
      Text,
      StatusBar,
      Button,
      Alert
    } from 'react-native';
    
    import {
      Header,
      Colors,
    } from 'react-native/Libraries/NewAppScreen';
    
    
    import NotificationService from './NotificationService';
    
    class App extends Component {
    
      constructor(props) {
        super(props);
            //creating a new instance of the NotificationService 
            //& passing in the function we want called when the notification happens
        this.notification = new NotificationService(this.onNotification);
      }
    
        //Gets called when the notification comes in
      onNotification = (notif) => {
        Alert.alert(notif.title, notif.message);
      }
        
        //Permissions to use notifications
      handlePerm(perms) {
        Alert.alert("Permissions", JSON.stringify(perms));
      }
    
      render(){
        return (
          <>
            <StatusBar barStyle="dark-content" />
            <SafeAreaView>
              <ScrollView
                contentInsetAdjustmentBehavior="automatic"
                style={styles.scrollView}>
                <Header />
                {global.HermesInternal == null ? null : (
                  <View style={styles.engine}>
                    <Text style={styles.footer}>Engine: Hermes</Text>
                  </View>
                )}
                <View style={styles.body}>
                  <Button title={"Local Notification"} onPress={() => { this.notification.localNotification() }} />
                  <Button title={"Scheduled (30s) Notification"} onPress={() => { this.notification.scheduleNotification() }} />
                </View>
              </ScrollView>
            </SafeAreaView>
          </>
        );
      }
    }
    
    const styles = StyleSheet.create({
      scrollView: {
        backgroundColor: Colors.lighter,
      },
      engine: {
        position: 'absolute',
        right: 0,
      },
      body: {
        backgroundColor: Colors.white,
      },
      sectionContainer: {
        marginTop: 32,
        paddingHorizontal: 24,
      },
      sectionTitle: {
        fontSize: 24,
        fontWeight: '600',
        color: Colors.black,
      },
      sectionDescription: {
        marginTop: 8,
        fontSize: 18,
        fontWeight: '400',
        color: Colors.dark,
      },
      highlight: {
        fontWeight: '700',
      },
      footer: {
        color: Colors.dark,
        fontSize: 12,
        fontWeight: '600',
        padding: 4,
        paddingRight: 12,
        textAlign: 'right',
      },
    });
    
    export default App;

Wrap up

If everything was successful you should be able to schedule local notifications! Here the the repo for the project: https://github.com/edmondso006/ReactNativeLocalNotifications. If you have any questions please feel free to reach out and ask.

Sources

https://github.com/zo0r/react-native-push-notification

https://github.com/react-native-community/react-native-push-notification-ios