[notifications] Specific notificationPressed data type including action

This commit is contained in:
Chris Bianca 2018-02-22 17:25:15 +00:00
parent 303cb4c428
commit 8e84dd576b
4 changed files with 101 additions and 65 deletions

View File

@ -38,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
@ -51,20 +51,22 @@ RCT_EXPORT_MODULE();
// ******************************************************* // *******************************************************
- (void)didReceiveLocalNotification:(nonnull UILocalNotification *)notification { - (void)didReceiveLocalNotification:(nonnull UILocalNotification *)notification {
NSString *event; #if !defined(__IPHONE_10_0) || __IPHONE_OS_VERSION_MAX_ALLOWED < __IPHONE_10_0
if (RCTSharedApplication().applicationState == UIApplicationStateBackground) { NSString *event;
// notification_displayed if (RCTSharedApplication().applicationState == UIApplicationStateBackground) {
event = NOTIFICATIONS_NOTIFICATION_DISPLAYED; // notification_displayed
} else if (RCTSharedApplication().applicationState == UIApplicationStateInactive) { event = NOTIFICATIONS_NOTIFICATION_DISPLAYED;
// notification_displayed } else if (RCTSharedApplication().applicationState == UIApplicationStateInactive) {
event = NOTIFICATIONS_NOTIFICATION_PRESSED; // notification_displayed
} else { event = NOTIFICATIONS_NOTIFICATION_PRESSED;
// notification_received } else {
event = NOTIFICATIONS_NOTIFICATION_RECEIVED; // notification_received
} event = NOTIFICATIONS_NOTIFICATION_RECEIVED;
}
NSDictionary *message = [self parseUILocalNotification:notification]; NSDictionary *message = [self parseUILocalNotification:notification];
[RNFirebaseUtil sendJSEvent:self name:event body:message]; [RNFirebaseUtil sendJSEvent:self name:event body:message];
#endif
} }
// Listen for background messages // Listen for background messages
@ -85,11 +87,16 @@ RCT_EXPORT_MODULE();
event = NOTIFICATIONS_NOTIFICATION_PRESSED; event = NOTIFICATIONS_NOTIFICATION_PRESSED;
} else { } else {
// notification_received // notification_received
event = NOTIFICATIONS_NOTIFICATION_RECEIVED; // On IOS 10, foreground notifications also go through willPresentNotification
// This prevents duplicate messages from hitting the JS app
#if defined(__IPHONE_10_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_10_0
return;
#else
event = NOTIFICATIONS_NOTIFICATION_RECEIVED;
#endif
} }
// TODO: Proper notification structure NSDictionary *message = [self parseUserInfo:userInfo messageType:@"RemoteNotification" category:nil];
NSDictionary *message = [self parseUserInfo:userInfo messageType:@"RemoteNotification" clickAction:nil];
[RNFirebaseUtil sendJSEvent:self name:event body:message]; [RNFirebaseUtil sendJSEvent:self name:event body:message];
} }
@ -104,6 +111,7 @@ RCT_EXPORT_MODULE();
return; return;
} }
NSString *event; NSString *event;
if (RCTSharedApplication().applicationState == UIApplicationStateBackground) { if (RCTSharedApplication().applicationState == UIApplicationStateBackground) {
// notification_displayed // notification_displayed
@ -113,16 +121,19 @@ RCT_EXPORT_MODULE();
event = NOTIFICATIONS_NOTIFICATION_PRESSED; event = NOTIFICATIONS_NOTIFICATION_PRESSED;
} else { } else {
// notification_received // notification_received
event = NOTIFICATIONS_NOTIFICATION_RECEIVED; // On IOS 10, foreground notifications also go through willPresentNotification
// This prevents duplicate messages from hitting the JS app
#if defined(__IPHONE_10_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_10_0
return;
#else
event = NOTIFICATIONS_NOTIFICATION_RECEIVED;
#endif
} }
// TODO: Proper notification structure NSDictionary *message = [self parseUserInfo:userInfo messageType:@"RemoteNotificationHandler" category:nil];
NSDictionary *message = [self parseUserInfo:userInfo messageType:@"RemoteNotificationHandler" clickAction:nil];
// TODO: Callback handler
// [_callbackHandlers setObject:[completionHandler copy] forKey:message[@"messageId"]];
[RNFirebaseUtil sendJSEvent:self name:event body:message]; [RNFirebaseUtil sendJSEvent:self name:event body:message];
completionHandler(UIBackgroundFetchResultNoData);
} }
// ******************************************************* // *******************************************************
@ -181,7 +192,7 @@ didReceiveNotificationResponse:(UNNotificationResponse *)response
#else #else
withCompletionHandler:(void(^)())completionHandler { withCompletionHandler:(void(^)())completionHandler {
#endif #endif
NSDictionary *message = [self parseUNNotification:response.notification messageType:@"NotificationResponse"]; NSDictionary *message = [self parseUNNotificationResponse:response messageType:@"NotificationResponse"];
[RNFirebaseUtil sendJSEvent:self name:NOTIFICATIONS_NOTIFICATION_PRESSED body:message]; [RNFirebaseUtil sendJSEvent:self name:NOTIFICATIONS_NOTIFICATION_PRESSED body:message];
completionHandler(); completionHandler();
@ -253,7 +264,7 @@ RCT_EXPORT_METHOD(getInitialNotification:(RCTPromiseResolveBlock)resolve rejecte
} else { } else {
NSDictionary *remoteNotification = [self bridge].launchOptions[UIApplicationLaunchOptionsRemoteNotificationKey]; NSDictionary *remoteNotification = [self bridge].launchOptions[UIApplicationLaunchOptionsRemoteNotificationKey];
if (remoteNotification) { if (remoteNotification) {
NSDictionary *message = [self parseUserInfo:remoteNotification messageType:@"InitialMessage" clickAction:nil]; NSDictionary *message = [self parseUserInfo:remoteNotification messageType:@"InitialMessage" category:nil];
resolve(message); resolve(message);
} else { } else {
resolve(nil); resolve(nil);
@ -560,17 +571,27 @@ RCT_EXPORT_METHOD(scheduleNotification:(NSDictionary*) notification
return notification; return notification;
} }
- (NSDictionary*)parseUNNotificationResponse:(UNNotificationResponse *)response
messageType:(NSString *)messageType {
NSMutableDictionary *notificationResponse = [[NSMutableDictionary alloc] init];
NSDictionary *notification = [self parseUNNotification:response.notification messageType:messageType];
notificationResponse[@"notification"] = notification;
notificationResponse[@"action"] = response.actionIdentifier;
return notificationResponse;
}
- (NSDictionary*)parseUNNotification:(UNNotification *)notification - (NSDictionary*)parseUNNotification:(UNNotification *)notification
messageType:(NSString *)messageType { messageType:(NSString *)messageType {
NSDictionary *userInfo = notification.request.content.userInfo; NSDictionary *userInfo = notification.request.content.userInfo;
NSString *clickAction = notification.request.content.categoryIdentifier; NSString *category = notification.request.content.categoryIdentifier;
return [self parseUserInfo:userInfo messageType:messageType clickAction:clickAction]; return [self parseUserInfo:userInfo messageType:messageType category:category];
} }
- (NSDictionary*)parseUserInfo:(NSDictionary *)userInfo - (NSDictionary*)parseUserInfo:(NSDictionary *)userInfo
messageType:(NSString *) messageType messageType:(NSString *) messageType
clickAction:(NSString *) clickAction { category:(NSString *) category {
NSMutableDictionary *notification = [[NSMutableDictionary alloc] init]; NSMutableDictionary *notification = [[NSMutableDictionary alloc] init];
NSMutableDictionary *data = [[NSMutableDictionary alloc] init]; NSMutableDictionary *data = [[NSMutableDictionary alloc] init];
@ -585,22 +606,15 @@ RCT_EXPORT_METHOD(scheduleNotification:(NSDictionary*) notification
for (id k3 in alert) { for (id k3 in alert) {
if ([k3 isEqualToString:@"body"]) { if ([k3 isEqualToString:@"body"]) {
notification[@"body"] = alert[k3]; notification[@"body"] = alert[k3];
} else if ([k3 isEqualToString:@"loc-args"]) {
// TODO: What to do with this?
// notif[@"bodyLocalizationArgs"] = alert[k3];
} else if ([k3 isEqualToString:@"loc-key"]) {
// TODO: What to do with this?
// notif[@"bodyLocalizationKey"] = alert[k3];
} else if ([k3 isEqualToString:@"subtitle"]) { } else if ([k3 isEqualToString:@"subtitle"]) {
notification[@"subtitle"] = alert[k3]; notification[@"subtitle"] = alert[k3];
} else if ([k3 isEqualToString:@"title"]) { } else if ([k3 isEqualToString:@"title"]) {
notification[@"title"] = alert[k3]; notification[@"title"] = alert[k3];
} else if ([k3 isEqualToString:@"title-loc-args"]) { } else if ([k3 isEqualToString:@"loc-args"]
// TODO: What to do with this? || [k3 isEqualToString:@"loc-key"]
// notif[@"titleLocalizationArgs"] = alert[k3]; || [k3 isEqualToString:@"title-loc-args"]
} else if ([k3 isEqualToString:@"title-loc-key"]) { || [k3 isEqualToString:@"title-loc-key"]) {
// TODO: What to do with this? // Ignore known keys
// notif[@"titleLocalizationKey"] = alert[k3];
} else { } else {
NSLog(@"Unknown alert key: %@", k2); NSLog(@"Unknown alert key: %@", k2);
} }
@ -617,15 +631,13 @@ RCT_EXPORT_METHOD(scheduleNotification:(NSDictionary*) notification
} }
} else if ([k1 isEqualToString:@"gcm.message_id"]) { } else if ([k1 isEqualToString:@"gcm.message_id"]) {
notification[@"notificationId"] = userInfo[k1]; notification[@"notificationId"] = userInfo[k1];
} else if ([k1 isEqualToString:@"google.c.a.ts"]) {
// 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"]
|| [k1 isEqualToString:@"google.c.a.c_l"] || [k1 isEqualToString:@"google.c.a.c_l"]
|| [k1 isEqualToString:@"google.c.a.e"] || [k1 isEqualToString:@"google.c.a.e"]
|| [k1 isEqualToString:@"google.c.a.udt"]) { || [k1 isEqualToString:@"google.c.a.udt"]
|| [k1 isEqualToString:@"google.c.a.ts"]) {
// Ignore known keys // Ignore known keys
} else { } else {
// Assume custom data // Assume custom data
@ -633,6 +645,10 @@ RCT_EXPORT_METHOD(scheduleNotification:(NSDictionary*) notification
} }
} }
if (!ios[@"category"]) {
ios[@"category"] = category;
}
// TODO: What to do with this? // TODO: What to do with this?
// message[@"messageType"] = messageType; // message[@"messageType"] = messageType;

View File

@ -9,6 +9,11 @@ import { generatePushID, isObject } from '../../utils';
import type { NativeNotification } from './types'; import type { NativeNotification } from './types';
export type NotificationPressed = {
action: string,
notification: Notification,
};
export default class Notification { export default class Notification {
// iOS 8/9 | 10+ | Android // iOS 8/9 | 10+ | Android
_android: AndroidNotification; _android: AndroidNotification;

View File

@ -18,7 +18,12 @@ import {
} from './types'; } from './types';
import type App from '../core/app'; import type App from '../core/app';
import type { NativeNotification, Schedule } from './types'; import type { NotificationPressed } from './Notification';
import type {
NativeNotification,
NativeNotificationPressed,
Schedule,
} from './types';
type OnNotification = Notification => any; type OnNotification = Notification => any;
@ -26,6 +31,12 @@ type OnNotificationObserver = {
next: OnNotification, next: OnNotification,
}; };
type OnNotificationPressed = NotificationPressed => any;
type OnNotificationPressedObserver = {
next: OnNotificationPressed,
};
const NATIVE_EVENTS = [ const NATIVE_EVENTS = [
'notifications_notification_displayed', 'notifications_notification_displayed',
'notifications_notification_pressed', 'notifications_notification_pressed',
@ -61,18 +72,6 @@ export default class Notifications extends ModuleBase {
namespace: NAMESPACE, namespace: NAMESPACE,
}); });
SharedEventEmitter.addListener(
// sub to internal native event - this fans out to
// public event name: onNotificationPressed
'notifications_notification_pressed',
(notification: NativeNotification) => {
SharedEventEmitter.emit(
'onNotificationPressed',
new Notification(notification)
);
}
);
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: onNotificationDisplayed // public event name: onNotificationDisplayed
@ -85,6 +84,18 @@ export default class Notifications extends ModuleBase {
} }
); );
SharedEventEmitter.addListener(
// sub to internal native event - this fans out to
// public event name: onNotificationPressed
'notifications_notification_pressed',
(notificationPressed: NativeNotificationPressed) => {
SharedEventEmitter.emit('onNotificationPressed', {
action: notificationPressed.action,
notification: new Notification(notificationPressed.notification),
});
}
);
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: onNotification // public event name: onNotification
@ -193,11 +204,10 @@ export default class Notifications extends ModuleBase {
} }
onNotificationPressed( onNotificationPressed(
nextOrObserver: OnNotification | OnNotificationObserver nextOrObserver: OnNotificationPressed | OnNotificationPressedObserver
): () => any { ): () => any {
let listener: Notification => any; let listener;
if (isFunction(nextOrObserver)) { if (isFunction(nextOrObserver)) {
// $FlowBug: Not coping with the overloaded method signature
listener = nextOrObserver; listener = nextOrObserver;
} else if (isObject(nextOrObserver) && isFunction(nextOrObserver.next)) { } else if (isObject(nextOrObserver) && isFunction(nextOrObserver.next)) {
listener = nextOrObserver.next; listener = nextOrObserver.next;

View File

@ -160,3 +160,8 @@ export type NativeNotification = {|
subtitle?: string, subtitle?: string,
title: string, title: string,
|}; |};
export type NativeNotificationPressed = {|
action: string,
notification: NativeNotification,
|};