DEV Community

Jeff Edmondson
Jeff Edmondson

Posted on

React Native Local iOS and Android Notifications

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

Top comments (13)

Collapse
 
paras700 profile image
Paras700

Hello, Jeff,
I am working on local schedule notification .so my app sends me multiple times notification react-native-android. In my app perform some habit to schedule it after that my app sends notification particular time so what is
the exact reason this problem??

Collapse
 
jeff_codes profile image
Jeff Edmondson

Hi!
I am not sure what you mean. If you could provide more details I might be able to help.

Collapse
 
paras700 profile image
Paras700

Hi,
There is another problem onNotification is not working react-native-android why ??

Collapse
 
rio412964527 profile image
Rio412964527 • Edited

Hi,jeff,
i am a beginner of react native.i have try your code on a android emulator.after i clicking the Local Notification, i got such a warning : Failed to post notification on channel"fcm_fallback_notification_channel"
can you help me to solve this?

Collapse
 
diegobonagurio profile image
diegobonagurio

Hi friend,

I have the same problem, did you manage to solve it?

Collapse
 
julianquintero profile image
Julian Quintero

Hello, how to do repeating local notifications with this? i added repeatType: 'minute' to the local notification function but it keeps showing the notification everysecond instead of every minute, help please.

Collapse
 
ahmetozalp profile image
Ahmet • Edited

Problem :(

  • Where:
    Build file '/Users/ahmetozalp/Desktop/reactnative/OtoAnaliz/node_modules/react-native-push-notification/android/build.gradle' line: 51

  • What went wrong:
    A problem occurred evaluating project ':react-native-push-notification'.

    Could not find method testImplementation() for arguments [junit:junit:4.12] on object of type org.gradle.api.internal.artifacts.dsl.dependencies.DefaultDependencyHandler.

  • Try:
    Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.

Collapse
 
jeff_codes profile image
Jeff Edmondson

Try running cd android && ./gradlew clean. Also was this problem when trying to clone and run the repo or incorporate the package into a project of your own?

Collapse
 
achuth_hadnoor profile image
Achuth Hadnoor🚀

Hi Jeff,
Thanks for putting things together.. I am not able to get the scheduled notifications if the app is closed or the phone is re-booted on Android . Is there any changes we need to do further to achieve this? Also can we have
1) repeating notifications,schedule notifications to a particular Date&time.
2) how to Request permission when it is turned off in settings?

Collapse
 
greenais profile image
Alexander

Did you sort out neglecting playSound: false for scheduled notifications in Android? I expect this inflexibility as very annoying one for users(
600+ open issues on github clearly look like we won't get any solution for that from mantainers soon...

Collapse
 
ffervsouza profile image
Fernando Vicente

Could you tell me if it is possible to hold an event when notification is generated?
I need to hold an event while the app is closed. But in iOS it kills processes when the user closes the app.

Collapse
 
abhijeetmane profile image
Abhijeet

Hi Jeff,

It works perfectly for Android. For ios it doesn't show notifications(local+remote). I see notification in logs but notification alert doesn't pop up in device. Any idea?

Collapse
 
jeff_codes profile image
Jeff Edmondson

That's interesting... Are you sure you allowed notifications for your app? When you first launch the application after configuring it with notifications it should ask you for permission to use notifications. If you did that however, go back and compare your AppDelagate.m file with the code here.

I hope that helps. Let me know if you need any further help!