Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions e2e/ios-simulator-notifications/RNNotifications.apns
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"Simulator Target Bundle": "org.reactjs.native.example.NotificationsExampleApp",
"aps": {
"content-available": 1,
"sound": "",
},
"link": "link"
}
40 changes: 40 additions & 0 deletions e2e/mock-server/MockNotificationServer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/* eslint no-console:off */
const express = require('express');
const bodyParser = require('body-parser');

const {MockNotificationsServerPort} = require("./consts");

class MockNotificationServer {
init({port = MockNotificationsServerPort}) {
this.cleanup();
this.app = express();
this.app.use(bodyParser.json());
this.app.get('/', (_, res) => {console.log('server is working'), res.send('ok')});
this.app.post('/register', this.onRegiscribe.bind(this));
this.app.post('/unregister', this.onUnsubscribe.bind(this));
this.server = this.app.listen(port);
console.log(`Mock Notification Server: listening on localhost port ${port}`);
}
cleanup() {
this.reset();
if (this.server) {
this.server.close();
this.server = undefined;
}
}
reset() {
this.lastRegiscribe = {};
this.lastUnsubscribe = {};
}
onRegiscribe(req, res) {
this.lastRegiscribe = req;
res.json({
});
}
onUnsubscribe(req, res) {
this.lastUnsubscribe = req;
res.send('ok');
}
}

new MockNotificationServer().init({});
3 changes: 3 additions & 0 deletions e2e/mock-server/consts.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module.exports = {
MockNotificationsServerPort: 2469,
};
212 changes: 212 additions & 0 deletions example/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,212 @@
import React, {useState, useEffect} from 'react';
import {
AppRegistry,
StyleSheet,
View,
Text,
Button,
Platform,
} from 'react-native';
import {
Notifications,
NotificationAction,
NotificationCategory,
NotificationBackgroundFetchResult,
Notification,
} from '../lib/src';

function NotificationsExampleApp() {
const [notifications, setNotifications] = useState<Notification[]>([]);
const [openedNotifications, setOpenedNotifications] = useState<Notification[]>([]);

useEffect(() => {
registerNotificationEvents();
setCategories();
getInitialNotifaction();
}, [])

const registerNotificationEvents = () => {
Notifications.events().registerNotificationReceivedForeground((notification, completion) => {
setNotifications([...notifications, notification]);
completion({alert: notification.payload.showAlert, sound: false, badge: false});
});

Notifications.events().registerNotificationOpened((notification, completion) => {
console.log({notification});
completion();
});

Notifications.events().registerNotificationReceivedBackground((notification, completion) => {
completion(NotificationBackgroundFetchResult.NO_DATA);
});

if (Platform.OS === 'ios') {
Notifications.ios.events().appNotificationSettingsLinked(() => {
console.warn('App Notification Settings Linked')
});
}
}

const requestPermissionsIos = (options) => {
Notifications.ios.registerRemoteNotifications(
Object.fromEntries(options.map(opt => [opt, true]))
);
}

const requestPermissions = () => {
Notifications.registerRemoteNotifications();
}

const setCategories = () => {
const upvoteAction = new NotificationAction(
'UPVOTE_ACTION',
'background',
String.fromCodePoint(0x1F44D),
false,
);

const replyAction = new NotificationAction(
'REPLY_ACTION',
'background',
'Reply',
true,
{
buttonTitle: 'Reply now',
placeholder: 'Insert message'
},
);


const category = new NotificationCategory(
'SOME_CATEGORY',
[upvoteAction, replyAction]
);

Notifications.setCategories([category]);
}

const sendLocalNotification = () => {
Notifications.postLocalNotification({
identifier: '0',
body: 'Local notification!',
title: 'Local Notification Title',
sound: 'chime.aiff',
badge: 0,
type: '',
thread: '',
payload: {
category: 'SOME_CATEGORY',
link: 'localNotificationLink',
android_channel_id: 'my-channel',
}
});
}

const removeAllDeliveredNotifications = () => {
Notifications.removeAllDeliveredNotifications();
}

const setNotificationChannel = () => {
Notifications.setNotificationChannel({
channelId: 'my-channel',
name: 'My Channel',
groupId: 'my-group-id',
groupName: 'my group name',
importance: 5,
description: 'My Description',
enableLights: true,
enableVibration: true,
showBadge: true,
soundFile: 'doorbell.mp3',
vibrationPattern: [200, 1000, 500, 1000, 500],
})
}

const getInitialNotifaction = async () => {
const initialNotification = await Notifications.getInitialNotification();
if (initialNotification) {
setOpenedNotifications([initialNotification, ...openedNotifications]);
}
}

const renderNotification = (notification) => {
return (
<View style={{backgroundColor: 'lightgray', margin: 10}}>
<Text>{`Title: ${notification.title}`}</Text>
<Text>{`Body: ${notification.body}`}</Text>
<Text>{`Extra Link Param: ${notification.payload.link}`}</Text>
</View>
);
}

const renderOpenedNotification = (notification) => {
return (
<View style={{backgroundColor: 'lightgray', margin: 10}}>
<Text>{`Title: ${notification.title}`}</Text>
<Text>{`Body: ${notification.body}`}</Text>
<Text>{`Notification Clicked: ${notification.payload.link}`}</Text>
</View>
);
}

const checkPermissions = () => {
Notifications.ios.checkPermissions().then((currentPermissions) => {
console.warn(currentPermissions);
});
}

const isRegistered = () => {
Notifications.isRegisteredForRemoteNotifications().then((registered) => {
console.warn(registered);
});
}

return (
<View style={styles.container}>
<Button title={'Request permissions'} onPress={requestPermissions} testID={'requestPermissions'} />
{Platform.OS === 'ios' && Platform.Version > '12.0' && (<>
<Button title={'Request permissions with app notification settings'} onPress={() => requestPermissionsIos(['providesAppNotificationSettings'])} testID={'requestPermissionsWithAppSettings'} />
<Button title={'Request permissions with provisional'} onPress={() => requestPermissionsIos(['provisional'])} testID={'requestPermissionsWithAppSettings'} />
<Button title={'Request permissions with app notification settings and provisional'} onPress={() => requestPermissionsIos(['providesAppNotificationSettings', 'provisional'])} testID={'requestPermissionsWithAppSettings'} />
<Button title={'Check permissions'} onPress={checkPermissions} />
</>)}
{Platform.OS === 'android' &&
<Button title={'Set channel'} onPress={setNotificationChannel} testID={'setNotificationChannel'} />
}
<Button title={'Send local notification'} onPress={sendLocalNotification} testID={'sendLocalNotification'} />
<Button title={'Remove all delivered notifications'} onPress={removeAllDeliveredNotifications} />
<Button title={'Check registeration'} onPress={isRegistered} />
{notifications.map((notification, idx) => (
<View key={`notification_${idx}`}>
{renderNotification(notification)}
</View>
))}
{openedNotifications.map((notification, idx) => (
<View key={`notification_${idx}`}>
{renderOpenedNotification(notification)}
</View>
))}
</View>
);
}

const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF',
},
welcome: {
fontSize: 20,
textAlign: 'center',
margin: 10,
},
instructions: {
textAlign: 'center',
color: '#333333',
marginBottom: 5,
},
});

AppRegistry.registerComponent('NotificationsExampleApp', () => NotificationsExampleApp);
23 changes: 19 additions & 4 deletions example/ios/NotificationsExampleApp.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,13 @@
13B07FBD1A68108700A75B9A /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB11A68108700A75B9A /* LaunchScreen.xib */; };
13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; };
13B07FC11A68108700A75B9A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; };
3CF8BF3027B500E2001D69BA /* libPods-NotificationsExampleApp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 3CF8BF2F27B500E2001D69BA /* libPods-NotificationsExampleApp.a */; };
5004AC02233BE75A00490132 /* CallKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5004ABE1233BE75A00490132 /* CallKit.framework */; };
50ABBFF224B329CA00077ED8 /* RNNotificationsTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 50ABBFD824B3294200077ED8 /* RNNotificationsTests.m */; };
50ABC01424B32ABE00077ED8 /* RNNotificationsStoreTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 50ABBFD924B3294200077ED8 /* RNNotificationsStoreTests.m */; };
50ABC01524B32ABE00077ED8 /* RNNotificationEventHandlerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 50ABBFDA24B3294200077ED8 /* RNNotificationEventHandlerTests.m */; };
50ABC02D24B32C6A00077ED8 /* RNCommandsHandlerIntegrationTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 50ABC02C24B32C6A00077ED8 /* RNCommandsHandlerIntegrationTest.m */; };
86B6E1FE34FA8D2D24E5AAD4 /* libPods-NotificationsExampleAppTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = B1FB78C4C15FDF7AC821B216 /* libPods-NotificationsExampleAppTests.a */; };
A602BC62970AAC3CABB3FC9E /* libPods-NotificationsExampleApp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = B08A38CF5037E07CAB47E42F /* libPods-NotificationsExampleApp.a */; };
D84861182267695100E9103D /* JavaScriptCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D84861172267695100E9103D /* JavaScriptCore.framework */; };
/* End PBXBuildFile section */

Expand Down Expand Up @@ -271,6 +271,7 @@
13B07FB71A68108700A75B9A /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = NotificationsExampleApp/main.m; sourceTree = "<group>"; };
146833FF1AC3E56700842450 /* React.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = React.xcodeproj; path = "../../node_modules/react-native/React/React.xcodeproj"; sourceTree = "<group>"; };
33D24DE18AC038B943B8CBC8 /* Pods-NotificationsExampleApp.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NotificationsExampleApp.debug.xcconfig"; path = "Target Support Files/Pods-NotificationsExampleApp/Pods-NotificationsExampleApp.debug.xcconfig"; sourceTree = "<group>"; };
3CF8BF2F27B500E2001D69BA /* libPods-NotificationsExampleApp.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; path = "libPods-NotificationsExampleApp.a"; sourceTree = BUILT_PRODUCTS_DIR; };
5004ABE1233BE75A00490132 /* CallKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CallKit.framework; path = System/Library/Frameworks/CallKit.framework; sourceTree = SDKROOT; };
50ABBFD824B3294200077ED8 /* RNNotificationsTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNNotificationsTests.m; sourceTree = "<group>"; };
50ABBFD924B3294200077ED8 /* RNNotificationsStoreTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNNotificationsStoreTests.m; sourceTree = "<group>"; };
Expand All @@ -296,8 +297,8 @@
buildActionMask = 2147483647;
files = (
5004AC02233BE75A00490132 /* CallKit.framework in Frameworks */,
3CF8BF3027B500E2001D69BA /* libPods-NotificationsExampleApp.a in Frameworks */,
D84861182267695100E9103D /* JavaScriptCore.framework in Frameworks */,
A602BC62970AAC3CABB3FC9E /* libPods-NotificationsExampleApp.a in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down Expand Up @@ -485,6 +486,7 @@
D84860E82267695100E9103D /* Frameworks */ = {
isa = PBXGroup;
children = (
3CF8BF2F27B500E2001D69BA /* libPods-NotificationsExampleApp.a */,
5004ABE1233BE75A00490132 /* CallKit.framework */,
D84861172267695100E9103D /* JavaScriptCore.framework */,
B08A38CF5037E07CAB47E42F /* libPods-NotificationsExampleApp.a */,
Expand Down Expand Up @@ -554,6 +556,10 @@
LastUpgradeCheck = 0810;
ORGANIZATIONNAME = Facebook;
TargetAttributes = {
13B07F861A680F5B00A75B9A = {
DevelopmentTeam = R3D7545769;
LastSwiftMigration = 1320;
};
50ABBFE724B3299900077ED8 = {
CreatedOnToolsVersion = 11.2.1;
ProvisioningStyle = Automatic;
Expand Down Expand Up @@ -1015,9 +1021,10 @@
baseConfigurationReference = 33D24DE18AC038B943B8CBC8 /* Pods-NotificationsExampleApp.debug.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = 1;
DEAD_CODE_STRIPPING = NO;
DEVELOPMENT_TEAM = "";
DEVELOPMENT_TEAM = R3D7545769;
HEADER_SEARCH_PATHS = (
"$(inherited)",
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
Expand All @@ -1034,6 +1041,9 @@
);
PRODUCT_BUNDLE_IDENTIFIER = org.reactjs.native.example.NotificationsExampleApp;
PRODUCT_NAME = NotificationsExampleApp;
SWIFT_OBJC_BRIDGING_HEADER = "NotificationsExampleApp-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
VERSIONING_SYSTEM = "apple-generic";
};
Expand All @@ -1044,8 +1054,9 @@
baseConfigurationReference = 716C1316CDE92F3D079D7F77 /* Pods-NotificationsExampleApp.release.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_TEAM = "";
DEVELOPMENT_TEAM = R3D7545769;
HEADER_SEARCH_PATHS = (
"$(inherited)",
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
Expand All @@ -1062,6 +1073,8 @@
);
PRODUCT_BUNDLE_IDENTIFIER = org.reactjs.native.example.NotificationsExampleApp;
PRODUCT_NAME = NotificationsExampleApp;
SWIFT_OBJC_BRIDGING_HEADER = "NotificationsExampleApp-Bridging-Header.h";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
VERSIONING_SYSTEM = "apple-generic";
};
Expand All @@ -1086,8 +1099,10 @@
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development";
CODE_SIGN_STYLE = Automatic;
DEBUG_INFORMATION_FORMAT = dwarf;
DEVELOPMENT_TEAM = "";
GCC_C_LANGUAGE_STANDARD = gnu11;
INFOPLIST_FILE = NotificationsExampleAppTests/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 13.2;
Expand Down
Loading