From c5778c3d0dfeb68666abe8ff38802787760cdc52 Mon Sep 17 00:00:00 2001 From: Chris Bianca Date: Fri, 23 Feb 2018 16:11:59 +0000 Subject: [PATCH] [notifications] JS tidy up --- .../messaging/RNFirebaseMessaging.m | 61 ------ .../notifications/RNFirebaseNotifications.m | 2 +- lib/index.js | 1 - lib/modules/messaging/Message.js | 108 ---------- lib/modules/messaging/RemoteMessage.js | 58 ++++-- lib/modules/messaging/index.js | 31 +-- lib/modules/messaging/types.js | 40 +--- .../notifications/AndroidNotification.js | 188 +++++++++++++++--- lib/modules/notifications/IOSNotification.js | 28 +++ lib/modules/notifications/Notification.js | 26 ++- lib/modules/notifications/types.js | 56 +++--- .../ios/ReactNativeFirebaseDemo/AppDelegate.m | 4 - 12 files changed, 307 insertions(+), 296 deletions(-) delete mode 100644 lib/modules/messaging/Message.js diff --git a/ios/RNFirebase/messaging/RNFirebaseMessaging.m b/ios/RNFirebase/messaging/RNFirebaseMessaging.m index 31365c80..4af1e1b3 100644 --- a/ios/RNFirebase/messaging/RNFirebaseMessaging.m +++ b/ios/RNFirebase/messaging/RNFirebaseMessaging.m @@ -14,10 +14,6 @@ #if defined(__IPHONE_10_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_10_0 @import UserNotifications; #endif -@interface RNFirebaseMessaging () -@property (nonatomic, strong) NSMutableDictionary *callbackHandlers; -@end - @implementation RNFirebaseMessaging @@ -47,9 +43,6 @@ RCT_EXPORT_MODULE() // Set static instance for use from AppDelegate theRNFirebaseMessaging = self; - - // Initialise callback handlers dictionary - _callbackHandlers = [NSMutableDictionary dictionary]; } // ******************************************************* @@ -187,60 +180,6 @@ RCT_EXPORT_METHOD(unsubscribeFromTopic: (NSString*) topic) { [[FIRMessaging messaging] unsubscribeFromTopic:topic]; } -// Response handler methods - -RCT_EXPORT_METHOD(completeNotificationResponse: (NSString*) messageId) { - void(^callbackHandler)() = [_callbackHandlers objectForKey:messageId]; - if (!callbackHandler) { - NSLog(@"There is no callback handler for messageId: %@", messageId); - return; - } - callbackHandler(); - [_callbackHandlers removeObjectForKey:messageId]; -} - -RCT_EXPORT_METHOD(completePresentNotification: (NSString*) messageId - result: (NSString*) result) { - void(^callbackHandler)(UNNotificationPresentationOptions) = [_callbackHandlers objectForKey:messageId]; - if (!callbackHandler) { - NSLog(@"There is no callback handler for messageId: %@", messageId); - return; - } - UNNotificationPresentationOptions options; - if ([result isEqualToString:@"UNNotificationPresentationOptionAll"]) { - options = UNNotificationPresentationOptionAlert | UNNotificationPresentationOptionBadge | UNNotificationPresentationOptionSound; - } else if ([result isEqualToString:@"UNNotificationPresentationOptionNone"]) { - options = UNNotificationPresentationOptionNone; - } else { - NSLog(@"Invalid result for PresentNotification: %@", result); - return; - } - callbackHandler(options); - [_callbackHandlers removeObjectForKey:messageId]; -} - -RCT_EXPORT_METHOD(completeRemoteNotification: (NSString*) messageId - result: (NSString*) result) { - void(^callbackHandler)(UIBackgroundFetchResult) = [_callbackHandlers objectForKey:messageId]; - if (!callbackHandler) { - NSLog(@"There is no callback handler for messageId: %@", messageId); - return; - } - UIBackgroundFetchResult fetchResult; - if ([result isEqualToString:@"UIBackgroundFetchResultNewData"]) { - fetchResult = UIBackgroundFetchResultNewData; - } else if ([result isEqualToString:@"UIBackgroundFetchResultNoData"]) { - fetchResult = UIBackgroundFetchResultNoData; - } else if ([result isEqualToString:@"UIBackgroundFetchResultFailed"]) { - fetchResult = UIBackgroundFetchResultFailed; - } else { - NSLog(@"Invalid result for PresentNotification: %@", result); - return; - } - callbackHandler(fetchResult); - [_callbackHandlers removeObjectForKey:messageId]; -} - // ** Start internals ** - (NSDictionary*)parseFIRMessagingRemoteMessage:(FIRMessagingRemoteMessage *)remoteMessage { diff --git a/ios/RNFirebase/notifications/RNFirebaseNotifications.m b/ios/RNFirebase/notifications/RNFirebaseNotifications.m index beb733a0..fda16c66 100644 --- a/ios/RNFirebase/notifications/RNFirebaseNotifications.m +++ b/ios/RNFirebase/notifications/RNFirebaseNotifications.m @@ -378,7 +378,7 @@ RCT_EXPORT_METHOD(setBadge: (NSInteger) number) { initialNotification = body; } // PRE-BRIDGE-EVENTS: Consider enabling this to allow events built up before the bridge is built to be sent to the JS side - [pendingEvents addObject:@{@"name":name, @"body":body}]; + // [pendingEvents addObject:@{@"name":name, @"body":body}]; } } diff --git a/lib/index.js b/lib/index.js index 8d7a7cc2..6cd42dce 100644 --- a/lib/index.js +++ b/lib/index.js @@ -68,7 +68,6 @@ export type { default as WriteBatch } from './modules/firestore/WriteBatch'; /* * Export Messaging types */ -export type { default as Message } from './modules/messaging/Message'; export type { default as RemoteMessage, } from './modules/messaging/RemoteMessage'; diff --git a/lib/modules/messaging/Message.js b/lib/modules/messaging/Message.js deleted file mode 100644 index 38f3433f..00000000 --- a/lib/modules/messaging/Message.js +++ /dev/null @@ -1,108 +0,0 @@ -/** - * @flow - * Message representation wrapper - */ -import { Platform } from 'react-native'; -import { getNativeModule } from '../../utils/native'; -import { - MessageType, - PresentNotificationResult, - RemoteNotificationResult, -} from './types'; -import type Messaging from './'; -import type { - NativeMessage, - PresentNotificationResultType, - RemoteNotificationResultType, -} from './types'; - -/** - * @class Message - */ -export default class Message { - _completed: boolean; - _messaging: Messaging; - _message: NativeMessage; - - constructor(messaging: Messaging, message: NativeMessage) { - this._messaging = messaging; - this._message = message; - } - - get collapseKey(): ?string { - return this._message.collapseKey; - } - - get data(): { [string]: string } { - return this._message.data; - } - - get from(): ?string { - return this._message.from; - } - - get messageId(): ?string { - return this._message.messageId; - } - - get sentTime(): ?number { - return this._message.sentTime; - } - - get to(): ?string { - return this._message.to; - } - - get ttl(): ?number { - return this._message.ttl; - } - - complete( - result?: PresentNotificationResultType | RemoteNotificationResultType - ): void { - if (Platform.OS === 'android') { - return; - } - - if (!this._completed) { - this._completed = true; - - switch (this.messageType) { - case MessageType.NotificationResponse: - getNativeModule(this._messaging).completeNotificationResponse( - this.messageId - ); - break; - - case MessageType.PresentNotification: - if ( - result && - !Object.values(PresentNotificationResult).includes(result) - ) { - throw new Error(`Invalid PresentNotificationResult: ${result}`); - } - getNativeModule(this._messaging).completePresentNotification( - this.messageId, - result || PresentNotificationResult.None - ); - break; - - case MessageType.RemoteNotificationHandler: - if ( - result && - !Object.values(RemoteNotificationResult).includes(result) - ) { - throw new Error(`Invalid RemoteNotificationResult: ${result}`); - } - getNativeModule(this._messaging).completeRemoteNotification( - this.messageId, - result || RemoteNotificationResult.NoData - ); - break; - - default: - break; - } - } - } -} diff --git a/lib/modules/messaging/RemoteMessage.js b/lib/modules/messaging/RemoteMessage.js index 15a8493f..e99de6ca 100644 --- a/lib/modules/messaging/RemoteMessage.js +++ b/lib/modules/messaging/RemoteMessage.js @@ -4,30 +4,64 @@ */ import { isObject, generatePushID } from './../../utils'; -type NativeRemoteMessage = { - collapseKey?: string, - data: { [string]: string }, - messageId: string, - messageType?: string, - to: string, - ttl: number, -}; +import type { + NativeInboundRemoteMessage, + NativeOutboundRemoteMessage, +} from './types'; export default class RemoteMessage { _collapseKey: string | void; _data: { [string]: string }; + _from: string | void; _messageId: string; _messageType: string | void; + _sentTime: number | void; _to: string; _ttl: number; - constructor() { - this._data = {}; + constructor(inboundMessage?: NativeInboundRemoteMessage) { + if (inboundMessage) { + this._collapseKey = inboundMessage.collapseKey; + this._data = inboundMessage.data; + this._from = inboundMessage.from; + this._messageId = inboundMessage.messageId; + this._sentTime = inboundMessage.sentTime; + } + // defaults + this._data = this._data || {}; // TODO: Is this the best way to generate an ID? - this._messageId = generatePushID(); + this._messageId = this._messageId || generatePushID(); this._ttl = 3600; } + get collapseKey(): ?string { + return this._collapseKey; + } + + get data(): { [string]: string } { + return this._data; + } + + get from(): ?string { + return this._from; + } + + get messageId(): ?string { + return this._messageId; + } + + get sentTime(): ?number { + return this._sentTime; + } + + get to(): ?string { + return this._to; + } + + get ttl(): ?number { + return this._ttl; + } + /** * * @param collapseKey @@ -83,7 +117,7 @@ export default class RemoteMessage { return this; } - build(): NativeRemoteMessage { + build(): NativeOutboundRemoteMessage { if (!this.data) { throw new Error('RemoteMessage: Missing required `data` property'); } else if (!this.messageId) { diff --git a/lib/modules/messaging/index.js b/lib/modules/messaging/index.js index 5b658afd..ad46838b 100644 --- a/lib/modules/messaging/index.js +++ b/lib/modules/messaging/index.js @@ -8,18 +8,12 @@ import { getLogger } from '../../utils/log'; import ModuleBase from '../../utils/ModuleBase'; import { getNativeModule } from '../../utils/native'; import { isFunction, isObject } from '../../utils'; -import Message from './Message'; import RemoteMessage from './RemoteMessage'; -import { - MessageType, - PresentNotificationResult, - RemoteNotificationResult, -} from './types'; import type App from '../core/app'; -import type { NativeMessage } from './types'; +import type { NativeInboundRemoteMessage } from './types'; -type OnMessage = Message => any; +type OnMessage = RemoteMessage => any; type OnMessageObserver = { next: OnMessage, @@ -55,8 +49,8 @@ export default class Messaging extends ModuleBase { // sub to internal native event - this fans out to // public event name: onMessage 'messaging_message_received', - (message: NativeMessage) => { - SharedEventEmitter.emit('onMessage', new Message(this, message)); + (message: NativeInboundRemoteMessage) => { + SharedEventEmitter.emit('onMessage', new RemoteMessage(message)); } ); @@ -75,7 +69,7 @@ export default class Messaging extends ModuleBase { } onMessage(nextOrObserver: OnMessage | OnMessageObserver): () => any { - let listener: Message => any; + let listener: RemoteMessage => any; if (isFunction(nextOrObserver)) { // $FlowBug: Not coping with the overloaded method signature listener = nextOrObserver; @@ -89,24 +83,20 @@ export default class Messaging extends ModuleBase { getLogger(this).info('Creating onMessage listener'); - const wrappedListener = async (message: Message) => { - await listener(message); - message.complete(); - }; - - SharedEventEmitter.addListener('onMessage', wrappedListener); + SharedEventEmitter.addListener('onMessage', listener); return () => { getLogger(this).info('Removing onMessage listener'); - SharedEventEmitter.removeListener('onMessage', wrappedListener); + SharedEventEmitter.removeListener('onMessage', listener); }; } onTokenRefresh( nextOrObserver: OnTokenRefresh | OnTokenRefreshObserver ): () => any { - let listener; + let listener: String => any; if (isFunction(nextOrObserver)) { + // $FlowBug: Not coping with the overloaded method signature listener = nextOrObserver; } else if (isObject(nextOrObserver) && isFunction(nextOrObserver.next)) { listener = nextOrObserver.next; @@ -186,8 +176,5 @@ export default class Messaging extends ModuleBase { } export const statics = { - MessageType, - PresentNotificationResult, RemoteMessage, - RemoteNotificationResult, }; diff --git a/lib/modules/messaging/types.js b/lib/modules/messaging/types.js index 3b58201a..1d187e30 100644 --- a/lib/modules/messaging/types.js +++ b/lib/modules/messaging/types.js @@ -1,35 +1,6 @@ /** * @flow */ - -export const MessageType = { - InitialMessage: 'InitialMessage', - NotificationResponse: 'NotificationResponse', - PresentNotification: 'PresentNotification', - RemoteMessage: 'RemoteMessage', - RemoteNotification: 'RemoteNotification', - RemoteNotificationHandler: 'RemoteNotificationHandler', -}; - -export const PresentNotificationResult = { - All: 'UNNotificationPresentationOptionAll', - None: 'UNNotificationPresentationOptionNone', -}; - -export const RemoteNotificationResult = { - NewData: 'UIBackgroundFetchResultNewData', - NoData: 'UIBackgroundFetchResultNoData', - ResultFailed: 'UIBackgroundFetchResultFailed', -}; - -export type MessageTypeType = $Values; -export type PresentNotificationResultType = $Values< - typeof PresentNotificationResult ->; -export type RemoteNotificationResultType = $Values< - typeof RemoteNotificationResult ->; - export type Notification = { body: string, bodyLocalizationArgs?: string[], @@ -46,7 +17,7 @@ export type Notification = { titleLocalizationKey?: string, }; -export type NativeMessage = { +export type NativeInboundRemoteMessage = { collapseKey?: string, data: { [string]: string }, from?: string, @@ -55,3 +26,12 @@ export type NativeMessage = { to?: string, ttl?: number, }; + +export type NativeOutboundRemoteMessage = { + collapseKey?: string, + data: { [string]: string }, + messageId: string, + messageType?: string, + to: string, + ttl: number, +}; diff --git a/lib/modules/notifications/AndroidNotification.js b/lib/modules/notifications/AndroidNotification.js index c3305e0b..2b33d4d2 100644 --- a/lib/modules/notifications/AndroidNotification.js +++ b/lib/modules/notifications/AndroidNotification.js @@ -20,41 +20,41 @@ import type { export default class AndroidNotification { // TODO optional fields // TODO actions: Action[]; // icon, title, ??pendingIntent??, allowGeneratedReplies, extender, extras, remoteinput (ugh) - _autoCancel: boolean; - _badgeIconType: BadgeIconTypeType; - _category: CategoryType; + _autoCancel: boolean | void; + _badgeIconType: BadgeIconTypeType | void; + _category: CategoryType | void; _channelId: string; _clickAction: string | void; - _color: string; - _colorized: boolean; - _contentInfo: string; - _defaults: DefaultsType[]; - _group: string; - _groupAlertBehaviour: GroupAlertType; - _groupSummary: boolean; - _largeIcon: string; - _lights: Lights; - _localOnly: boolean; + _color: string | void; + _colorized: boolean | void; + _contentInfo: string | void; + _defaults: DefaultsType[] | void; + _group: string | void; + _groupAlertBehaviour: GroupAlertType | void; + _groupSummary: boolean | void; + _largeIcon: string | void; + _lights: Lights | void; + _localOnly: boolean | void; _notification: Notification; - _number: number; - _ongoing: boolean; - _onlyAlertOnce: boolean; + _number: number | void; + _ongoing: boolean | void; + _onlyAlertOnce: boolean | void; _people: string[]; - _priority: PriorityType; - _progress: Progress; + _priority: PriorityType | void; + _progress: Progress | void; // _publicVersion: Notification; - _remoteInputHistory: string[]; - _shortcutId: string; - _showWhen: boolean; + _remoteInputHistory: string[] | void; + _shortcutId: string | void; + _showWhen: boolean | void; _smallIcon: SmallIcon; - _sortKey: string; + _sortKey: string | void; // TODO: style: Style; // Need to figure out if this can work - _ticker: string; - _timeoutAfter: number; - _usesChronometer: boolean; - _vibrate: number[]; - _visibility: VisibilityType; - _when: number; + _ticker: string | void; + _timeoutAfter: number | void; + _usesChronometer: boolean | void; + _vibrate: number[] | void; + _visibility: VisibilityType | void; + _when: number | void; // android unsupported // content: RemoteViews @@ -112,6 +112,134 @@ export default class AndroidNotification { }; } + get autoCancel(): ?boolean { + return this._autoCancel; + } + + get badgeIconType(): ?BadgeIconTypeType { + return this._badgeIconType; + } + + get category(): ?CategoryType { + return this._category; + } + + get channelId(): string { + return this._channelId; + } + + get clickAction(): ?string { + return this._clickAction; + } + + get color(): ?string { + return this._color; + } + + get colorized(): ?boolean { + return this._colorized; + } + + get contentInfo(): ?string { + return this._contentInfo; + } + + get defaults(): ?(DefaultsType[]) { + return this._defaults; + } + + get group(): ?string { + return this._group; + } + + get groupAlertBehaviour(): ?GroupAlertType { + return this._groupAlertBehaviour; + } + + get groupSummary(): ?boolean { + return this._groupSummary; + } + + get largeIcon(): ?string { + return this._largeIcon; + } + + get lights(): ?Lights { + return this._lights; + } + + get localOnly(): ?boolean { + return this._localOnly; + } + + get number(): ?number { + return this._number; + } + + get ongoing(): ?boolean { + return this._ongoing; + } + + get onlyAlertOnce(): ?boolean { + return this._onlyAlertOnce; + } + + get people(): string[] { + return this._people; + } + + get priority(): ?PriorityType { + return this._priority; + } + + get progress(): ?Progress { + return this._progress; + } + + get remoteInputHistory(): ?(string[]) { + return this._remoteInputHistory; + } + + get shortcutId(): ?string { + return this._shortcutId; + } + + get showWhen(): ?boolean { + return this._showWhen; + } + + get smallIcon(): SmallIcon { + return this._smallIcon; + } + + get sortKey(): ?string { + return this._sortKey; + } + + get ticker(): ?string { + return this._ticker; + } + + get timeoutAfter(): ?number { + return this._timeoutAfter; + } + + get usesChronometer(): ?boolean { + return this._usesChronometer; + } + + get vibrate(): ?(number[]) { + return this._vibrate; + } + + get visibility(): ?VisibilityType { + return this._visibility; + } + + get when(): ?number { + return this._when; + } + /** * * @param person @@ -451,6 +579,10 @@ export default class AndroidNotification { throw new Error( 'AndroidNotification: Missing required `channelId` property' ); + } else if (!this._smallIcon) { + throw new Error( + 'AndroidNotification: Missing required `smallIcon` property' + ); } return { diff --git a/lib/modules/notifications/IOSNotification.js b/lib/modules/notifications/IOSNotification.js index 5b1e563b..b78e97bd 100644 --- a/lib/modules/notifications/IOSNotification.js +++ b/lib/modules/notifications/IOSNotification.js @@ -36,6 +36,34 @@ export default class IOSNotification { this._attachments = this._attachments || []; } + get alertAction(): ?string { + return this._alertAction; + } + + get attachments(): Attachment[] { + return this._attachments; + } + + get badge(): ?number { + return this._badge; + } + + get category(): ?string { + return this._category; + } + + get hasAction(): ?boolean { + return this._hasAction; + } + + get launchImage(): ?string { + return this._launchImage; + } + + get threadIdentifier(): ?string { + return this._threadIdentifier; + } + /** * * @param identifier diff --git a/lib/modules/notifications/Notification.js b/lib/modules/notifications/Notification.js index 1ad7d2cd..734c4441 100644 --- a/lib/modules/notifications/Notification.js +++ b/lib/modules/notifications/Notification.js @@ -32,7 +32,6 @@ export default class Notification { if (data) { 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; @@ -41,6 +40,7 @@ export default class Notification { // Defaults this._data = this._data || {}; + // TODO: Is this the best way to generate an ID? this._notificationId = this._notificationId || generatePushID(); } @@ -48,10 +48,34 @@ export default class Notification { return this._android; } + get body(): string { + return this._body; + } + + get data(): { [string]: string } { + return this._data; + } + get ios(): IOSNotification { return this._ios; } + get notificationId(): string { + return this._notificationId; + } + + get sound(): ?string { + return this._sound; + } + + get subtitle(): ?string { + return this._subtitle; + } + + get title(): string { + return this._title; + } + /** * * @param body diff --git a/lib/modules/notifications/types.js b/lib/modules/notifications/types.js index 9c2abe10..22760c16 100644 --- a/lib/modules/notifications/types.js +++ b/lib/modules/notifications/types.js @@ -79,40 +79,40 @@ export type SmallIcon = { export type NativeAndroidNotification = {| // TODO actions: Action[], - autoCancel: boolean, - badgeIconType: BadgeIconTypeType, - category: CategoryType, + 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, + 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, + priority?: PriorityType, + progress?: Progress, // publicVersion: Notification, - remoteInputHistory: string[], - shortcutId: string, - showWhen: boolean, + remoteInputHistory?: string[], + shortcutId?: string, + showWhen?: boolean, smallIcon: SmallIcon, - sortKey: string, + sortKey?: string, // TODO: style: Style, - ticker: string, - timeoutAfter: number, - usesChronometer: boolean, - vibrate: number[], - visibility: VisibilityType, - when: number, + ticker?: string, + timeoutAfter?: number, + usesChronometer?: boolean, + vibrate?: number[], + visibility?: VisibilityType, + when?: number, |}; export type AttachmentOptions = {| diff --git a/tests/ios/ReactNativeFirebaseDemo/AppDelegate.m b/tests/ios/ReactNativeFirebaseDemo/AppDelegate.m index 88cfe550..81105040 100644 --- a/tests/ios/ReactNativeFirebaseDemo/AppDelegate.m +++ b/tests/ios/ReactNativeFirebaseDemo/AppDelegate.m @@ -38,10 +38,6 @@ return YES; } -- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo { - [[RNFirebaseNotifications instance] didReceiveRemoteNotification:userInfo]; -} - - (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler { [[RNFirebaseNotifications instance] didReceiveRemoteNotification:userInfo fetchCompletionHandler:completionHandler];