diff --git a/apps/automated/src/main.ts b/apps/automated/src/main.ts index 1d5076d37..818500f9d 100644 --- a/apps/automated/src/main.ts +++ b/apps/automated/src/main.ts @@ -12,6 +12,13 @@ if (Application.ios) { Application.ios.addNotificationObserver(UIApplicationDidFinishLaunchingNotification, (notification: NSNotification) => { console.log('UIApplicationDidFinishLaunchingNotification:', notification); }); + + // Make sure we can add multiple handlers for the same event. + for (let i = 0; i < 10; i++) { + Application.ios.addDelegateHandler('applicationDidBecomeActive', (application: UIApplication) => { + console.log('applicationDidBecomeActive', i, application); + }); + } } // Common events for both Android and iOS. diff --git a/packages/core/application/application.d.ts b/packages/core/application/application.d.ts index 477f08314..c61ba0098 100644 --- a/packages/core/application/application.d.ts +++ b/packages/core/application/application.d.ts @@ -167,6 +167,14 @@ export class iOSApplication extends ApplicationCommon { */ set delegate(value: UIApplicationDelegate | unknown); + /** + * Adds a delegate handler for the specified delegate method name. This method does not replace an existing handler, + * but rather adds the new handler to the existing chain of handlers. + * @param methodName The name of the delegate method to add a handler for. + * @param handler A function that will be called when the specified delegate method is called. + */ + addDelegateHandler(methodName: T, handler: (typeof UIApplicationDelegate.prototype)[T]): void; + /** * Adds an observer to the default notification center for the specified notification. * For more information, please visit 'https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSNotificationCenter_Class/#//apple_ref/occ/instm/NSNotificationCenter/addObserver:selector:name:object:' diff --git a/packages/core/application/application.ios.ts b/packages/core/application/application.ios.ts index a83d77b6f..4ea488226 100644 --- a/packages/core/application/application.ios.ts +++ b/packages/core/application/application.ios.ts @@ -74,6 +74,7 @@ class Responder extends UIResponder implements UIApplicationDelegate { export class iOSApplication extends ApplicationCommon implements IiOSApplication { private _delegate: UIApplicationDelegate; + private _delegateHandlers = new Map>(); private _window: UIWindow; private _notificationObservers: NotificationObserver[] = []; private _rootView: View; @@ -255,6 +256,44 @@ export class iOSApplication extends ApplicationCommon implements IiOSApplication } } + addDelegateHandler(methodName: T, handler: (typeof UIApplicationDelegate.prototype)[T]): void { + // safe-guard against invalid handlers + if (typeof handler !== 'function') { + return; + } + + // ensure we have a delegate + this.delegate ??= Responder as any; + + const handlers = this._delegateHandlers.get(methodName) ?? []; + + if (!this._delegateHandlers.has(methodName)) { + const originalHandler = this.delegate.prototype[methodName]; + + if (originalHandler) { + // if there is an original handler, we add it to the handlers array to be called first. + handlers.push(originalHandler as Function); + } + + // replace the original method implementation with one that will call all handlers. + this.delegate.prototype[methodName] = function (...args: any[]) { + let res: any; + for (const handler of handlers) { + if (typeof handler !== 'function') { + continue; + } + res = handler.apply(this, args); + } + return res; + } as (typeof UIApplicationDelegate.prototype)[T]; + + // store the handlers + this._delegateHandlers.set(methodName, handlers); + } + + handlers.push(handler); + } + getNativeApplication() { return this.nativeApp; }