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
@implementation RNFirebaseNotifications {
BOOL isUserHandlingOnNotificationDisplayed;
NSMutableDictionary<NSString *, void (^)(UIBackgroundFetchResult)> *completionHandlers;
}
@ -57,6 +56,7 @@ 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
@ -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) {
void (^completionHandler)(UIBackgroundFetchResult) = completionHandlers[handlerKey];
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
- (void)didReceiveRemoteNotification:(NSDictionary *)userInfo
fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
@ -153,6 +119,7 @@ RCT_EXPORT_METHOD(complete:(NSString*)handlerKey fetchResult:(UIBackgroundFetchR
}
NSDictionary *notification = [self parseUserInfo:userInfo];
NSString *handlerKey = notification[@"notificationId"];
NSString *event;
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];
}

View File

@ -128,11 +128,14 @@ export default class Notifications extends ModuleBase {
android: () => {},
});
SharedEventEmitter.emit(
'onNotificationDisplayed',
rnNotification,
done
);
const publicEventName = 'onNotificationDisplayed';
if (!hasListeners(publicEventName)) {
// 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
): () => any {
const isNext = isFunction(nextOrObserver);
const isObserver = isObject(nextOrObserver) && isFunction(nextOrObserver.next);
if (!isNext && !isObserver) {
const isObserver =
isObject(nextOrObserver) && isFunction(nextOrObserver.next);
const eventName = 'onNotificationDisplayed';
if (!isNext && !isObserver) {
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;
}
const autoCompletingListener: OnNotification = async (notification, done) => {
const autoCompletingListener: OnNotification = async (
notification,
done
) => {
const listenerResult = await listener(notification, done);
done(this.backgroundFetchResult.noData);
return listenerResult;
};
getLogger(this).info('Creating onNotificationDisplayed listener');
SharedEventEmitter.addListener('onNotificationDisplayed', autoCompletingListener);
if (hasListeners('onNotificationDisplayed')) {
getNativeModule(this).startHandlingNotificationDisplayed();
}
getLogger(this).info(`Creating ${eventName} listener`);
SharedEventEmitter.addListener(eventName, autoCompletingListener);
return () => {
getLogger(this).info('Removing onNotificationDisplayed listener');
SharedEventEmitter.removeListener('onNotificationDisplayed', autoCompletingListener);
if (!hasListeners('onNotificationDisplayed')) {
getNativeModule(this).stopHandlingNotificationDisplayed();
}
getLogger(this).info(`Removing ${eventName} listener`);
SharedEventEmitter.removeListener(eventName, autoCompletingListener);
};
}