[notifications] Refactor for better support of separate messages
This commit is contained in:
parent
831eec82f7
commit
303cb4c428
|
@ -39,8 +39,8 @@ static NSString *const MESSAGING_TOKEN_REFRESHED = @"messaging_token_refreshed";
|
||||||
static NSString *const MESSAGING_NOTIFICATION_RECEIVED = @"messaging_notification_received";
|
static NSString *const MESSAGING_NOTIFICATION_RECEIVED = @"messaging_notification_received";
|
||||||
|
|
||||||
// Notifications
|
// Notifications
|
||||||
static NSString *const NOTIFICATIONS_NOTIFICATION_CLICKED = @"notifications_notification_clicked";
|
|
||||||
static NSString *const NOTIFICATIONS_NOTIFICATION_DISPLAYED = @"notifications_notification_displayed";
|
static NSString *const NOTIFICATIONS_NOTIFICATION_DISPLAYED = @"notifications_notification_displayed";
|
||||||
|
static NSString *const NOTIFICATIONS_NOTIFICATION_PRESSED = @"notifications_notification_pressed";
|
||||||
static NSString *const NOTIFICATIONS_NOTIFICATION_RECEIVED = @"notifications_notification_received";
|
static NSString *const NOTIFICATIONS_NOTIFICATION_RECEIVED = @"notifications_notification_received";
|
||||||
|
|
||||||
// AdMob
|
// AdMob
|
||||||
|
|
|
@ -15,7 +15,8 @@
|
||||||
@property _Nullable RCTPromiseResolveBlock permissionResolver;
|
@property _Nullable RCTPromiseResolveBlock permissionResolver;
|
||||||
|
|
||||||
#if !TARGET_OS_TV
|
#if !TARGET_OS_TV
|
||||||
- (void)didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings;
|
- (void)didReceiveRemoteNotification:(nonnull NSDictionary *)userInfo;
|
||||||
|
- (void)didRegisterUserNotificationSettings:(nonnull UIUserNotificationSettings *)notificationSettings;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
|
@ -70,6 +70,12 @@ RCT_EXPORT_MODULE()
|
||||||
_permissionResolver = nil;
|
_permissionResolver = nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Listen for FCM data messages that arrive as a remote notification
|
||||||
|
- (void)didReceiveRemoteNotification:(nonnull NSDictionary *)userInfo {
|
||||||
|
NSDictionary *message = [self parseUserInfo:userInfo];
|
||||||
|
[RNFirebaseUtil sendJSEvent:self name:MESSAGING_MESSAGE_RECEIVED body:message];
|
||||||
|
}
|
||||||
|
|
||||||
// *******************************************************
|
// *******************************************************
|
||||||
// ** Finish AppDelegate methods
|
// ** Finish AppDelegate methods
|
||||||
// *******************************************************
|
// *******************************************************
|
||||||
|
@ -88,8 +94,15 @@ RCT_EXPORT_MODULE()
|
||||||
|
|
||||||
// Listen for data messages in the foreground
|
// Listen for data messages in the foreground
|
||||||
- (void)applicationReceivedRemoteMessage:(nonnull FIRMessagingRemoteMessage *)remoteMessage {
|
- (void)applicationReceivedRemoteMessage:(nonnull FIRMessagingRemoteMessage *)remoteMessage {
|
||||||
NSDictionary *message = [self parseFIRMessagingRemoteMessage:remoteMessage openedFromTray:false];
|
NSDictionary *message = [self parseFIRMessagingRemoteMessage:remoteMessage];
|
||||||
|
[RNFirebaseUtil sendJSEvent:self name:MESSAGING_MESSAGE_RECEIVED body:message];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Receive data messages on iOS 10+ directly from FCM (bypassing APNs) when the app is in the foreground.
|
||||||
|
// To enable direct data messages, you can set [Messaging messaging].shouldEstablishDirectChannel to YES.
|
||||||
|
- (void)messaging:(nonnull FIRMessaging *)messaging
|
||||||
|
didReceiveMessage:(nonnull FIRMessagingRemoteMessage *)remoteMessage {
|
||||||
|
NSDictionary *message = [self parseFIRMessagingRemoteMessage:remoteMessage];
|
||||||
[RNFirebaseUtil sendJSEvent:self name:MESSAGING_MESSAGE_RECEIVED body:message];
|
[RNFirebaseUtil sendJSEvent:self name:MESSAGING_MESSAGE_RECEIVED body:message];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -250,8 +263,7 @@ RCT_EXPORT_METHOD(completeRemoteNotification: (NSString*) messageId
|
||||||
|
|
||||||
// ** Start internals **
|
// ** Start internals **
|
||||||
|
|
||||||
- (NSDictionary*)parseFIRMessagingRemoteMessage:(FIRMessagingRemoteMessage *)remoteMessage
|
- (NSDictionary*)parseFIRMessagingRemoteMessage:(FIRMessagingRemoteMessage *)remoteMessage {
|
||||||
openedFromTray:(bool)openedFromTray {
|
|
||||||
NSDictionary *appData = remoteMessage.appData;
|
NSDictionary *appData = remoteMessage.appData;
|
||||||
|
|
||||||
NSMutableDictionary *message = [[NSMutableDictionary alloc] init];
|
NSMutableDictionary *message = [[NSMutableDictionary alloc] init];
|
||||||
|
@ -262,46 +274,46 @@ RCT_EXPORT_METHOD(completeRemoteNotification: (NSString*) messageId
|
||||||
} else if ([k1 isEqualToString:@"from"]) {
|
} else if ([k1 isEqualToString:@"from"]) {
|
||||||
message[@"from"] = appData[k1];
|
message[@"from"] = appData[k1];
|
||||||
} else if ([k1 isEqualToString:@"notification"]) {
|
} else if ([k1 isEqualToString:@"notification"]) {
|
||||||
NSDictionary *notification = appData[k1];
|
// Ignore for messages
|
||||||
NSMutableDictionary *notif = [[NSMutableDictionary alloc] init];
|
|
||||||
for (id k2 in notification) {
|
|
||||||
if ([k2 isEqualToString:@"badge"]) {
|
|
||||||
notif[@"badge"] = notification[k2];
|
|
||||||
} else if ([k2 isEqualToString:@"body"]) {
|
|
||||||
notif[@"body"] = notification[k2];
|
|
||||||
} else if ([k2 isEqualToString:@"body_loc_args"]) {
|
|
||||||
notif[@"bodyLocalizationArgs"] = notification[k2];
|
|
||||||
} else if ([k2 isEqualToString:@"body_loc_key"]) {
|
|
||||||
notif[@"bodyLocalizationKey"] = notification[k2];
|
|
||||||
} else if ([k2 isEqualToString:@"click_action"]) {
|
|
||||||
notif[@"clickAction"] = notification[k2];
|
|
||||||
} else if ([k2 isEqualToString:@"sound"]) {
|
|
||||||
notif[@"sound"] = notification[k2];
|
|
||||||
} else if ([k2 isEqualToString:@"subtitle"]) {
|
|
||||||
notif[@"subtitle"] = notification[k2];
|
|
||||||
} else if ([k2 isEqualToString:@"title"]) {
|
|
||||||
notif[@"title"] = notification[k2];
|
|
||||||
} else if ([k2 isEqualToString:@"title_loc_args"]) {
|
|
||||||
notif[@"titleLocalizationArgs"] = notification[k2];
|
|
||||||
} else if ([k2 isEqualToString:@"title_loc_key"]) {
|
|
||||||
notif[@"titleLocalizationKey"] = notification[k2];
|
|
||||||
} else {
|
|
||||||
NSLog(@"Unknown notification key: %@", k2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
message[@"notification"] = notif;
|
|
||||||
} else {
|
} else {
|
||||||
// Assume custom data key
|
// Assume custom data key
|
||||||
data[k1] = appData[k1];
|
data[k1] = appData[k1];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
message[@"messageType"] = @"RemoteMessage";
|
|
||||||
message[@"data"] = data;
|
message[@"data"] = data;
|
||||||
message[@"openedFromTray"] = @(false);
|
|
||||||
|
|
||||||
return message;
|
return message;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (NSDictionary*)parseUserInfo:(NSDictionary *)userInfo {
|
||||||
|
NSMutableDictionary *message = [[NSMutableDictionary alloc] init];
|
||||||
|
NSMutableDictionary *data = [[NSMutableDictionary alloc] init];
|
||||||
|
|
||||||
|
for (id k1 in userInfo) {
|
||||||
|
if ([k1 isEqualToString:@"aps"]) {
|
||||||
|
// Ignore notification section
|
||||||
|
} else if ([k1 isEqualToString:@"gcm.message_id"]) {
|
||||||
|
message[@"messageId"] = userInfo[k1];
|
||||||
|
} else if ([k1 isEqualToString:@"google.c.a.ts"]) {
|
||||||
|
message[@"sentTime"] = userInfo[k1];
|
||||||
|
} else if ([k1 isEqualToString:@"gcm.n.e"]
|
||||||
|
|| [k1 isEqualToString:@"gcm.notification.sound2"]
|
||||||
|
|| [k1 isEqualToString:@"google.c.a.c_id"]
|
||||||
|
|| [k1 isEqualToString:@"google.c.a.c_l"]
|
||||||
|
|| [k1 isEqualToString:@"google.c.a.e"]
|
||||||
|
|| [k1 isEqualToString:@"google.c.a.udt"]) {
|
||||||
|
// Ignore known keys
|
||||||
|
} else {
|
||||||
|
// Assume custom data
|
||||||
|
data[k1] = userInfo[k1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
message[@"data"] = data;
|
||||||
|
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
- (NSArray<NSString *> *)supportedEvents {
|
- (NSArray<NSString *> *)supportedEvents {
|
||||||
return @[MESSAGING_MESSAGE_RECEIVED, MESSAGING_TOKEN_REFRESHED];
|
return @[MESSAGING_MESSAGE_RECEIVED, MESSAGING_TOKEN_REFRESHED];
|
||||||
}
|
}
|
||||||
|
@ -317,4 +329,3 @@ RCT_EXPORT_METHOD(completeRemoteNotification: (NSString*) messageId
|
||||||
@implementation RNFirebaseMessaging
|
@implementation RNFirebaseMessaging
|
||||||
@end
|
@end
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
#if __has_include(<FirebaseMessaging/FIRMessaging.h>)
|
#if __has_include(<FirebaseMessaging/FIRMessaging.h>)
|
||||||
#import "RNFirebaseEvents.h"
|
#import "RNFirebaseEvents.h"
|
||||||
|
#import "RNFirebaseMessaging.h"
|
||||||
#import "RNFirebaseUtil.h"
|
#import "RNFirebaseUtil.h"
|
||||||
#import <React/RCTUtils.h>
|
#import <React/RCTUtils.h>
|
||||||
|
|
||||||
|
@ -37,7 +38,7 @@ RCT_EXPORT_MODULE();
|
||||||
- (void)configure {
|
- (void)configure {
|
||||||
// If we're on iOS 10 then we need to set this as a delegate for the UNUserNotificationCenter
|
// If we're on iOS 10 then we need to set this as a delegate for the UNUserNotificationCenter
|
||||||
#if defined(__IPHONE_10_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_10_0
|
#if defined(__IPHONE_10_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_10_0
|
||||||
[UNUserNotificationCenter currentNotificationCenter].delegate = self;
|
// [UNUserNotificationCenter currentNotificationCenter].delegate = self;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Set static instance for use from AppDelegate
|
// Set static instance for use from AppDelegate
|
||||||
|
@ -50,26 +51,78 @@ RCT_EXPORT_MODULE();
|
||||||
// *******************************************************
|
// *******************************************************
|
||||||
|
|
||||||
- (void)didReceiveLocalNotification:(nonnull UILocalNotification *)notification {
|
- (void)didReceiveLocalNotification:(nonnull UILocalNotification *)notification {
|
||||||
|
NSString *event;
|
||||||
|
if (RCTSharedApplication().applicationState == UIApplicationStateBackground) {
|
||||||
|
// notification_displayed
|
||||||
|
event = NOTIFICATIONS_NOTIFICATION_DISPLAYED;
|
||||||
|
} else if (RCTSharedApplication().applicationState == UIApplicationStateInactive) {
|
||||||
|
// notification_displayed
|
||||||
|
event = NOTIFICATIONS_NOTIFICATION_PRESSED;
|
||||||
|
} else {
|
||||||
|
// notification_received
|
||||||
|
event = NOTIFICATIONS_NOTIFICATION_RECEIVED;
|
||||||
|
}
|
||||||
|
|
||||||
|
NSDictionary *message = [self parseUILocalNotification:notification];
|
||||||
|
[RNFirebaseUtil sendJSEvent:self name:event body:message];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Listen for background messages
|
// Listen for background messages
|
||||||
- (void)didReceiveRemoteNotification:(nonnull NSDictionary *)userInfo {
|
- (void)didReceiveRemoteNotification:(nonnull NSDictionary *)userInfo {
|
||||||
BOOL isFromBackground = (RCTSharedApplication().applicationState == UIApplicationStateInactive);
|
// FCM Data messages come through here if they specify content-available=true
|
||||||
NSDictionary *message = [self parseUserInfo:userInfo messageType:@"RemoteNotification" clickAction:nil openedFromTray:isFromBackground];
|
// Pass them over to the RNFirebaseMessaging handler instead
|
||||||
|
if (userInfo[@"aps"] && ((NSDictionary*)userInfo[@"aps"]).count == 1 && userInfo[@"aps"][@"content-available"]) {
|
||||||
|
[[RNFirebaseMessaging instance] didReceiveRemoteNotification:userInfo];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
[RNFirebaseUtil sendJSEvent:self name:MESSAGING_MESSAGE_RECEIVED body:message];
|
NSString *event;
|
||||||
|
if (RCTSharedApplication().applicationState == UIApplicationStateBackground) {
|
||||||
|
// notification_displayed
|
||||||
|
event = NOTIFICATIONS_NOTIFICATION_DISPLAYED;
|
||||||
|
} else if (RCTSharedApplication().applicationState == UIApplicationStateInactive) {
|
||||||
|
// notification_displayed
|
||||||
|
event = NOTIFICATIONS_NOTIFICATION_PRESSED;
|
||||||
|
} else {
|
||||||
|
// notification_received
|
||||||
|
event = NOTIFICATIONS_NOTIFICATION_RECEIVED;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Proper notification structure
|
||||||
|
NSDictionary *message = [self parseUserInfo:userInfo messageType:@"RemoteNotification" clickAction:nil];
|
||||||
|
|
||||||
|
[RNFirebaseUtil sendJSEvent:self name:event body:message];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Listen for background messages
|
// Listen for background messages
|
||||||
- (void)didReceiveRemoteNotification:(NSDictionary *)userInfo
|
- (void)didReceiveRemoteNotification:(NSDictionary *)userInfo
|
||||||
fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
|
fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
|
||||||
BOOL isFromBackground = (RCTSharedApplication().applicationState == UIApplicationStateInactive);
|
// FCM Data messages come through here if they specify content-available=true
|
||||||
NSDictionary *message = [self parseUserInfo:userInfo messageType:@"RemoteNotificationHandler" clickAction:nil openedFromTray:isFromBackground];
|
// Pass them over to the RNFirebaseMessaging handler instead
|
||||||
|
if (userInfo[@"aps"] && ((NSDictionary*)userInfo[@"aps"]).count == 1 && userInfo[@"aps"][@"content-available"]) {
|
||||||
|
[[RNFirebaseMessaging instance] didReceiveRemoteNotification:userInfo];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
NSString *event;
|
||||||
|
if (RCTSharedApplication().applicationState == UIApplicationStateBackground) {
|
||||||
|
// notification_displayed
|
||||||
|
event = NOTIFICATIONS_NOTIFICATION_DISPLAYED;
|
||||||
|
} else if (RCTSharedApplication().applicationState == UIApplicationStateInactive) {
|
||||||
|
// notification_displayed
|
||||||
|
event = NOTIFICATIONS_NOTIFICATION_PRESSED;
|
||||||
|
} else {
|
||||||
|
// notification_received
|
||||||
|
event = NOTIFICATIONS_NOTIFICATION_RECEIVED;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Proper notification structure
|
||||||
|
NSDictionary *message = [self parseUserInfo:userInfo messageType:@"RemoteNotificationHandler" clickAction:nil];
|
||||||
|
|
||||||
|
// TODO: Callback handler
|
||||||
// [_callbackHandlers setObject:[completionHandler copy] forKey:message[@"messageId"]];
|
// [_callbackHandlers setObject:[completionHandler copy] forKey:message[@"messageId"]];
|
||||||
|
|
||||||
[RNFirebaseUtil sendJSEvent:self name:MESSAGING_MESSAGE_RECEIVED body:message];
|
[RNFirebaseUtil sendJSEvent:self name:event body:message];
|
||||||
}
|
}
|
||||||
|
|
||||||
// *******************************************************
|
// *******************************************************
|
||||||
|
@ -93,7 +146,7 @@ RCT_EXPORT_MODULE();
|
||||||
|
|
||||||
NSString *event;
|
NSString *event;
|
||||||
UNNotificationPresentationOptions options;
|
UNNotificationPresentationOptions options;
|
||||||
NSDictionary *message = [self parseUNNotification:notification messageType:@"PresentNotification" openedFromTray:false];
|
NSDictionary *message = [self parseUNNotification:notification messageType:@"PresentNotification"];
|
||||||
|
|
||||||
if (isFcm || isScheduled) {
|
if (isFcm || isScheduled) {
|
||||||
// If app is in the background
|
// If app is in the background
|
||||||
|
@ -116,9 +169,7 @@ RCT_EXPORT_MODULE();
|
||||||
event = NOTIFICATIONS_NOTIFICATION_DISPLAYED;
|
event = NOTIFICATIONS_NOTIFICATION_DISPLAYED;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (event) {
|
[RNFirebaseUtil sendJSEvent:self name:event body:message];
|
||||||
[RNFirebaseUtil sendJSEvent:self name:event body:message];
|
|
||||||
}
|
|
||||||
completionHandler(options);
|
completionHandler(options);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -130,9 +181,9 @@ didReceiveNotificationResponse:(UNNotificationResponse *)response
|
||||||
#else
|
#else
|
||||||
withCompletionHandler:(void(^)())completionHandler {
|
withCompletionHandler:(void(^)())completionHandler {
|
||||||
#endif
|
#endif
|
||||||
NSDictionary *message = [self parseUNNotification:response.notification messageType:@"NotificationResponse" openedFromTray:true];
|
NSDictionary *message = [self parseUNNotification:response.notification messageType:@"NotificationResponse"];
|
||||||
|
|
||||||
[RNFirebaseUtil sendJSEvent:self name:NOTIFICATIONS_NOTIFICATION_CLICKED body:message];
|
[RNFirebaseUtil sendJSEvent:self name:NOTIFICATIONS_NOTIFICATION_PRESSED body:message];
|
||||||
completionHandler();
|
completionHandler();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -200,7 +251,13 @@ RCT_EXPORT_METHOD(getInitialNotification:(RCTPromiseResolveBlock)resolve rejecte
|
||||||
NSDictionary *notification = [self parseUILocalNotification:localNotification];
|
NSDictionary *notification = [self parseUILocalNotification:localNotification];
|
||||||
resolve(notification);
|
resolve(notification);
|
||||||
} else {
|
} else {
|
||||||
resolve(nil);
|
NSDictionary *remoteNotification = [self bridge].launchOptions[UIApplicationLaunchOptionsRemoteNotificationKey];
|
||||||
|
if (remoteNotification) {
|
||||||
|
NSDictionary *message = [self parseUserInfo:remoteNotification messageType:@"InitialMessage" clickAction:nil];
|
||||||
|
resolve(message);
|
||||||
|
} else {
|
||||||
|
resolve(nil);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -485,7 +542,7 @@ RCT_EXPORT_METHOD(scheduleNotification:(NSDictionary*) notification
|
||||||
}
|
}
|
||||||
ios[@"attachments"] = attachments;
|
ios[@"attachments"] = attachments;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (localNotification.content.badge) {
|
if (localNotification.content.badge) {
|
||||||
ios[@"badge"] = localNotification.content.badge;
|
ios[@"badge"] = localNotification.content.badge;
|
||||||
}
|
}
|
||||||
|
@ -504,21 +561,20 @@ RCT_EXPORT_METHOD(scheduleNotification:(NSDictionary*) notification
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSDictionary*)parseUNNotification:(UNNotification *)notification
|
- (NSDictionary*)parseUNNotification:(UNNotification *)notification
|
||||||
messageType:(NSString *)messageType
|
messageType:(NSString *)messageType {
|
||||||
openedFromTray:(bool)openedFromTray {
|
|
||||||
NSDictionary *userInfo = notification.request.content.userInfo;
|
NSDictionary *userInfo = notification.request.content.userInfo;
|
||||||
NSString *clickAction = notification.request.content.categoryIdentifier;
|
NSString *clickAction = notification.request.content.categoryIdentifier;
|
||||||
|
|
||||||
return [self parseUserInfo:userInfo messageType:messageType clickAction:clickAction openedFromTray:openedFromTray];
|
return [self parseUserInfo:userInfo messageType:messageType clickAction:clickAction];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSDictionary*)parseUserInfo:(NSDictionary *)userInfo
|
- (NSDictionary*)parseUserInfo:(NSDictionary *)userInfo
|
||||||
messageType:(NSString *) messageType
|
messageType:(NSString *) messageType
|
||||||
clickAction:(NSString *) clickAction
|
clickAction:(NSString *) clickAction {
|
||||||
openedFromTray:(bool)openedFromTray {
|
|
||||||
NSMutableDictionary *message = [[NSMutableDictionary alloc] init];
|
NSMutableDictionary *notification = [[NSMutableDictionary alloc] init];
|
||||||
NSMutableDictionary *notif = [[NSMutableDictionary alloc] init];
|
|
||||||
NSMutableDictionary *data = [[NSMutableDictionary alloc] init];
|
NSMutableDictionary *data = [[NSMutableDictionary alloc] init];
|
||||||
|
NSMutableDictionary *ios = [[NSMutableDictionary alloc] init];
|
||||||
|
|
||||||
for (id k1 in userInfo) {
|
for (id k1 in userInfo) {
|
||||||
if ([k1 isEqualToString:@"aps"]) {
|
if ([k1 isEqualToString:@"aps"]) {
|
||||||
|
@ -528,37 +584,42 @@ RCT_EXPORT_METHOD(scheduleNotification:(NSDictionary*) notification
|
||||||
NSDictionary *alert = aps[k2];
|
NSDictionary *alert = aps[k2];
|
||||||
for (id k3 in alert) {
|
for (id k3 in alert) {
|
||||||
if ([k3 isEqualToString:@"body"]) {
|
if ([k3 isEqualToString:@"body"]) {
|
||||||
notif[@"body"] = alert[k3];
|
notification[@"body"] = alert[k3];
|
||||||
} else if ([k3 isEqualToString:@"loc-args"]) {
|
} else if ([k3 isEqualToString:@"loc-args"]) {
|
||||||
notif[@"bodyLocalizationArgs"] = alert[k3];
|
// TODO: What to do with this?
|
||||||
|
// notif[@"bodyLocalizationArgs"] = alert[k3];
|
||||||
} else if ([k3 isEqualToString:@"loc-key"]) {
|
} else if ([k3 isEqualToString:@"loc-key"]) {
|
||||||
notif[@"bodyLocalizationKey"] = alert[k3];
|
// TODO: What to do with this?
|
||||||
|
// notif[@"bodyLocalizationKey"] = alert[k3];
|
||||||
} else if ([k3 isEqualToString:@"subtitle"]) {
|
} else if ([k3 isEqualToString:@"subtitle"]) {
|
||||||
notif[@"subtitle"] = alert[k3];
|
notification[@"subtitle"] = alert[k3];
|
||||||
} else if ([k3 isEqualToString:@"title"]) {
|
} else if ([k3 isEqualToString:@"title"]) {
|
||||||
notif[@"title"] = alert[k3];
|
notification[@"title"] = alert[k3];
|
||||||
} else if ([k3 isEqualToString:@"title-loc-args"]) {
|
} else if ([k3 isEqualToString:@"title-loc-args"]) {
|
||||||
notif[@"titleLocalizationArgs"] = alert[k3];
|
// TODO: What to do with this?
|
||||||
|
// notif[@"titleLocalizationArgs"] = alert[k3];
|
||||||
} else if ([k3 isEqualToString:@"title-loc-key"]) {
|
} else if ([k3 isEqualToString:@"title-loc-key"]) {
|
||||||
notif[@"titleLocalizationKey"] = alert[k3];
|
// TODO: What to do with this?
|
||||||
|
// notif[@"titleLocalizationKey"] = alert[k3];
|
||||||
} else {
|
} else {
|
||||||
NSLog(@"Unknown alert key: %@", k2);
|
NSLog(@"Unknown alert key: %@", k2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if ([k2 isEqualToString:@"badge"]) {
|
} else if ([k2 isEqualToString:@"badge"]) {
|
||||||
notif[@"badge"] = aps[k2];
|
ios[@"badge"] = aps[k2];
|
||||||
} else if ([k2 isEqualToString:@"category"]) {
|
} else if ([k2 isEqualToString:@"category"]) {
|
||||||
notif[@"clickAction"] = aps[k2];
|
ios[@"category"] = aps[k2];
|
||||||
} else if ([k2 isEqualToString:@"sound"]) {
|
} else if ([k2 isEqualToString:@"sound"]) {
|
||||||
notif[@"sound"] = aps[k2];
|
notification[@"sound"] = aps[k2];
|
||||||
} else {
|
} else {
|
||||||
NSLog(@"Unknown aps key: %@", k2);
|
NSLog(@"Unknown aps key: %@", k2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if ([k1 isEqualToString:@"gcm.message_id"]) {
|
} else if ([k1 isEqualToString:@"gcm.message_id"]) {
|
||||||
message[@"messageId"] = userInfo[k1];
|
notification[@"notificationId"] = userInfo[k1];
|
||||||
} else if ([k1 isEqualToString:@"google.c.a.ts"]) {
|
} else if ([k1 isEqualToString:@"google.c.a.ts"]) {
|
||||||
message[@"sentTime"] = userInfo[k1];
|
// TODO: What to do with this?
|
||||||
|
// message[@"sentTime"] = userInfo[k1];
|
||||||
} else if ([k1 isEqualToString:@"gcm.n.e"]
|
} else if ([k1 isEqualToString:@"gcm.n.e"]
|
||||||
|| [k1 isEqualToString:@"gcm.notification.sound2"]
|
|| [k1 isEqualToString:@"gcm.notification.sound2"]
|
||||||
|| [k1 isEqualToString:@"google.c.a.c_id"]
|
|| [k1 isEqualToString:@"google.c.a.c_id"]
|
||||||
|
@ -572,26 +633,17 @@ RCT_EXPORT_METHOD(scheduleNotification:(NSDictionary*) notification
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!notif[@"clickAction"] && clickAction) {
|
// TODO: What to do with this?
|
||||||
notif[@"clickAction"] = clickAction;
|
// message[@"messageType"] = messageType;
|
||||||
}
|
|
||||||
|
|
||||||
// Generate a message ID if one was not present in the notification
|
notification[@"data"] = data;
|
||||||
// This is used for resolving click handlers
|
notification[@"ios"] = ios;
|
||||||
if (!message[@"messageId"]) {
|
|
||||||
message[@"messageId"] = [[NSUUID UUID] UUIDString];
|
|
||||||
}
|
|
||||||
message[@"messageType"] = messageType;
|
|
||||||
|
|
||||||
message[@"data"] = data;
|
return notification;
|
||||||
message[@"notification"] = notif;
|
|
||||||
message[@"openedFromTray"] = @(openedFromTray);
|
|
||||||
|
|
||||||
return message;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSArray<NSString *> *)supportedEvents {
|
- (NSArray<NSString *> *)supportedEvents {
|
||||||
return @[NOTIFICATIONS_NOTIFICATION_CLICKED, NOTIFICATIONS_NOTIFICATION_DISPLAYED, NOTIFICATIONS_NOTIFICATION_RECEIVED];
|
return @[NOTIFICATIONS_NOTIFICATION_DISPLAYED, NOTIFICATIONS_NOTIFICATION_PRESSED, NOTIFICATIONS_NOTIFICATION_RECEIVED];
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (BOOL)requiresMainQueueSetup
|
+ (BOOL)requiresMainQueueSetup
|
||||||
|
@ -605,4 +657,3 @@ RCT_EXPORT_METHOD(scheduleNotification:(NSDictionary*) notification
|
||||||
@implementation RNFirebaseNotifications
|
@implementation RNFirebaseNotifications
|
||||||
@end
|
@end
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -11,9 +11,7 @@ import {
|
||||||
} from './types';
|
} from './types';
|
||||||
import type Messaging from './';
|
import type Messaging from './';
|
||||||
import type {
|
import type {
|
||||||
MessageTypeType,
|
|
||||||
NativeMessage,
|
NativeMessage,
|
||||||
Notification,
|
|
||||||
PresentNotificationResultType,
|
PresentNotificationResultType,
|
||||||
RemoteNotificationResultType,
|
RemoteNotificationResultType,
|
||||||
} from './types';
|
} from './types';
|
||||||
|
@ -47,18 +45,6 @@ export default class Message {
|
||||||
return this._message.messageId;
|
return this._message.messageId;
|
||||||
}
|
}
|
||||||
|
|
||||||
get messageType(): ?MessageTypeType {
|
|
||||||
return this._message.messageType;
|
|
||||||
}
|
|
||||||
|
|
||||||
get openedFromTray(): boolean {
|
|
||||||
return this._message.openedFromTray;
|
|
||||||
}
|
|
||||||
|
|
||||||
get notification(): ?Notification {
|
|
||||||
return this._message.notification;
|
|
||||||
}
|
|
||||||
|
|
||||||
get sentTime(): ?number {
|
get sentTime(): ?number {
|
||||||
return this._message.sentTime;
|
return this._message.sentTime;
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,8 +55,8 @@ export default class Messaging extends ModuleBase {
|
||||||
// sub to internal native event - this fans out to
|
// sub to internal native event - this fans out to
|
||||||
// public event name: onMessage
|
// public event name: onMessage
|
||||||
'messaging_message_received',
|
'messaging_message_received',
|
||||||
(message: Message) => {
|
(message: NativeMessage) => {
|
||||||
SharedEventEmitter.emit('onMessage', message);
|
SharedEventEmitter.emit('onMessage', new Message(this, message));
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -89,8 +89,7 @@ export default class Messaging extends ModuleBase {
|
||||||
|
|
||||||
getLogger(this).info('Creating onMessage listener');
|
getLogger(this).info('Creating onMessage listener');
|
||||||
|
|
||||||
const wrappedListener = async (nativeMessage: NativeMessage) => {
|
const wrappedListener = async (message: Message) => {
|
||||||
const message = new Message(this, nativeMessage);
|
|
||||||
await listener(message);
|
await listener(message);
|
||||||
message.complete();
|
message.complete();
|
||||||
};
|
};
|
||||||
|
|
|
@ -51,9 +51,6 @@ export type NativeMessage = {
|
||||||
data: { [string]: string },
|
data: { [string]: string },
|
||||||
from?: string,
|
from?: string,
|
||||||
messageId: string,
|
messageId: string,
|
||||||
messageType?: MessageTypeType,
|
|
||||||
openedFromTray: boolean,
|
|
||||||
notification?: Notification,
|
|
||||||
sentTime?: number,
|
sentTime?: number,
|
||||||
to?: string,
|
to?: string,
|
||||||
ttl?: number,
|
ttl?: number,
|
||||||
|
|
|
@ -2,128 +2,29 @@
|
||||||
* @flow
|
* @flow
|
||||||
* AndroidNotification representation wrapper
|
* AndroidNotification representation wrapper
|
||||||
*/
|
*/
|
||||||
|
import { Category } from './types';
|
||||||
import type Notification from './Notification';
|
import type Notification from './Notification';
|
||||||
|
import type {
|
||||||
type Lights = {
|
BadgeIconTypeType,
|
||||||
argb: number,
|
CategoryType,
|
||||||
onMs: number,
|
DefaultsType,
|
||||||
offMs: number,
|
GroupAlertType,
|
||||||
};
|
Lights,
|
||||||
|
NativeAndroidNotification,
|
||||||
type Progress = {
|
PriorityType,
|
||||||
max: number,
|
Progress,
|
||||||
progress: number,
|
SmallIcon,
|
||||||
indeterminate: boolean,
|
VisibilityType,
|
||||||
};
|
} from './types';
|
||||||
|
|
||||||
type SmallIcon = {
|
|
||||||
icon: string,
|
|
||||||
level?: number,
|
|
||||||
};
|
|
||||||
|
|
||||||
export type NativeAndroidNotification = {|
|
|
||||||
// TODO actions: Action[],
|
|
||||||
autoCancel: boolean,
|
|
||||||
badgeIconType: BadgeIconTypeType,
|
|
||||||
category: CategoryType,
|
|
||||||
channelId: string,
|
|
||||||
clickAction?: string,
|
|
||||||
color: string,
|
|
||||||
colorized: boolean,
|
|
||||||
contentInfo: string,
|
|
||||||
defaults: DefaultsType[],
|
|
||||||
group: string,
|
|
||||||
groupAlertBehaviour: GroupAlertType,
|
|
||||||
groupSummary: boolean,
|
|
||||||
largeIcon: string,
|
|
||||||
lights: Lights,
|
|
||||||
localOnly: boolean,
|
|
||||||
number: number,
|
|
||||||
ongoing: boolean,
|
|
||||||
onlyAlertOnce: boolean,
|
|
||||||
people: string[],
|
|
||||||
priority: PriorityType,
|
|
||||||
progress: Progress,
|
|
||||||
// publicVersion: Notification,
|
|
||||||
remoteInputHistory: string[],
|
|
||||||
shortcutId: string,
|
|
||||||
showWhen: boolean,
|
|
||||||
smallIcon: SmallIcon,
|
|
||||||
sortKey: string,
|
|
||||||
// TODO: style: Style,
|
|
||||||
ticker: string,
|
|
||||||
timeoutAfter: number,
|
|
||||||
usesChronometer: boolean,
|
|
||||||
vibrate: number[],
|
|
||||||
visibility: VisibilityType,
|
|
||||||
when: number,
|
|
||||||
|};
|
|
||||||
|
|
||||||
export const BadgeIconType = {
|
|
||||||
Large: 2,
|
|
||||||
None: 0,
|
|
||||||
Small: 1,
|
|
||||||
};
|
|
||||||
|
|
||||||
export const Category = {
|
|
||||||
Alarm: 'alarm',
|
|
||||||
Call: 'call',
|
|
||||||
Email: 'email',
|
|
||||||
Error: 'err',
|
|
||||||
Event: 'event',
|
|
||||||
Message: 'msg',
|
|
||||||
Progress: 'progress',
|
|
||||||
Promo: 'promo',
|
|
||||||
Recommendation: 'recommendation',
|
|
||||||
Reminder: 'reminder',
|
|
||||||
Service: 'service',
|
|
||||||
Social: 'social',
|
|
||||||
Status: 'status',
|
|
||||||
System: 'system',
|
|
||||||
Transport: 'transport',
|
|
||||||
};
|
|
||||||
|
|
||||||
export const Defaults = {
|
|
||||||
All: -1,
|
|
||||||
Lights: 4,
|
|
||||||
Sound: 1,
|
|
||||||
Vibrate: 2,
|
|
||||||
};
|
|
||||||
|
|
||||||
export const GroupAlert = {
|
|
||||||
All: 0,
|
|
||||||
Children: 2,
|
|
||||||
Summary: 1,
|
|
||||||
};
|
|
||||||
|
|
||||||
export const Priority = {
|
|
||||||
Default: 0,
|
|
||||||
High: 1,
|
|
||||||
Low: -1,
|
|
||||||
Max: 2,
|
|
||||||
Min: -2,
|
|
||||||
};
|
|
||||||
|
|
||||||
export const Visibility = {
|
|
||||||
Private: 0,
|
|
||||||
Public: 1,
|
|
||||||
Secret: -1,
|
|
||||||
};
|
|
||||||
|
|
||||||
type BadgeIconTypeType = $Values<typeof BadgeIconType>;
|
|
||||||
type CategoryType = $Values<typeof Category>;
|
|
||||||
type DefaultsType = $Values<typeof Defaults>;
|
|
||||||
type GroupAlertType = $Values<typeof GroupAlert>;
|
|
||||||
type PriorityType = $Values<typeof Priority>;
|
|
||||||
type VisibilityType = $Values<typeof Visibility>;
|
|
||||||
|
|
||||||
export default class AndroidNotification {
|
export default class AndroidNotification {
|
||||||
|
// TODO optional fields
|
||||||
// TODO actions: Action[]; // icon, title, ??pendingIntent??, allowGeneratedReplies, extender, extras, remoteinput (ugh)
|
// TODO actions: Action[]; // icon, title, ??pendingIntent??, allowGeneratedReplies, extender, extras, remoteinput (ugh)
|
||||||
_autoCancel: boolean;
|
_autoCancel: boolean;
|
||||||
_badgeIconType: BadgeIconTypeType;
|
_badgeIconType: BadgeIconTypeType;
|
||||||
_category: CategoryType;
|
_category: CategoryType;
|
||||||
_channelId: string;
|
_channelId: string;
|
||||||
_clickAction: string;
|
_clickAction: string | void;
|
||||||
_color: string;
|
_color: string;
|
||||||
_colorized: boolean;
|
_colorized: boolean;
|
||||||
_contentInfo: string;
|
_contentInfo: string;
|
||||||
|
@ -145,9 +46,7 @@ export default class AndroidNotification {
|
||||||
_remoteInputHistory: string[];
|
_remoteInputHistory: string[];
|
||||||
_shortcutId: string;
|
_shortcutId: string;
|
||||||
_showWhen: boolean;
|
_showWhen: boolean;
|
||||||
_smallIcon: SmallIcon = {
|
_smallIcon: SmallIcon;
|
||||||
icon: 'ic_launcher',
|
|
||||||
};
|
|
||||||
_sortKey: string;
|
_sortKey: string;
|
||||||
// TODO: style: Style; // Need to figure out if this can work
|
// TODO: style: Style; // Need to figure out if this can work
|
||||||
_ticker: string;
|
_ticker: string;
|
||||||
|
@ -167,9 +66,50 @@ export default class AndroidNotification {
|
||||||
// fullScreenIntent: PendingIntent
|
// fullScreenIntent: PendingIntent
|
||||||
// sound.streamType
|
// sound.streamType
|
||||||
|
|
||||||
constructor(notification: Notification) {
|
constructor(notification: Notification, data?: NativeAndroidNotification) {
|
||||||
this._notification = notification;
|
this._notification = notification;
|
||||||
this._people = [];
|
|
||||||
|
if (data) {
|
||||||
|
this._autoCancel = data.autoCancel;
|
||||||
|
this._badgeIconType = data.badgeIconType;
|
||||||
|
this._category = data.category;
|
||||||
|
this._channelId = data.channelId;
|
||||||
|
this._clickAction = data.clickAction;
|
||||||
|
this._color = data.color;
|
||||||
|
this._colorized = data.colorized;
|
||||||
|
this._contentInfo = data.contentInfo;
|
||||||
|
this._defaults = data.defaults;
|
||||||
|
this._group = data.group;
|
||||||
|
this._groupAlertBehaviour = data.groupAlertBehaviour;
|
||||||
|
this._groupSummary = data.groupSummary;
|
||||||
|
this._largeIcon = data.largeIcon;
|
||||||
|
this._lights = data.lights;
|
||||||
|
this._localOnly = data.localOnly;
|
||||||
|
this._number = data.number;
|
||||||
|
this._ongoing = data.ongoing;
|
||||||
|
this._onlyAlertOnce = data.onlyAlertOnce;
|
||||||
|
this._people = data.people;
|
||||||
|
this._priority = data.priority;
|
||||||
|
this._progress = data.progress;
|
||||||
|
// _publicVersion: Notification;
|
||||||
|
this._remoteInputHistory = data.remoteInputHistory;
|
||||||
|
this._shortcutId = data.shortcutId;
|
||||||
|
this._showWhen = data.showWhen;
|
||||||
|
this._smallIcon = data.smallIcon;
|
||||||
|
this._sortKey = data.sortKey;
|
||||||
|
this._ticker = data.ticker;
|
||||||
|
this._timeoutAfter = data.timeoutAfter;
|
||||||
|
this._usesChronometer = data.usesChronometer;
|
||||||
|
this._vibrate = data.vibrate;
|
||||||
|
this._visibility = data.visibility;
|
||||||
|
this._when = data.when;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Defaults
|
||||||
|
this._people = this._people || [];
|
||||||
|
this._smallIcon = this._smallIcon || {
|
||||||
|
icon: 'ic_launcher',
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -506,7 +446,7 @@ export default class AndroidNotification {
|
||||||
}
|
}
|
||||||
|
|
||||||
build(): NativeAndroidNotification {
|
build(): NativeAndroidNotification {
|
||||||
// TODO: Validation
|
// TODO: Validation of required fields
|
||||||
if (!this._channelId) {
|
if (!this._channelId) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
'AndroidNotification: Missing required `channelId` property'
|
'AndroidNotification: Missing required `channelId` property'
|
||||||
|
|
|
@ -3,48 +3,37 @@
|
||||||
* IOSNotification representation wrapper
|
* IOSNotification representation wrapper
|
||||||
*/
|
*/
|
||||||
import type Notification from './Notification';
|
import type Notification from './Notification';
|
||||||
|
import type {
|
||||||
type AttachmentOptions = {|
|
Attachment,
|
||||||
TypeHint: string,
|
AttachmentOptions,
|
||||||
ThumbnailHidden: boolean,
|
NativeIOSNotification,
|
||||||
ThumbnailClippingRect: {
|
} from './types';
|
||||||
height: number,
|
|
||||||
width: number,
|
|
||||||
x: number,
|
|
||||||
y: number,
|
|
||||||
},
|
|
||||||
ThumbnailTime: number,
|
|
||||||
|};
|
|
||||||
|
|
||||||
type Attachment = {|
|
|
||||||
identifier: string,
|
|
||||||
options?: AttachmentOptions,
|
|
||||||
url: string,
|
|
||||||
|};
|
|
||||||
|
|
||||||
export type NativeIOSNotification = {|
|
|
||||||
alertAction?: string,
|
|
||||||
attachments: Attachment[],
|
|
||||||
badge?: number,
|
|
||||||
category?: string,
|
|
||||||
hasAction?: boolean,
|
|
||||||
launchImage?: string,
|
|
||||||
threadIdentifier?: string,
|
|
||||||
|};
|
|
||||||
|
|
||||||
export default class IOSNotification {
|
export default class IOSNotification {
|
||||||
_alertAction: string; // alertAction | N/A
|
_alertAction: string | void; // alertAction | N/A
|
||||||
_attachments: Attachment[]; // N/A | attachments
|
_attachments: Attachment[]; // N/A | attachments
|
||||||
_badge: number; // applicationIconBadgeNumber | badge
|
_badge: number | void; // applicationIconBadgeNumber | badge
|
||||||
_category: string;
|
_category: string | void;
|
||||||
_hasAction: boolean; // hasAction | N/A
|
_hasAction: boolean | void; // hasAction | N/A
|
||||||
_launchImage: string; // alertLaunchImage | launchImageName
|
_launchImage: string | void; // alertLaunchImage | launchImageName
|
||||||
_notification: Notification;
|
_notification: Notification;
|
||||||
_threadIdentifier: string; // N/A | threadIdentifier
|
_threadIdentifier: string | void; // N/A | threadIdentifier
|
||||||
|
|
||||||
constructor(notification: Notification) {
|
constructor(notification: Notification, data?: NativeIOSNotification) {
|
||||||
this._attachments = [];
|
|
||||||
this._notification = notification;
|
this._notification = notification;
|
||||||
|
|
||||||
|
if (data) {
|
||||||
|
this._alertAction = data.alertAction;
|
||||||
|
this._attachments = data.attachments;
|
||||||
|
this._badge = data.badge;
|
||||||
|
this._category = data.category;
|
||||||
|
this._hasAction = data.hasAction;
|
||||||
|
this._launchImage = data.launchImage;
|
||||||
|
this._threadIdentifier = data.threadIdentifier;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Defaults
|
||||||
|
this._attachments = this._attachments || [];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -128,7 +117,7 @@ export default class IOSNotification {
|
||||||
}
|
}
|
||||||
|
|
||||||
build(): NativeIOSNotification {
|
build(): NativeIOSNotification {
|
||||||
// TODO: Validation
|
// TODO: Validation of required fields
|
||||||
|
|
||||||
return {
|
return {
|
||||||
alertAction: this._alertAction,
|
alertAction: this._alertAction,
|
||||||
|
|
|
@ -7,21 +7,7 @@ import AndroidNotification from './AndroidNotification';
|
||||||
import IOSNotification from './IOSNotification';
|
import IOSNotification from './IOSNotification';
|
||||||
import { generatePushID, isObject } from '../../utils';
|
import { generatePushID, isObject } from '../../utils';
|
||||||
|
|
||||||
import type { NativeAndroidNotification } from './AndroidNotification';
|
import type { NativeNotification } from './types';
|
||||||
import type { NativeIOSNotification } from './IOSNotification';
|
|
||||||
import type { Schedule } from './';
|
|
||||||
|
|
||||||
type NativeNotification = {|
|
|
||||||
android?: NativeAndroidNotification,
|
|
||||||
body: string,
|
|
||||||
data: { [string]: string },
|
|
||||||
ios?: NativeIOSNotification,
|
|
||||||
notificationId: string,
|
|
||||||
schedule?: Schedule,
|
|
||||||
sound?: string,
|
|
||||||
subtitle?: string,
|
|
||||||
title: string,
|
|
||||||
|};
|
|
||||||
|
|
||||||
export default class Notification {
|
export default class Notification {
|
||||||
// iOS 8/9 | 10+ | Android
|
// iOS 8/9 | 10+ | Android
|
||||||
|
@ -34,12 +20,23 @@ export default class Notification {
|
||||||
_subtitle: string | void; // N/A | subtitle | subText
|
_subtitle: string | void; // N/A | subtitle | subText
|
||||||
_title: string; // alertTitle | title | contentTitle
|
_title: string; // alertTitle | title | contentTitle
|
||||||
|
|
||||||
constructor() {
|
constructor(data?: NativeNotification) {
|
||||||
this._android = new AndroidNotification(this);
|
this._android = new AndroidNotification(this, data && data.android);
|
||||||
this._data = {};
|
this._ios = new IOSNotification(this, data && data.ios);
|
||||||
this._ios = new IOSNotification(this);
|
|
||||||
// TODO: Is this the best way to generate an ID?
|
if (data) {
|
||||||
this._notificationId = generatePushID();
|
this._body = data.body;
|
||||||
|
this._data = data.data;
|
||||||
|
// TODO: Is this the best way to generate an ID?
|
||||||
|
this._notificationId = data.notificationId;
|
||||||
|
this._sound = data.sound;
|
||||||
|
this._subtitle = data.subtitle;
|
||||||
|
this._title = data.title;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Defaults
|
||||||
|
this._data = this._data || {};
|
||||||
|
this._notificationId = this._notificationId || generatePushID();
|
||||||
}
|
}
|
||||||
|
|
||||||
get android(): AndroidNotification {
|
get android(): AndroidNotification {
|
||||||
|
|
|
@ -15,26 +15,20 @@ import {
|
||||||
GroupAlert,
|
GroupAlert,
|
||||||
Priority,
|
Priority,
|
||||||
Visibility,
|
Visibility,
|
||||||
} from './AndroidNotification';
|
} from './types';
|
||||||
|
|
||||||
import type App from '../core/app';
|
import type App from '../core/app';
|
||||||
|
import type { NativeNotification, Schedule } from './types';
|
||||||
|
|
||||||
// TODO: Received notification type will be different from sent notification
|
|
||||||
type OnNotification = Notification => any;
|
type OnNotification = Notification => any;
|
||||||
|
|
||||||
type OnNotificationObserver = {
|
type OnNotificationObserver = {
|
||||||
next: OnNotification,
|
next: OnNotification,
|
||||||
};
|
};
|
||||||
|
|
||||||
export type Schedule = {
|
|
||||||
exact?: boolean,
|
|
||||||
fireDate: number,
|
|
||||||
repeatInterval?: 'minute' | 'hour' | 'day' | 'week',
|
|
||||||
};
|
|
||||||
|
|
||||||
const NATIVE_EVENTS = [
|
const NATIVE_EVENTS = [
|
||||||
'notifications_notification_clicked',
|
|
||||||
'notifications_notification_displayed',
|
'notifications_notification_displayed',
|
||||||
|
'notifications_notification_pressed',
|
||||||
'notifications_notification_received',
|
'notifications_notification_received',
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@ -69,10 +63,13 @@ export default class Notifications extends ModuleBase {
|
||||||
|
|
||||||
SharedEventEmitter.addListener(
|
SharedEventEmitter.addListener(
|
||||||
// sub to internal native event - this fans out to
|
// sub to internal native event - this fans out to
|
||||||
// public event name: onNotificationClicked
|
// public event name: onNotificationPressed
|
||||||
'notifications_notification_clicked',
|
'notifications_notification_pressed',
|
||||||
(notification: Notification) => {
|
(notification: NativeNotification) => {
|
||||||
SharedEventEmitter.emit('onNotificationClicked', notification);
|
SharedEventEmitter.emit(
|
||||||
|
'onNotificationPressed',
|
||||||
|
new Notification(notification)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -80,8 +77,11 @@ export default class Notifications extends ModuleBase {
|
||||||
// sub to internal native event - this fans out to
|
// sub to internal native event - this fans out to
|
||||||
// public event name: onNotificationDisplayed
|
// public event name: onNotificationDisplayed
|
||||||
'notifications_notification_displayed',
|
'notifications_notification_displayed',
|
||||||
(notification: Notification) => {
|
(notification: NativeNotification) => {
|
||||||
SharedEventEmitter.emit('onNotificationDisplayed', notification);
|
SharedEventEmitter.emit(
|
||||||
|
'onNotificationDisplayed',
|
||||||
|
new Notification(notification)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -89,8 +89,11 @@ export default class Notifications extends ModuleBase {
|
||||||
// sub to internal native event - this fans out to
|
// sub to internal native event - this fans out to
|
||||||
// public event name: onNotification
|
// public event name: onNotification
|
||||||
'notifications_notification_received',
|
'notifications_notification_received',
|
||||||
(notification: Notification) => {
|
(notification: NativeNotification) => {
|
||||||
SharedEventEmitter.emit('onNotification', notification);
|
SharedEventEmitter.emit(
|
||||||
|
'onNotification',
|
||||||
|
new Notification(notification)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -166,29 +169,6 @@ export default class Notifications extends ModuleBase {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
onNotificationClicked(
|
|
||||||
nextOrObserver: OnNotification | OnNotificationObserver
|
|
||||||
): () => any {
|
|
||||||
let listener;
|
|
||||||
if (isFunction(nextOrObserver)) {
|
|
||||||
listener = nextOrObserver;
|
|
||||||
} else if (isObject(nextOrObserver) && isFunction(nextOrObserver.next)) {
|
|
||||||
listener = nextOrObserver.next;
|
|
||||||
} else {
|
|
||||||
throw new Error(
|
|
||||||
'Notifications.onNotificationClicked failed: First argument must be a function or observer object with a `next` function.'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
getLogger(this).info('Creating onNotificationClicked listener');
|
|
||||||
SharedEventEmitter.addListener('onNotificationClicked', listener);
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
getLogger(this).info('Removing onNotificationClicked listener');
|
|
||||||
SharedEventEmitter.removeListener('onNotificationClicked', listener);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
onNotificationDisplayed(
|
onNotificationDisplayed(
|
||||||
nextOrObserver: OnNotification | OnNotificationObserver
|
nextOrObserver: OnNotification | OnNotificationObserver
|
||||||
): () => any {
|
): () => any {
|
||||||
|
@ -212,6 +192,30 @@ export default class Notifications extends ModuleBase {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onNotificationPressed(
|
||||||
|
nextOrObserver: OnNotification | OnNotificationObserver
|
||||||
|
): () => any {
|
||||||
|
let listener: Notification => any;
|
||||||
|
if (isFunction(nextOrObserver)) {
|
||||||
|
// $FlowBug: Not coping with the overloaded method signature
|
||||||
|
listener = nextOrObserver;
|
||||||
|
} else if (isObject(nextOrObserver) && isFunction(nextOrObserver.next)) {
|
||||||
|
listener = nextOrObserver.next;
|
||||||
|
} else {
|
||||||
|
throw new Error(
|
||||||
|
'Notifications.onNotificationPressed failed: First argument must be a function or observer object with a `next` function.'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
getLogger(this).info('Creating onNotificationPressed listener');
|
||||||
|
SharedEventEmitter.addListener('onNotificationPressed', listener);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
getLogger(this).info('Removing onNotificationPressed listener');
|
||||||
|
SharedEventEmitter.removeListener('onNotificationPressed', listener);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove all delivered notifications.
|
* Remove all delivered notifications.
|
||||||
* @returns {*}
|
* @returns {*}
|
||||||
|
|
|
@ -0,0 +1,162 @@
|
||||||
|
/**
|
||||||
|
* @flow
|
||||||
|
*/
|
||||||
|
|
||||||
|
export const BadgeIconType = {
|
||||||
|
Large: 2,
|
||||||
|
None: 0,
|
||||||
|
Small: 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const Category = {
|
||||||
|
Alarm: 'alarm',
|
||||||
|
Call: 'call',
|
||||||
|
Email: 'email',
|
||||||
|
Error: 'err',
|
||||||
|
Event: 'event',
|
||||||
|
Message: 'msg',
|
||||||
|
Progress: 'progress',
|
||||||
|
Promo: 'promo',
|
||||||
|
Recommendation: 'recommendation',
|
||||||
|
Reminder: 'reminder',
|
||||||
|
Service: 'service',
|
||||||
|
Social: 'social',
|
||||||
|
Status: 'status',
|
||||||
|
System: 'system',
|
||||||
|
Transport: 'transport',
|
||||||
|
};
|
||||||
|
|
||||||
|
export const Defaults = {
|
||||||
|
All: -1,
|
||||||
|
Lights: 4,
|
||||||
|
Sound: 1,
|
||||||
|
Vibrate: 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const GroupAlert = {
|
||||||
|
All: 0,
|
||||||
|
Children: 2,
|
||||||
|
Summary: 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const Priority = {
|
||||||
|
Default: 0,
|
||||||
|
High: 1,
|
||||||
|
Low: -1,
|
||||||
|
Max: 2,
|
||||||
|
Min: -2,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const Visibility = {
|
||||||
|
Private: 0,
|
||||||
|
Public: 1,
|
||||||
|
Secret: -1,
|
||||||
|
};
|
||||||
|
|
||||||
|
export type BadgeIconTypeType = $Values<typeof BadgeIconType>;
|
||||||
|
export type CategoryType = $Values<typeof Category>;
|
||||||
|
export type DefaultsType = $Values<typeof Defaults>;
|
||||||
|
export type GroupAlertType = $Values<typeof GroupAlert>;
|
||||||
|
export type PriorityType = $Values<typeof Priority>;
|
||||||
|
export type VisibilityType = $Values<typeof Visibility>;
|
||||||
|
|
||||||
|
export type Lights = {
|
||||||
|
argb: number,
|
||||||
|
onMs: number,
|
||||||
|
offMs: number,
|
||||||
|
};
|
||||||
|
|
||||||
|
export type Progress = {
|
||||||
|
max: number,
|
||||||
|
progress: number,
|
||||||
|
indeterminate: boolean,
|
||||||
|
};
|
||||||
|
|
||||||
|
export type SmallIcon = {
|
||||||
|
icon: string,
|
||||||
|
level?: number,
|
||||||
|
};
|
||||||
|
|
||||||
|
export type NativeAndroidNotification = {|
|
||||||
|
// TODO actions: Action[],
|
||||||
|
autoCancel: boolean,
|
||||||
|
badgeIconType: BadgeIconTypeType,
|
||||||
|
category: CategoryType,
|
||||||
|
channelId: string,
|
||||||
|
clickAction?: string,
|
||||||
|
color: string,
|
||||||
|
colorized: boolean,
|
||||||
|
contentInfo: string,
|
||||||
|
defaults: DefaultsType[],
|
||||||
|
group: string,
|
||||||
|
groupAlertBehaviour: GroupAlertType,
|
||||||
|
groupSummary: boolean,
|
||||||
|
largeIcon: string,
|
||||||
|
lights: Lights,
|
||||||
|
localOnly: boolean,
|
||||||
|
number: number,
|
||||||
|
ongoing: boolean,
|
||||||
|
onlyAlertOnce: boolean,
|
||||||
|
people: string[],
|
||||||
|
priority: PriorityType,
|
||||||
|
progress: Progress,
|
||||||
|
// publicVersion: Notification,
|
||||||
|
remoteInputHistory: string[],
|
||||||
|
shortcutId: string,
|
||||||
|
showWhen: boolean,
|
||||||
|
smallIcon: SmallIcon,
|
||||||
|
sortKey: string,
|
||||||
|
// TODO: style: Style,
|
||||||
|
ticker: string,
|
||||||
|
timeoutAfter: number,
|
||||||
|
usesChronometer: boolean,
|
||||||
|
vibrate: number[],
|
||||||
|
visibility: VisibilityType,
|
||||||
|
when: number,
|
||||||
|
|};
|
||||||
|
|
||||||
|
export type AttachmentOptions = {|
|
||||||
|
TypeHint: string,
|
||||||
|
ThumbnailHidden: boolean,
|
||||||
|
ThumbnailClippingRect: {
|
||||||
|
height: number,
|
||||||
|
width: number,
|
||||||
|
x: number,
|
||||||
|
y: number,
|
||||||
|
},
|
||||||
|
ThumbnailTime: number,
|
||||||
|
|};
|
||||||
|
|
||||||
|
export type Attachment = {|
|
||||||
|
identifier: string,
|
||||||
|
options?: AttachmentOptions,
|
||||||
|
url: string,
|
||||||
|
|};
|
||||||
|
|
||||||
|
export type NativeIOSNotification = {|
|
||||||
|
alertAction?: string,
|
||||||
|
attachments: Attachment[],
|
||||||
|
badge?: number,
|
||||||
|
category?: string,
|
||||||
|
hasAction?: boolean,
|
||||||
|
launchImage?: string,
|
||||||
|
threadIdentifier?: string,
|
||||||
|
|};
|
||||||
|
|
||||||
|
export type Schedule = {
|
||||||
|
exact?: boolean,
|
||||||
|
fireDate: number,
|
||||||
|
repeatInterval?: 'minute' | 'hour' | 'day' | 'week',
|
||||||
|
};
|
||||||
|
|
||||||
|
export type NativeNotification = {|
|
||||||
|
android?: NativeAndroidNotification,
|
||||||
|
body: string,
|
||||||
|
data: { [string]: string },
|
||||||
|
ios?: NativeIOSNotification,
|
||||||
|
notificationId: string,
|
||||||
|
schedule?: Schedule,
|
||||||
|
sound?: string,
|
||||||
|
subtitle?: string,
|
||||||
|
title: string,
|
||||||
|
|};
|
Loading…
Reference in New Issue