diff --git a/e2e/ios-simulator-notifications/RNNotifications.apns b/e2e/ios-simulator-notifications/RNNotifications.apns new file mode 100644 index 000000000..448edd1ea --- /dev/null +++ b/e2e/ios-simulator-notifications/RNNotifications.apns @@ -0,0 +1,8 @@ +{ + "Simulator Target Bundle": "org.reactjs.native.example.NotificationsExampleApp", + "aps": { + "content-available": 1, + "sound": "", + }, + "link": "link" +} diff --git a/e2e/mock-server/MockNotificationServer.js b/e2e/mock-server/MockNotificationServer.js new file mode 100644 index 000000000..366c947c8 --- /dev/null +++ b/e2e/mock-server/MockNotificationServer.js @@ -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({}); diff --git a/e2e/mock-server/consts.js b/e2e/mock-server/consts.js new file mode 100644 index 000000000..fb3f5477c --- /dev/null +++ b/e2e/mock-server/consts.js @@ -0,0 +1,3 @@ +module.exports = { + MockNotificationsServerPort: 2469, +}; diff --git a/example/index.tsx b/example/index.tsx new file mode 100644 index 000000000..01948418e --- /dev/null +++ b/example/index.tsx @@ -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([]); + const [openedNotifications, setOpenedNotifications] = useState([]); + + 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 ( + + {`Title: ${notification.title}`} + {`Body: ${notification.body}`} + {`Extra Link Param: ${notification.payload.link}`} + + ); + } + + const renderOpenedNotification = (notification) => { + return ( + + {`Title: ${notification.title}`} + {`Body: ${notification.body}`} + {`Notification Clicked: ${notification.payload.link}`} + + ); + } + + const checkPermissions = () => { + Notifications.ios.checkPermissions().then((currentPermissions) => { + console.warn(currentPermissions); + }); + } + + const isRegistered = () => { + Notifications.isRegisteredForRemoteNotifications().then((registered) => { + console.warn(registered); + }); + } + + return ( + +