Add auto call to done which awaits the listener before doing so

The idea is to catch any cases where the API user is not calling done manually.
This has the issue that we've modified pre-existing function to take a
Promisified callback instead of just a callback. Any user upgrading to a
version that contains this that does not read the upgrade guide and make
appropriate changes will:
- be passing a plain callback (not promisified)
- not be calling done
- may be performing async (something that triggers a later callback) in their
onNotificationDisplayed handler.

This all means that we will be auto calling `done` prior to them performing
any background work. This is exactly how things worked prior to these changes
so perhaps the user is no worse off.
This commit is contained in:
Ryan Grey 2018-08-07 14:26:16 +01:00
parent 0291605934
commit ab42108234
1 changed files with 29 additions and 21 deletions

View File

@ -33,7 +33,17 @@ import type {
Schedule,
} from './types';
type OnNotification = Notification => any;
type BackgroundFetchResultValue = string;
type BackgroundFetchResult = {
noData: BackgroundFetchResultValue,
newData: BackgroundFetchResultValue,
failure: BackgroundFetchResultValue,
};
type CompletionHandler = BackgroundFetchResultValue => void;
type OnNotification = (Notification, CompletionHandler) => Promise<any>;
type OnNotificationObserver = {
next: OnNotification,
@ -45,12 +55,6 @@ type OnNotificationOpenedObserver = {
next: NotificationOpen,
};
type BackgroundFetchResult = {
noData: string,
newData: string,
failure: string,
};
const NATIVE_EVENTS = [
'notifications_notification_displayed',
'notifications_notification_opened',
@ -266,32 +270,36 @@ export default class Notifications extends ModuleBase {
onNotificationDisplayed(
nextOrObserver: OnNotification | OnNotificationObserver
): () => any {
let listener;
if (isFunction(nextOrObserver)) {
listener = nextOrObserver;
} else if (isObject(nextOrObserver) && isFunction(nextOrObserver.next)) {
listener = nextOrObserver.next;
} else {
const isNext = isFunction(nextOrObserver);
const isObserver = isObject(nextOrObserver) && isFunction(nextOrObserver.next);
if (!isNext && !isObserver) {
throw new Error(
'Notifications.onNotificationDisplayed failed: First argument must be a function or observer object with a `next` function.'
);
}
let listener: OnNotification;
if (nextOrObserver.next) {
listener = nextOrObserver.next;
} else {
listener = nextOrObserver;
}
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',
listener
);
SharedEventEmitter.addListener('onNotificationDisplayed', autoCompletingListener);
if (hasListeners('onNotificationDisplayed')) {
getNativeModule(this).startHandlingNotificationDisplayed();
}
return () => {
getLogger(this).info('Removing onNotificationDisplayed listener');
SharedEventEmitter.removeListener(
'onNotificationDisplayed',
listener
);
SharedEventEmitter.removeListener('onNotificationDisplayed', autoCompletingListener);
if (!hasListeners('onNotificationDisplayed')) {
getNativeModule(this).stopHandlingNotificationDisplayed();
}