From 89d5ce73dbc7eb2fb273b9b6bae17535124065db Mon Sep 17 00:00:00 2001 From: danielel Date: Mon, 14 Feb 2022 13:01:03 +0200 Subject: [PATCH 1/2] fix registerNotificationReceivedBackground --- .../RNNotifications.apns | 8 ++++ e2e/mock-server/MockNotificationServer.js | 40 +++++++++++++++++++ e2e/mock-server/consts.js | 3 ++ .../project.pbxproj | 23 +++++++++-- .../ios/NotificationsExampleApp/AppDelegate.m | 9 +++-- .../ios/NotificationsExampleApp/Info.plist | 6 +++ lib/ios/RNNotifications.h | 1 + lib/ios/RNNotifications.m | 4 ++ package.json | 4 ++ 9 files changed, 90 insertions(+), 8 deletions(-) create mode 100644 e2e/ios-simulator-notifications/RNNotifications.apns create mode 100644 e2e/mock-server/MockNotificationServer.js create mode 100644 e2e/mock-server/consts.js 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/ios/NotificationsExampleApp.xcodeproj/project.pbxproj b/example/ios/NotificationsExampleApp.xcodeproj/project.pbxproj index fa43202a8..7278ce72a 100644 --- a/example/ios/NotificationsExampleApp.xcodeproj/project.pbxproj +++ b/example/ios/NotificationsExampleApp.xcodeproj/project.pbxproj @@ -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 */ @@ -271,6 +271,7 @@ 13B07FB71A68108700A75B9A /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = NotificationsExampleApp/main.m; sourceTree = ""; }; 146833FF1AC3E56700842450 /* React.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = React.xcodeproj; path = "../../node_modules/react-native/React/React.xcodeproj"; sourceTree = ""; }; 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 = ""; }; + 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 = ""; }; 50ABBFD924B3294200077ED8 /* RNNotificationsStoreTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNNotificationsStoreTests.m; sourceTree = ""; }; @@ -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; }; @@ -485,6 +486,7 @@ D84860E82267695100E9103D /* Frameworks */ = { isa = PBXGroup; children = ( + 3CF8BF2F27B500E2001D69BA /* libPods-NotificationsExampleApp.a */, 5004ABE1233BE75A00490132 /* CallKit.framework */, D84861172267695100E9103D /* JavaScriptCore.framework */, B08A38CF5037E07CAB47E42F /* libPods-NotificationsExampleApp.a */, @@ -554,6 +556,10 @@ LastUpgradeCheck = 0810; ORGANIZATIONNAME = Facebook; TargetAttributes = { + 13B07F861A680F5B00A75B9A = { + DevelopmentTeam = R3D7545769; + LastSwiftMigration = 1320; + }; 50ABBFE724B3299900077ED8 = { CreatedOnToolsVersion = 11.2.1; ProvisioningStyle = Automatic; @@ -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, @@ -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"; }; @@ -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, @@ -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"; }; @@ -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; diff --git a/example/ios/NotificationsExampleApp/AppDelegate.m b/example/ios/NotificationsExampleApp/AppDelegate.m index 4204bd318..519a7ff00 100644 --- a/example/ios/NotificationsExampleApp/AppDelegate.m +++ b/example/ios/NotificationsExampleApp/AppDelegate.m @@ -8,7 +8,8 @@ @implementation AppDelegate -- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { +- (BOOL)application:(UIApplication *)application willFinishLaunchingWithOptions:(NSDictionary *)launchOptions { + [RNNotifications startMonitorNotifications]; NSURL *jsCodeLocation; jsCodeLocation = [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index" fallbackResource:nil]; @@ -24,8 +25,7 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:( rootViewController.view = rootView; self.window.rootViewController = rootViewController; [self.window makeKeyAndVisible]; - - [RNNotifications startMonitorNotifications]; + return YES; } @@ -38,7 +38,8 @@ - (void)application:(UIApplication *)application didFailToRegisterForRemoteNotif [RNNotifications didFailToRegisterForRemoteNotificationsWithError:error]; } -- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult result))completionHandler { +- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult result))completionHandler { + NSLog(@"didReceiveRemoteNotification"); [RNNotifications didReceiveBackgroundNotification:userInfo withCompletionHandler:completionHandler]; } diff --git a/example/ios/NotificationsExampleApp/Info.plist b/example/ios/NotificationsExampleApp/Info.plist index 3e5fb7187..4374c1a02 100644 --- a/example/ios/NotificationsExampleApp/Info.plist +++ b/example/ios/NotificationsExampleApp/Info.plist @@ -35,6 +35,12 @@ NSLocationWhenInUseUsageDescription + UIBackgroundModes + + fetch + processing + remote-notification + UILaunchStoryboardName LaunchScreen UIRequiredDeviceCapabilities diff --git a/lib/ios/RNNotifications.h b/lib/ios/RNNotifications.h index 416786f26..597191343 100644 --- a/lib/ios/RNNotifications.h +++ b/lib/ios/RNNotifications.h @@ -11,6 +11,7 @@ + (void)startMonitorPushKitNotifications; + (void)didReceiveBackgroundNotification:(NSDictionary *)userInfo withCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler; ++ (void)didReceiveBackgroundNotification:(NSDictionary *)userInfo; + (void)didRegisterForRemoteNotificationsWithDeviceToken:(id)deviceToken; + (void)didFailToRegisterForRemoteNotificationsWithError:(NSError *)error; diff --git a/lib/ios/RNNotifications.m b/lib/ios/RNNotifications.m index 205808da6..520f6380e 100644 --- a/lib/ios/RNNotifications.m +++ b/lib/ios/RNNotifications.m @@ -45,6 +45,10 @@ + (void)didReceiveBackgroundNotification:(NSDictionary *)userInfo withCompletion [[self sharedInstance] didReceiveBackgroundNotification:userInfo withCompletionHandler:completionHandler]; } ++ (void)didReceiveBackgroundNotification:(NSDictionary *)userInfo { + +} + + (void)didRegisterForRemoteNotificationsWithDeviceToken:(id)deviceToken { [[self sharedInstance] didRegisterForRemoteNotificationsWithDeviceToken:deviceToken]; } diff --git a/package.json b/package.json index 54a935476..96be37ee2 100644 --- a/package.json +++ b/package.json @@ -58,6 +58,7 @@ "@types/react-test-renderer": "16.9.2", "babel-eslint": "10.0.3", "detox": "^17.5.7", + "express": "^4.17.2", "github-release-notes": "https://github.com/yogevbd/github-release-notes/tarball/e601b3dba72dcd6cba323c1286ea6dd0c0110b58", "jest": "24.9.0", "lodash": "4.17.21", @@ -130,5 +131,8 @@ "text", "html" ] + }, + "dependencies": { + "body-parser": "^1.19.1" } } From 2afc5df65e4e24a0bc6d49400d99cd90aaf5b61c Mon Sep 17 00:00:00 2001 From: danielel Date: Mon, 14 Feb 2022 15:36:58 +0200 Subject: [PATCH 2/2] get opened notifications from getInitialNotification --- example/index.tsx | 212 +++++++++++++++++++++++++++++ website/docs/api/general-events.md | 1 + 2 files changed, 213 insertions(+) create mode 100644 example/index.tsx 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 ( + +