Only store completionHandlers on iOS native side when user adds listener
Note the following cases. This commit is catering for case 3: 1. User is listening for onNotificationDisplayed and is manually calling the completionHandler - manually called completionHandler is removed - automatically called completionHandler is guarded against on iOS native side 2. User is listening for onNotificationDisplayed and is not calling the completionHandler: - automatically called completionHandler is removed 3. User is not listening for onNotificationDisplayed - On rn side we can only automatically call completionHandler if the user _is_ listening. This means we need to detect if the user is listening or not.
This commit is contained in:
parent
0d14a5e3b3
commit
5168f96a32
|
@ -17,6 +17,7 @@
|
|||
@end
|
||||
|
||||
@implementation RNFirebaseNotifications {
|
||||
BOOL isUserHandlingOnNotificationDisplayed;
|
||||
NSMutableDictionary<NSString *, void (^)(UIBackgroundFetchResult)> *completionHandlers;
|
||||
}
|
||||
|
||||
|
@ -56,8 +57,6 @@ RCT_EXPORT_MODULE();
|
|||
|
||||
// Set static instance for use from AppDelegate
|
||||
theRNFirebaseNotifications = self;
|
||||
|
||||
completionHandlers = [[NSMutableDictionary alloc] init];
|
||||
}
|
||||
|
||||
// PRE-BRIDGE-EVENTS: Consider enabling this to allow events built up before the bridge is built to be sent to the JS side
|
||||
|
@ -99,6 +98,21 @@ RCT_EXPORT_MODULE();
|
|||
}
|
||||
}
|
||||
|
||||
RCT_EXPORT_METHOD(startHandlingNotificationDisplayed) {
|
||||
isUserHandlingOnNotificationDisplayed = YES;
|
||||
completionHandlers = [[NSMutableDictionary alloc] init];
|
||||
}
|
||||
|
||||
RCT_EXPORT_METHOD(stopHandlingNotificationDisplayed) {
|
||||
isUserHandlingOnNotificationDisplayed = NO;
|
||||
NSArray *allHandlers = completionHandlers.allValues;
|
||||
for (void (^ completionHandler)(UIBackgroundFetchResult) in allHandlers) {
|
||||
completionHandler(UIBackgroundFetchResultNoData);
|
||||
}
|
||||
[completionHandlers removeAllObjects];
|
||||
completionHandlers = nil;
|
||||
}
|
||||
|
||||
RCT_EXPORT_METHOD(complete:(NSString*)handlerKey fetchResult:(NSString *)rnFetchResult) {
|
||||
UIBackgroundFetchResult fetchResult = UIBackgroundFetchResultNoData;
|
||||
if ([@"noData" isEqualToString:rnFetchResult]) {
|
||||
|
@ -117,6 +131,15 @@ RCT_EXPORT_METHOD(complete:(NSString*)handlerKey fetchResult:(NSString *)rnFetch
|
|||
}
|
||||
}
|
||||
|
||||
- (void)executeOrStoreCompletionHandler:(void (^ _Nonnull)(UIBackgroundFetchResult))completionHandler notification:(NSDictionary *)notification {
|
||||
if(isUserHandlingOnNotificationDisplayed) {
|
||||
NSString *handlerKey = notification[@"notificationId"];
|
||||
completionHandlers[handlerKey] = completionHandler;
|
||||
} else {
|
||||
completionHandler(UIBackgroundFetchResultNoData);
|
||||
}
|
||||
}
|
||||
|
||||
// Listen for background messages
|
||||
- (void)didReceiveRemoteNotification:(NSDictionary *)userInfo
|
||||
fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
|
||||
|
@ -124,9 +147,12 @@ RCT_EXPORT_METHOD(complete:(NSString*)handlerKey fetchResult:(NSString *)rnFetch
|
|||
// Pass them over to the RNFirebaseMessaging handler instead
|
||||
if (userInfo[@"aps"] && ((NSDictionary*)userInfo[@"aps"]).count == 1 && userInfo[@"aps"][@"content-available"]) {
|
||||
[[RNFirebaseMessaging instance] didReceiveRemoteNotification:userInfo];
|
||||
completionHandler(UIBackgroundFetchResultNoData);
|
||||
return;
|
||||
}
|
||||
|
||||
NSDictionary *notification = [self parseUserInfo:userInfo];
|
||||
|
||||
NSString *event;
|
||||
if (RCTSharedApplication().applicationState == UIApplicationStateBackground) {
|
||||
event = NOTIFICATIONS_NOTIFICATION_DISPLAYED;
|
||||
|
@ -141,10 +167,10 @@ RCT_EXPORT_METHOD(complete:(NSString*)handlerKey fetchResult:(NSString *)rnFetch
|
|||
// - foreground notifications also go through willPresentNotification
|
||||
// - background notification presses also go through didReceiveNotificationResponse
|
||||
// This prevents duplicate messages from hitting the JS app
|
||||
completionHandler(UIBackgroundFetchResultNoData);
|
||||
return;
|
||||
}
|
||||
|
||||
NSDictionary *notification = [self parseUserInfo:userInfo];
|
||||
// For onOpened events, we set the default action name as iOS 8/9 has no concept of actions
|
||||
if (event == NOTIFICATIONS_NOTIFICATION_OPENED) {
|
||||
notification = @{
|
||||
|
@ -153,8 +179,7 @@ RCT_EXPORT_METHOD(complete:(NSString*)handlerKey fetchResult:(NSString *)rnFetch
|
|||
};
|
||||
}
|
||||
|
||||
NSString *handlerKey = notification[@"notificationId"];
|
||||
completionHandlers[handlerKey] = completionHandler;
|
||||
[self executeOrStoreCompletionHandler:completionHandler notification:notification];
|
||||
|
||||
[self sendJSEvent:self name:event body:notification];
|
||||
}
|
||||
|
|
|
@ -54,6 +54,11 @@ const NATIVE_EVENTS = [
|
|||
export const MODULE_NAME = 'RNFirebaseNotifications';
|
||||
export const NAMESPACE = 'notifications';
|
||||
|
||||
const hasListeners = (eventType: string): boolean => {
|
||||
const listeners = SharedEventEmitter.listeners(eventType);
|
||||
return listeners && listeners.length;
|
||||
};
|
||||
|
||||
// iOS 8/9 scheduling
|
||||
// fireDate: Date;
|
||||
// timeZone: TimeZone;
|
||||
|
@ -255,11 +260,23 @@ export default class Notifications extends ModuleBase {
|
|||
}
|
||||
|
||||
getLogger(this).info('Creating onNotificationDisplayed listener');
|
||||
SharedEventEmitter.addListener('onNotificationDisplayed', listener);
|
||||
SharedEventEmitter.addListener(
|
||||
'onNotificationDisplayed',
|
||||
listener
|
||||
);
|
||||
if (hasListeners('onNotificationDisplayed')) {
|
||||
getNativeModule(this).startHandlingNotificationDisplayed();
|
||||
}
|
||||
|
||||
return () => {
|
||||
getLogger(this).info('Removing onNotificationDisplayed listener');
|
||||
SharedEventEmitter.removeListener('onNotificationDisplayed', listener);
|
||||
SharedEventEmitter.removeListener(
|
||||
'onNotificationDisplayed',
|
||||
listener
|
||||
);
|
||||
if (!hasListeners('onNotificationDisplayed')) {
|
||||
getNativeModule(this).stopHandlingNotificationDisplayed();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue