RN Native Module Setup
This guide shows how to pass data from the Android Notification Service Extension Native Java class to React Native.
This follows upon concepts listed in the React Native Docs:
- Native Android Modules: https://reactnative.dev/docs/native-modules-android
- Native iOS Modules: https://reactnative.dev/docs/native-modules-ios
Jump to:
Android Notification Service Extension Module
Let's create a native module, NotificationServiceExtensionModule
, that will allow you to pass Notification Data received in the Android’s Notification APIs to JavaScript while the app is running but not in focus.
Requirements
You must have setup the Android Notification Service Extension before continuing with this integration.
Will not work if app is not running in the background or foreground.
If the app is swiped away, the React Native Module will not be initialized so the notification data within the NotificationServiceExtension cannot bridge into React Native.
Create a Notification Service Extension Module
Create the NotificationServiceExtensionModule.java
Java file inside android/app/src/main/java/com/your-app-name/
folder. This Java file will contain your native module Java class.
Add the following code:
package com.your-app-name; // replace com.your-app-name with your app’s name
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import java.util.Map;
import java.util.HashMap;
import android.util.Log;
public class NotificationServiceExtensionModule extends ReactContextBaseJavaModule {
NotificationServiceExtensionModule(ReactApplicationContext context) {
super(context);
}
@Override
public String getName() {
return "NotificationServiceExtensionModule";
}
@ReactMethod
public void createNotificationServiceExtensionEvent(String name) {
Log.d("NotificationServiceExtensionModule", "Create event called with name: " + name);
}
}
Register the Module (Android Specific)
Add your Native Module to ReactPackage
by creating a new Java Class named MyAppPackage.java
that implements ReactPackage
inside the android/app/src/main/java/com/your-app-name/
folder:
Then add the following content:
package com.your-app-name; // replace your-app-name with your app’s name
import com.facebook.react.ReactPackage;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.uimanager.ViewManager;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class MyAppPackage implements ReactPackage {
@Override
public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
return Collections.emptyList();
}
@Override
public List<NativeModule> createNativeModules(
ReactApplicationContext reactContext) {
List<NativeModule> modules = new ArrayList<>();
modules.add(new NotificationServiceExtensionModule(reactContext));
return modules;
}
}
To register the NotificationServiceExtensionModule
package, you must add MyAppPackage
to the list of packages returned in ReactNativeHost's getPackages()
method. Open up your MainApplication.java
file, which can be found in the following path: android/app/src/main/java/com/your-app-name/MainApplication.java
Locate ReactNativeHost’s getPackages()
method and add your package to the packages list getPackages()
returns:
@Override
protected List<ReactPackage> getPackages() {
@SuppressWarnings("UnnecessaryLocalVariable")
List<ReactPackage> packages = new PackageList(this).getPackages();
// below MyAppPackage is added to the list of packages returned
packages.add(new MyAppPackage());
return packages;
}
Sending Events to Javascript
The below instructions pick up from the React Native Docs: https://reactnative.dev/docs/native-modules-android#sending-events-to-javascript
Update the NotificationServiceExtensionModule.java
to include the event emitter
package com.your-app-name; // replace your-app-name with your app’s name
import androidx.annotation.Nullable;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import java.util.Map;
import java.util.HashMap;
import android.util.Log;
import com.facebook.react.modules.core.DeviceEventManagerModule;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.bridge.Arguments;
public class NotificationServiceExtensionModule extends ReactContextBaseJavaModule {
public static NotificationServiceExtensionModule instance;
NotificationServiceExtensionModule(ReactApplicationContext context) {
super(context);
instance = this;
}
@Override
public String getName() {
return "NotificationServiceExtensionModule";
}
@ReactMethod
public void createNotificationServiceExtensionEvent(String name) {
Log.d("NotificationServiceExtensionModule", "Create event called with name: " + name);
}
private void sendEvent(ReactContext reactContext, String eventName, @Nullable WritableMap params) {
reactContext
.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
.emit(eventName, params);
}
public void emitNotificationEvent() {
Log.i("OneSignalExample", "Emit Notification Event");
WritableMap params = Arguments.createMap();
params.putString("eventProperty", "someValue");
sendEvent(getReactApplicationContext(), "NotificationEvent", params);
}
}
Update the NotificationServiceExtension.java
file to add:
package com.your-app-name; // replace your-app-name with your app’s name
import android.content.Context;
import android.util.Log;
import org.json.JSONObject;
import com.onesignal.OSNotification;
import com.onesignal.OSMutableNotification;
import com.onesignal.OSNotificationReceivedEvent;
import com.onesignal.OneSignal.OSRemoteNotificationReceivedHandler;
import com.your-app-name.NotificationServiceExtensionModule;
@SuppressWarnings("unused")
public class NotificationServiceExtension implements OSRemoteNotificationReceivedHandler {
@Override
public void remoteNotificationReceived(Context context, OSNotificationReceivedEvent notificationReceivedEvent) {
OSNotification notification = notificationReceivedEvent.getNotification();
// Example of modifying the notification's accent color
OSMutableNotification mutableNotification = notification.mutableCopy();
mutableNotification.setExtender(builder -> builder.setColor(context.getResources().getColor(R.color.colorPrimary)));
JSONObject data = notification.getAdditionalData();
Log.i("OneSignalExample", "Received Notification Data: " + data);
if (NotificationServiceExtensionModule.instance != null ) {
NotificationServiceExtensionModule.instance.emitNotificationEvent();
}
// If complete isn't call within a time period of 25 seconds, OneSignal internal logic will show the original notification
// To omit displaying a notification, pass `null` to complete()
notificationReceivedEvent.complete(mutableNotification);
}
}
In your Javascript App.js
file include:
// Used to access data from NotificationServiceExtension
import { NativeEventEmitter, NativeModules } from 'react-native';
// sending events to Javascript: https://reactnative.dev/docs/native-modules-android#sending-events-to-javascript
const eventEmitter = new
NativeEventEmitter(NativeModules.NotificationServiceExtensionModule);
this.eventListener = eventEmitter.addListener('NotificationEvent', (event) => {
console.log("NotificationEvent Received In JS: ", event.eventProperty)// "someValue"
});
iOS Notification Service Extension Module
Let's create a native module, NotificationServiceExtensionModule
, that will allow you to pass Notification Data received in the iOS's Notification APIs to JavaScript while the app is running but not in focus.
Requirements
You must have setup the iOS Notification Service Extension as directed in the React Native & Expo SDK Setup guide you followed when adding OneSiganl before continuing with this integration.
Will not work if app is not running in the background or foreground.
If the app is swiped away, the React Native Module will not be initialized so the notification data within the NotificationServiceExtension cannot bridge into React Native.
Create a Notification Service Extension Module
In Xcode, open your app's xcworkspace
file. Right click the main project folder and create a new Objective-C h file called NotificationServiceExtensionModule
The NotificationServiceExtensionModule.h
file should contain this code.
#import <foundation/Foundation.h>
// NotificationServiceExtensionModule.h
#import <React/RCTBridgeModule.h>
#import <React/RCTEventEmitter.h>
@interface NotificationServiceExtensionModule : RCTEventEmitter <RCTBridgeModule>
+ (NotificationServiceExtensionModule*) sharedInstance;
- (void)emitNotificationEvent:(NSDictionary *)userInfo;
@end
Within the same root project folder. Create an Objective-C .m
file called NotificationServiceExtensionModule
.
The NotificationServiceExtensionModule.m
file should look like this:
#import <Foundation/Foundation.h>
// NotificationServiceExtensionModule.m
#import "NotificationServiceExtensionModule.h"
@implementation NotificationServiceExtensionModule
static NotificationServiceExtensionModule* _instance = nil;
+(NotificationServiceExtensionModule*) sharedInstance {
// @synchronized( _instance ) {
// if( !_instance ) {
// _instance = [[NotificationServiceExtensionModule alloc] init];
// }
// }
return _instance;
}
// To export a module named NotificationServiceExtensionModule
RCT_EXPORT_MODULE();
- (NSArray<NSString *> *)supportedEvents
{
NSLog(@"Supported EVENTS__________________________");
_instance = self;
return @[@"NotificationEvent"];
}
- (void)emitNotificationEvent:(NSDictionary *)userInfo
{
NSString *eventName = userInfo[@"aps"];
[self sendEventWithName:@"NotificationEvent" body:@{@"aps": eventName}];
}
@end
Sending Events to Javascript
Update AppDelegate to use NotificationServiceExtensionModule to send event to JavaScript
Your AppDelegate.h
file should look something like this:
#import <Foundation/Foundation.h>
#import <EXUpdates/EXUpdatesAppController.h>
#import <React/RCTBridgeDelegate.h>
#import <UIKit/UIKit.h>
#import <UserNotifications/UserNotifications.h>
#import <UMCore/UMAppDelegateWrapper.h>
@interface AppDelegate : UMAppDelegateWrapper <UIApplicationDelegate, RCTBridgeDelegate, EXUpdatesAppControllerDelegate>
@end
Your AppDelegate.m
file should implement the didReceiveRemoteNotification
method like this:
#import "NotificationServiceExtensionModule.h"
//Other AppDelegate code ...at bottom before @end place
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
{
//access NotificationServiceExtensionModule emitNotificationEvent method
[NotificationServiceExtensionModule.sharedInstance emitNotificationEvent:userInfo ];
completionHandler(UIBackgroundFetchResultNoData);
}
In your Javascript App.js
file include (same as the Android setup):
// Used to access data from NotificationServiceExtension
import { NativeEventEmitter, NativeModules } from 'react-native';
// sending events to Javascript: https://reactnative.dev/docs/native-modules-android#sending-events-to-javascript
const eventEmitter = new NativeEventEmitter(NativeModules.NotificationServiceExtensionModule);
this.eventListener = eventEmitter.addListener('NotificationEvent', (event) => {
console.log("NotificationEvent Received In JS: ", event.eventProperty) // "someValue"
});
Done!
Make sure to send push with
content_available
to wake the app when it is in the background.
Updated almost 4 years ago