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
|
@end
|
||||||
|
|
||||||
@implementation RNFirebaseNotifications {
|
@implementation RNFirebaseNotifications {
|
||||||
|
BOOL isUserHandlingOnNotificationDisplayed;
|
||||||
NSMutableDictionary<NSString *, void (^)(UIBackgroundFetchResult)> *completionHandlers;
|
NSMutableDictionary<NSString *, void (^)(UIBackgroundFetchResult)> *completionHandlers;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,8 +57,6 @@ RCT_EXPORT_MODULE();
|
||||||
|
|
||||||
// Set static instance for use from AppDelegate
|
// Set static instance for use from AppDelegate
|
||||||
theRNFirebaseNotifications = self;
|
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
|
// 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) {
|
RCT_EXPORT_METHOD(complete:(NSString*)handlerKey fetchResult:(NSString *)rnFetchResult) {
|
||||||
UIBackgroundFetchResult fetchResult = UIBackgroundFetchResultNoData;
|
UIBackgroundFetchResult fetchResult = UIBackgroundFetchResultNoData;
|
||||||
if ([@"noData" isEqualToString:rnFetchResult]) {
|
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
|
// Listen for background messages
|
||||||
- (void)didReceiveRemoteNotification:(NSDictionary *)userInfo
|
- (void)didReceiveRemoteNotification:(NSDictionary *)userInfo
|
||||||
fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
|
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
|
// Pass them over to the RNFirebaseMessaging handler instead
|
||||||
if (userInfo[@"aps"] && ((NSDictionary*)userInfo[@"aps"]).count == 1 && userInfo[@"aps"][@"content-available"]) {
|
if (userInfo[@"aps"] && ((NSDictionary*)userInfo[@"aps"]).count == 1 && userInfo[@"aps"][@"content-available"]) {
|
||||||
[[RNFirebaseMessaging instance] didReceiveRemoteNotification:userInfo];
|
[[RNFirebaseMessaging instance] didReceiveRemoteNotification:userInfo];
|
||||||
|
completionHandler(UIBackgroundFetchResultNoData);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NSDictionary *notification = [self parseUserInfo:userInfo];
|
||||||
|
|
||||||
NSString *event;
|
NSString *event;
|
||||||
if (RCTSharedApplication().applicationState == UIApplicationStateBackground) {
|
if (RCTSharedApplication().applicationState == UIApplicationStateBackground) {
|
||||||
event = NOTIFICATIONS_NOTIFICATION_DISPLAYED;
|
event = NOTIFICATIONS_NOTIFICATION_DISPLAYED;
|
||||||
|
@ -141,10 +167,10 @@ RCT_EXPORT_METHOD(complete:(NSString*)handlerKey fetchResult:(NSString *)rnFetch
|
||||||
// - foreground notifications also go through willPresentNotification
|
// - foreground notifications also go through willPresentNotification
|
||||||
// - background notification presses also go through didReceiveNotificationResponse
|
// - background notification presses also go through didReceiveNotificationResponse
|
||||||
// This prevents duplicate messages from hitting the JS app
|
// This prevents duplicate messages from hitting the JS app
|
||||||
|
completionHandler(UIBackgroundFetchResultNoData);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
NSDictionary *notification = [self parseUserInfo:userInfo];
|
|
||||||
// For onOpened events, we set the default action name as iOS 8/9 has no concept of actions
|
// For onOpened events, we set the default action name as iOS 8/9 has no concept of actions
|
||||||
if (event == NOTIFICATIONS_NOTIFICATION_OPENED) {
|
if (event == NOTIFICATIONS_NOTIFICATION_OPENED) {
|
||||||
notification = @{
|
notification = @{
|
||||||
|
@ -153,8 +179,7 @@ RCT_EXPORT_METHOD(complete:(NSString*)handlerKey fetchResult:(NSString *)rnFetch
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
NSString *handlerKey = notification[@"notificationId"];
|
[self executeOrStoreCompletionHandler:completionHandler notification:notification];
|
||||||
completionHandlers[handlerKey] = completionHandler;
|
|
||||||
|
|
||||||
[self sendJSEvent:self name:event body:notification];
|
[self sendJSEvent:self name:event body:notification];
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,6 +54,11 @@ const NATIVE_EVENTS = [
|
||||||
export const MODULE_NAME = 'RNFirebaseNotifications';
|
export const MODULE_NAME = 'RNFirebaseNotifications';
|
||||||
export const NAMESPACE = 'notifications';
|
export const NAMESPACE = 'notifications';
|
||||||
|
|
||||||
|
const hasListeners = (eventType: string): boolean => {
|
||||||
|
const listeners = SharedEventEmitter.listeners(eventType);
|
||||||
|
return listeners && listeners.length;
|
||||||
|
};
|
||||||
|
|
||||||
// iOS 8/9 scheduling
|
// iOS 8/9 scheduling
|
||||||
// fireDate: Date;
|
// fireDate: Date;
|
||||||
// timeZone: TimeZone;
|
// timeZone: TimeZone;
|
||||||
|
@ -255,11 +260,23 @@ export default class Notifications extends ModuleBase {
|
||||||
}
|
}
|
||||||
|
|
||||||
getLogger(this).info('Creating onNotificationDisplayed listener');
|
getLogger(this).info('Creating onNotificationDisplayed listener');
|
||||||
SharedEventEmitter.addListener('onNotificationDisplayed', listener);
|
SharedEventEmitter.addListener(
|
||||||
|
'onNotificationDisplayed',
|
||||||
|
listener
|
||||||
|
);
|
||||||
|
if (hasListeners('onNotificationDisplayed')) {
|
||||||
|
getNativeModule(this).startHandlingNotificationDisplayed();
|
||||||
|
}
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
getLogger(this).info('Removing onNotificationDisplayed listener');
|
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