Auto complete early when no user listeners.

This is to clear up memory on the objective-c side without needing to
signal the start/stop of user listeners.
This commit is contained in:
Ryan Grey 2018-08-10 16:50:40 +01:00
parent a8b4435abf
commit 6a69ae66b1
2 changed files with 25 additions and 56 deletions

View File

@ -17,7 +17,6 @@
@end @end
@implementation RNFirebaseNotifications { @implementation RNFirebaseNotifications {
BOOL isUserHandlingOnNotificationDisplayed;
NSMutableDictionary<NSString *, void (^)(UIBackgroundFetchResult)> *completionHandlers; NSMutableDictionary<NSString *, void (^)(UIBackgroundFetchResult)> *completionHandlers;
} }
@ -57,6 +56,7 @@ 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
@ -98,31 +98,6 @@ RCT_EXPORT_MODULE();
} }
} }
RCT_EXPORT_METHOD(startHandlingNotificationDisplayed) {
if(isUserHandlingOnNotificationDisplayed == YES) {
return;
}
isUserHandlingOnNotificationDisplayed = YES;
completionHandlers = [[NSMutableDictionary alloc] init];
}
RCT_EXPORT_METHOD(stopHandlingNotificationDisplayed) {
if(isUserHandlingOnNotificationDisplayed == NO) {
return;
}
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:(UIBackgroundFetchResult)fetchResult) { RCT_EXPORT_METHOD(complete:(NSString*)handlerKey fetchResult:(UIBackgroundFetchResult)fetchResult) {
void (^completionHandler)(UIBackgroundFetchResult) = completionHandlers[handlerKey]; void (^completionHandler)(UIBackgroundFetchResult) = completionHandlers[handlerKey];
completionHandlers[handlerKey] = nil; completionHandlers[handlerKey] = nil;
@ -132,15 +107,6 @@ RCT_EXPORT_METHOD(complete:(NSString*)handlerKey fetchResult:(UIBackgroundFetchR
} }
} }
- (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 {
@ -153,6 +119,7 @@ RCT_EXPORT_METHOD(complete:(NSString*)handlerKey fetchResult:(UIBackgroundFetchR
} }
NSDictionary *notification = [self parseUserInfo:userInfo]; NSDictionary *notification = [self parseUserInfo:userInfo];
NSString *handlerKey = notification[@"notificationId"];
NSString *event; NSString *event;
if (RCTSharedApplication().applicationState == UIApplicationStateBackground) { if (RCTSharedApplication().applicationState == UIApplicationStateBackground) {
@ -180,8 +147,8 @@ RCT_EXPORT_METHOD(complete:(NSString*)handlerKey fetchResult:(UIBackgroundFetchR
}; };
} }
[self executeOrStoreCompletionHandler:completionHandler notification:notification]; completionHandlers[handlerKey] = completionHandler;
[self sendJSEvent:self name:event body:notification]; [self sendJSEvent:self name:event body:notification];
} }

View File

@ -128,11 +128,14 @@ export default class Notifications extends ModuleBase {
android: () => {}, android: () => {},
}); });
SharedEventEmitter.emit( const publicEventName = 'onNotificationDisplayed';
'onNotificationDisplayed',
rnNotification, if (!hasListeners(publicEventName)) {
done // if user is not handling completion then we need to
); done(this.backgroundFetchResult.noData);
}
SharedEventEmitter.emit(publicEventName, rnNotification, done);
} }
); );
@ -271,10 +274,12 @@ export default class Notifications extends ModuleBase {
nextOrObserver: OnNotification | OnNotificationObserver nextOrObserver: OnNotification | OnNotificationObserver
): () => any { ): () => any {
const isNext = isFunction(nextOrObserver); const isNext = isFunction(nextOrObserver);
const isObserver = isObject(nextOrObserver) && isFunction(nextOrObserver.next); const isObserver =
if (!isNext && !isObserver) { isObject(nextOrObserver) && isFunction(nextOrObserver.next);
const eventName = 'onNotificationDisplayed';
if (!isNext && !isObserver) {
throw new Error( throw new Error(
'Notifications.onNotificationDisplayed failed: First argument must be a function or observer object with a `next` function.' `Notifications.${eventName} failed: First argument must be a function or observer object with a \`next\` function.`
); );
} }
@ -285,24 +290,21 @@ export default class Notifications extends ModuleBase {
listener = nextOrObserver; listener = nextOrObserver;
} }
const autoCompletingListener: OnNotification = async (notification, done) => { const autoCompletingListener: OnNotification = async (
notification,
done
) => {
const listenerResult = await listener(notification, done); const listenerResult = await listener(notification, done);
done(this.backgroundFetchResult.noData); done(this.backgroundFetchResult.noData);
return listenerResult; return listenerResult;
}; };
getLogger(this).info('Creating onNotificationDisplayed listener'); getLogger(this).info(`Creating ${eventName} listener`);
SharedEventEmitter.addListener('onNotificationDisplayed', autoCompletingListener); SharedEventEmitter.addListener(eventName, autoCompletingListener);
if (hasListeners('onNotificationDisplayed')) {
getNativeModule(this).startHandlingNotificationDisplayed();
}
return () => { return () => {
getLogger(this).info('Removing onNotificationDisplayed listener'); getLogger(this).info(`Removing ${eventName} listener`);
SharedEventEmitter.removeListener('onNotificationDisplayed', autoCompletingListener); SharedEventEmitter.removeListener(eventName, autoCompletingListener);
if (!hasListeners('onNotificationDisplayed')) {
getNativeModule(this).stopHandlingNotificationDisplayed();
}
}; };
} }