@setrow/setrow-rn-push

A React Native push notification library for Setrow customers.

Usage no npm install needed!

<script type="module">
  import setrowSetrowRnPush from 'https://cdn.skypack.dev/@setrow/setrow-rn-push';
</script>

README

Introduction

In this module, it's intended to make it possible for Setrow customers who use React Native to send push notifications to their users.

Pre-Install

1) Create Firebase Project

First of all, you have to create a Google Firebase Project here (It's free)

2) Add Apps

Add iOS and Android apps as per your requirement

3) Register Android

The Android Package Name can be found in /android/app/build.grade as applicationId. Defaults to com.project_name

Download google-services.json

A google-services.json file contains all of the information required by the Firebase Android SDK to connect to your Firebase project.

After creating your Android app, you'll be prompted to download the google-services.json file. Once downloaded, place this file in the root of your project at android/app/google-services.json.

(For more details, check the official Firebase docs here.)

4) Register iOS

Essentially the same as Android but grab the bundle id from the project in XCode.

Download GoogleService-Info.plist

A GoogleService-Info.plist file contains all of the information required by the Firebase iOS SDK to connect to your Firebase project.

Once downloaded, add the file to your iOS app using 'File > Add Files to "[YOUR APP NAME]"…' in XCode.

(For more details, check the official Firebase docs here)

Upload APNS Keys

In Firebase console, you have to include either APNs Authentication Key or APNs Certificate in Project Settings > Cloud Messaging in order to receive push notifications.

(For more details, check the official Firebase docs here to see how you can create these keys.)

Installation

$ npm install @setrow/setrow-rn-push --save

Post-Install

After installation, run the following command:

$ react-native link react-native-firebase

Android specific steps

1- Your android/app/build.gradle file should look like the following:

dependencies {
   implementation project(':react-native-device-info')
   implementation project(':@setrow_RNNotifications')
    
  
   // Add the following to the VERY BOTTOM of the file
   apply plugin: 'com.google.gms.google-services'

2- In android/gradle/wrapper/gradle-wrapper.properties, make sure your Gradle version is at least v4.4 or above. If not, update the gradle URL to gradle-5.4.1-all.zip

3- Your android/build.gradle should look like the following:

buildscript {
    repositories {
        google()  // <-- Check this line exists and is above jcenter
        jcenter()
        // ...
    }
    dependencies {
        classpath("com.android.tools.build:gradle:4.1.0")
        classpath 'com.google.gms:google-services:4.3.8'
        // ...
    }
}
allprojects {
    repositories {
        mavenLocal()
        google() // <-- Add this line above jcenter
        jcenter()
        maven {
            // All of React Native (JS, Obj-C sources, Android binaries) is installed from npm
            url "$rootDir/../node_modules/react-native/android"
        }
        maven {
            // Android JSC is installed from npm
            url("$rootDir/../node_modules/jsc-android/dist")
        }
    }
}

4- Your MainApplication.java should like following:

//...
import com.learnium.RNDeviceInfo.RNDeviceInfo;
import com.setrow.RNNotifications.LocalNotificationsPackage;

//...

protected List<ReactPackage> getPackages() {
  @SuppressWarnings("UnnecessaryLocalVariable")
  List<ReactPackage> packages = new PackageList(this).getPackages();
    //...
    packages.add(new LocalNotificationsPackage());
  return packages;
}

5- Your AndroidManifest.xml should include following lines:

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

<application
android:launchMode="singleTop">

6- Your /android/settings.gradle file should look like this:

//...
include ':react-native-device-info'
project(':react-native-device-info').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-device-info/android')
include ':@setrow_RNNotifications'
project(':@setrow_RNNotifications').projectDir = new File(rootProject.projectDir, '../node_modules/setrow-rn-push/android')
apply from: file("../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesSettingsGradle(settings)
include ':app'

iOS specific steps

Turn on following two capabilities in Xcode:

a) Push Notifications

b) Background Modes - Check only Remote Notifications

Make sure your Podfile includes the lines below and then run pod install

# Uncomment the line below to define a global platform for your project
platform :ios, '10.0'

target 'ReactPushNotifications' do
  # Uncomment the next line if you're using Swift or would like to use dynamic frameworks
  # use_frameworks!

  pod 'Firebase/Analytics'
  pod 'Firebase/Messaging'
  pod 'RNDeviceInfo', :path => '../node_modules/react-native-device-info'
  pod 'RNNotifications', :path => '../node_modules/setrow-rn-push'
end

Your AppDelegate should look like the following:

// ios/Notifications/AppDelegate.m

#import "AppDelegate.h"
#import <Firebase.h>

//...


@implementation AppDelegate

NSString *const kGCMMessageIDKey = @"gcm.message_id";

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
  {
      [FIRApp configure];
      [FIRMessaging messaging].delegate = self;
      if ([UNUserNotificationCenter class] != nil) {
      [UNUserNotificationCenter currentNotificationCenter].delegate = self;
      UNAuthorizationOptions authOptions = UNAuthorizationOptionAlert |
      UNAuthorizationOptionSound | UNAuthorizationOptionBadge;
      [[UNUserNotificationCenter currentNotificationCenter]
      requestAuthorizationWithOptions:authOptions
      completionHandler:^(BOOL granted, NSError * _Nullable error) {
      // ...
      }];
      } else {
      // iOS 10 notifications aren't available; fall back to iOS 8-9 notifications.
      UIUserNotificationType allNotificationTypes =
      (UIUserNotificationTypeSound | UIUserNotificationTypeAlert | UIUserNotificationTypeBadge);
      UIUserNotificationSettings *settings =
      [UIUserNotificationSettings settingsForTypes:allNotificationTypes categories:nil];
      [application registerUserNotificationSettings:settings];
      }
    
      [application registerForRemoteNotifications];
    
      // ...
      return YES;
}

- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
      completionHandler(UIBackgroundFetchResultNewData);
  }

- (void)userNotificationCenter:(UNUserNotificationCenter *)center
      willPresentNotification:(UNNotification *)notification
      withCompletionHandler:(void (^)(UNNotificationPresentationOptions))completionHandler { 
      completionHandler(UNNotificationPresentationOptionSound | UNNotificationPresentationOptionBadge | UNNotificationPresentationOptionAlert);
  }

- (void)userNotificationCenter:(UNUserNotificationCenter *)center
      didReceiveNotificationResponse:(UNNotificationResponse *)response
      withCompletionHandler:(void(^)(void))completionHandler {
      completionHandler();
  }
 
- (void)messaging:(FIRMessaging *)messaging didReceiveRegistrationToken:(NSString *)fcmToken {
  NSDictionary *dataDict = [NSDictionary dictionaryWithObject:fcmToken forKey:@"token"];
  [[NSNotificationCenter defaultCenter] postNotificationName:
  @"FCMToken" object:nil userInfo:dataDict];
  }

- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error {
  NSLog(@"Unable to register for remote notifications: %@", error);
  }

- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
  }

// ...

@end

Import

import PushService from "@setrow/setrow-rn-push";

Usage

You should first call the init function and pass the required parameters in an object like below:

PushService.init({
          apiKey: '<YOUR_SETROW_API_KEY>',  // Required
          bundleId: '<YOUR_BUNDLE_ID>',     // Optional
          userEmail: '',                    // Optional
          callbackAfterTap: function (data) {
            // Optional
            // Here, you can process the data you set when creating the notification
            // For example, you can do stuff like navigation accroding to data object
          }
        })
          .then((res) => {
            // Everything is up and running! You can now proceed to subscribe your users like below:
            PushService.requestPermissionAndGetToken().then(token => console.log(token)).catch(err => console.log(err));
          })
          .catch(err => console.log('Can\'t initiate the push service.', err))

Also, you should register the background handler in your index.js like the following:

// some other imports here...
import {backgroundMessaging} from './setrow-rn-push'; // <-- Import the backgroundMessaging function using destructuring

// Current main application
AppRegistry.registerComponent(appName, () => App);
// New task registration
AppRegistry.registerHeadlessTask('RNFirebaseBackgroundMessage', () => backgroundMessaging); // <-- Add this line

Example

import React, { useEffect , useState} from 'react';
import {Alert, StyleSheet, View, Switch} from 'react-native';
import PushService from '@setrow/setrow-rn-push';

export default App = () => {
  const [isSubscribed, setIsSubscribed] = useState(false);

  useEffect(() => {
    PushService.init({
      apiKey: '<YOUR_SETROW_API_KEY>'
    })
      .then(async (res) => {
        setIsSubscribed(await PushService.checkIfSubscribed());
        await PushService.sendUserLog();
      })
      .catch(err => console.log('Can\'t initiate the push service.', err))
  }, []);

  const styles = StyleSheet.create({
    container: {
      flex: 1,
      justifyContent: 'center',
      alignItems: 'center',
      backgroundColor: '#F5FCFF'
    },
    modules: {
      margin: 5
    }
  });

  return (
    <View style={styles.container}>
      <View style={styles.modules}>
        <Switch onValueChange = {(newValue) => {
          if(newValue) {
            PushService.requestPermissionAndGetToken()
            .then(res => Alert.alert('Result', res))
            .catch(err => Alert.alert('Error', err))
          }else {
            PushService.unsubscribe()
              .then(res => console.log("Unsubscribed"))
              .catch(err => console.log("Error when unsubscribing"))
          }
          setIsSubscribed(newValue);
        }} value = {isSubscribed}/>
      </View>
    </View>
  );
}

API

Table of Contents

SetrowRNPush

React Native Push Notification Service for Setrow Customers

init

Initiate Push Notification Service

Parameters

  • config {object} Config object
    • config.apiKey {String} Your Setrow API Key
    • config.userEmail {String} Device user's email (optional, default '')
    • config.bundleId {String} Your iOS Bundle ID (optional, default '')
    • config.callbackAfterTap {function} The callback to run after notification tap (optional, default function(){})

Returns Promise<R>

setEmail

Set email for current user

Parameters

  • email {string} Email

Returns Promise<R>

setCallback

Set callback to run after notification tappings

Parameters

  • callback {function}

Returns Promise<R>

validateEmail

Validate email

Parameters

  • email {string} Email

Returns boolean

requestPermissionAndGetToken

Subscribe the user. Request permission for notifications and get FCM Token as promise resolves.

Returns Promise<string> Resolves with FCM Token

checkPermission

Check whether the user has permission for notifications or not.

Returns Promise<string>

requestPermission

Request permission for notifications

Returns Promise<string>

getToken

Retrieve FCM token for current subscription. Note that this function should be called after permission request

Returns Promise<R> Resolves with FCM Token on success

checkExternalStoragePermission

Check the permission for external storage access

Returns Promise<string>

sendRequest

Make request to a URL specified

Parameters

  • url {string}
  • headers {Object}
  • body {Object}
  • method {string} (optional, default 'POST')

Returns Promise<R>

requestFCMEndpoint

Send notification to user.

Parameters

Returns Promise<R>

getDeviceInfo

Get device information

Returns Promise<R> Resolves with device info object

displayLocalNotification

Display notification. For Android, dataOnly value must be set to true.

Parameters

  • notification Notification {Notification}
  • dataOnly {boolean} (optional, default false)

unsubscribe

Unsubscribe the user

Returns Promise<R>

checkIfSubscribed

Check if the user is subscribed or not

Returns boolean

goToNotificationSettings

iOS Only! - Open notification settings for the app. BundleID should be set first.

Returns Promise<void>

createListeners

Create the event-listeners to handle notification displays/taps

sendUserLog

Saves the user's app opening time

backgroundMessaging

Background Messaging Task

Parameters

  • message RemoteMessage {RemoteMessage} FCM message

Returns Promise<resolve>