diff --git a/native/ios/Comm.xcodeproj/project.pbxproj b/native/ios/Comm.xcodeproj/project.pbxproj --- a/native/ios/Comm.xcodeproj/project.pbxproj +++ b/native/ios/Comm.xcodeproj/project.pbxproj @@ -59,6 +59,8 @@ CB4821AC27CFB17C001AB7E1 /* Session.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 71BF5B6F26B3FF0900EDE27D /* Session.cpp */; }; CB4821AE27CFB187001AB7E1 /* Tools.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 71BF5B7326B401D300EDE27D /* Tools.cpp */; }; CB4821AF27CFB19D001AB7E1 /* PlatformSpecificTools.mm in Sources */ = {isa = PBXBuildFile; fileRef = 71762A74270D8AAE00F565ED /* PlatformSpecificTools.mm */; }; + CB7EF17E295C674300B17035 /* CommIOSNotifications.mm in Sources */ = {isa = PBXBuildFile; fileRef = CB7EF17D295C5D1800B17035 /* CommIOSNotifications.mm */; }; + CB7EF180295C674300B17035 /* CommIOSNotificationsBridgeQueue.mm in Sources */ = {isa = PBXBuildFile; fileRef = CB7EF17B295C580500B17035 /* CommIOSNotificationsBridgeQueue.mm */; }; CB90951F29534B32002F2A7F /* CommSecureStore.mm in Sources */ = {isa = PBXBuildFile; fileRef = 71D4D7CB26C50B1000FCDBCD /* CommSecureStore.mm */; }; CBDEC69B28ED867000C17588 /* GlobalDBSingleton.mm in Sources */ = {isa = PBXBuildFile; fileRef = CBDEC69A28ED867000C17588 /* GlobalDBSingleton.mm */; }; CBFE58292885852B003B94C9 /* ThreadOperations.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CBFE58282885852B003B94C9 /* ThreadOperations.cpp */; }; @@ -207,6 +209,7 @@ CB3C621327CE66540054F24C /* libEXSecureStore.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; path = libEXSecureStore.a; sourceTree = BUILT_PRODUCTS_DIR; }; CB7EF17B295C580500B17035 /* CommIOSNotificationsBridgeQueue.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = CommIOSNotificationsBridgeQueue.mm; path = Comm/CommIOSNotifications/CommIOSNotificationsBridgeQueue.mm; sourceTree = ""; }; CB7EF17C295C580500B17035 /* CommIOSNotificationsBridgeQueue.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = CommIOSNotificationsBridgeQueue.h; path = Comm/CommIOSNotifications/CommIOSNotificationsBridgeQueue.h; sourceTree = ""; }; + CB7EF17D295C5D1800B17035 /* CommIOSNotifications.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = CommIOSNotifications.mm; path = Comm/CommIOSNotifications/CommIOSNotifications.mm; sourceTree = ""; }; CB90951929531663002F2A7F /* CommIOSNotifications.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CommIOSNotifications.h; path = Comm/CommIOSNotifications/CommIOSNotifications.h; sourceTree = ""; }; CBDEC69928ED859600C17588 /* GlobalDBSingleton.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GlobalDBSingleton.h; sourceTree = ""; }; CBDEC69A28ED867000C17588 /* GlobalDBSingleton.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = GlobalDBSingleton.mm; path = Comm/GlobalDBSingleton.mm; sourceTree = ""; }; @@ -558,6 +561,7 @@ CB90951729531647002F2A7F /* CommIOSNotifications */ = { isa = PBXGroup; children = ( + CB7EF17D295C5D1800B17035 /* CommIOSNotifications.mm */, CB7EF17C295C580500B17035 /* CommIOSNotificationsBridgeQueue.h */, CB7EF17B295C580500B17035 /* CommIOSNotificationsBridgeQueue.mm */, CB90951929531663002F2A7F /* CommIOSNotifications.h */, @@ -923,6 +927,8 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + CB7EF17E295C674300B17035 /* CommIOSNotifications.mm in Sources */, + CB7EF180295C674300B17035 /* CommIOSNotificationsBridgeQueue.mm in Sources */, 7F0C6E31291C4468002AA2D9 /* ExpoModulesProvider.swift in Sources */, 75291F0428F9A0D400F4C80E /* DeviceID.cpp in Sources */, 8E43C32C291E5B4A009378F5 /* TerminateApp.mm in Sources */, diff --git a/native/ios/Comm/CommIOSNotifications/CommIOSNotifications.mm b/native/ios/Comm/CommIOSNotifications/CommIOSNotifications.mm new file mode 100644 --- /dev/null +++ b/native/ios/Comm/CommIOSNotifications/CommIOSNotifications.mm @@ -0,0 +1,183 @@ +#import "CommIOSNotifications.h" +#import "CommIOSNotificationsBridgeQueue.h" +#import "Logger.h" +#import +#import +#import +#import +#import + +/* + Internal Constants +*/ +NSString *const CommIOSNotificationsRegistered = + @"CommIOSNotificationsRegistered"; +NSString *const CommIOSNotificationsRegistrationFailed = + @"CommIOSNotificationsRegistrationFailed"; +NSString *const CommIOSNotificationsReceivedForeground = + @"CommIOSNotificationsReceivedForeground"; +NSString *const CommIOSNotificationsOpened = @"CommIOSNotificationsOpened"; + +@implementation CommIOSNotifications + +RCT_EXPORT_MODULE() + +@synthesize bridge = _bridge; + +- (void)setBridge:(RCTBridge *)bridge { + _bridge = bridge; + [CommIOSNotificationsBridgeQueue sharedInstance].openedRemoteNotification = + [_bridge.launchOptions + objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey]; +} + +- (void)stopObserving { + _hasListeners = NO; +} + +- (void)startObserving { + _hasListeners = YES; +} + +- (instancetype)init { + self = [super init]; + if (!self) { + return self; + } + _hasListeners = NO; + _remoteNotificationCallbacks = [NSMutableDictionary dictionary]; + [NSNotificationCenter.defaultCenter + addObserver:self + selector:@selector(handleNotificationsRegistered:) + name:CommIOSNotificationsRegistered + object:nil]; + + [NSNotificationCenter.defaultCenter + addObserver:self + selector:@selector(handleNotificationsRegistrationFailed:) + name:CommIOSNotificationsRegistrationFailed + object:nil]; + + [NSNotificationCenter.defaultCenter + addObserver:self + selector:@selector(handleNotificationReceivedForeground:) + name:CommIOSNotificationsReceivedForeground + object:nil]; + + [NSNotificationCenter.defaultCenter + addObserver:self + selector:@selector(handleNotificationOpened:) + name:CommIOSNotificationsOpened + object:nil]; + return self; +} + +- (void)dealloc { + [[NSNotificationCenter defaultCenter] removeObserver:self]; +} + +- (NSArray *)supportedEvents { + return @[ + @"remoteNotificationsRegistered", + @"remoteNotificationsRegistrationFailed", + @"notificationReceivedForeground", + @"notificationOpened" + ]; +} + +/* + JavaScript Events + */ +- (void)handleNotificationsRegistered:(NSNotification *)notification { + if (!_hasListeners) { + return; + } + [self sendEventWithName:@"remoteNotificationsRegistered" + body:notification.userInfo]; +} + +- (void)handleNotificationsRegistrationFailed:(NSNotification *)notification { + if (!_hasListeners) { + return; + } + [self sendEventWithName:@"remoteNotificationsRegistrationFailed" + body:notification.userInfo]; +} + +- (void)handleNotifInfo:(NSDictionary *)notifInfo withName:(NSString *)name { + NSDictionary *notification = notifInfo[@"notification"]; + NSString *notifID = notification[@"id"]; + + RCTRemoteNotificationCallback completionHandler = + notifInfo[@"completionHandler"]; + if (completionHandler && notifID) { + self.remoteNotificationCallbacks[notifID] = completionHandler; + } + + NSDictionary *jsReadableNotification = + [CommIOSNotifications parseNotificationToJSReadableObject:notification + withRequestIdentifier:nil]; + if (!jsReadableNotification) { + return; + } + + [self sendEventWithName:name body:jsReadableNotification]; +} + +- (void)handleNotificationReceivedForeground:(NSNotification *)sysNotif { + if (!_hasListeners) { + return; + } + [self handleNotifInfo:sysNotif.userInfo + withName:@"notificationReceivedForeground"]; +} + +- (void)handleNotificationOpened:(NSNotification *)sysNotif { + if (!_hasListeners) { + return; + } + [self handleNotifInfo:sysNotif.userInfo withName:@"notificationOpened"]; +} + +/* + Helper methods +*/ ++ (NSDictionary *)parseNotificationToJSReadableObject: + (NSDictionary *)notification + withRequestIdentifier:(NSString *)identifier { + NSMutableDictionary *jsReadableNotification = + [[NSMutableDictionary alloc] init]; + + static NSArray *obligatoryJSNotificationKeys = + @[ @"id", @"threadID" ]; + static NSArray *optionalJSNotificationKeys = + @[ @"body", @"title", @"messageInfos", @"prefix" ]; + + for (NSString *key in obligatoryJSNotificationKeys) { + if (!notification[key]) { + comm::Logger::log( + "Received malformed notification missing key: " + + std::string([key UTF8String])); + return nil; + } + jsReadableNotification[key] = notification[key]; + } + + for (NSString *key in optionalJSNotificationKeys) { + if (notification[key]) { + jsReadableNotification[key] = notification[key]; + } + } + + if (notification[@"aps"] && notification[@"aps"][@"alert"]) { + jsReadableNotification[@"message"] = notification[@"aps"][@"alert"]; + } + + if (identifier) { + jsReadableNotification[@"identifier"] = identifier; + } + + return jsReadableNotification; +} + +@end