8000 fix(shared-notification-delegate): userNotificationCenterWillPresentN… · NativeScript/plugins@84fa206 · GitHub
[go: up one dir, main page]

Skip to content

Commit 84fa206

Browse files
authored
fix(shared-notification-delegate): userNotificationCenterWillPresentNotificationWithCompletionHandler must be synchronous (#83)
BREAKING CHANGES: When implementing userNotificationCenterWillPresentNotificationWithCompletionHandler, ensure to call completionHandler synchronously, otherwise it will be sent to another observer or completionHandler(0) will be called.
1 parent bb23c0f commit 84fa206

File tree

1 file changed

+183
-179
lines changed

1 file changed

+183
-179
lines changed

packages/shared-notification-delegate/index.ios.ts

Lines changed: 183 additions & 179 deletions
Original file line numberDiff line numberDiff line change
@@ -1,202 +1,206 @@
11
import { SharedNotificationDelegateCommon } from './common';
22

33
type DeferedPromise<T> = {
4-
promise: Promise<T>;
5-
resolve: (value?: T | PromiseLike<T>) => void;
6-
reject: (reason?: any) => void;
4+
promise: Promise<T>;
5+
resolve: (value?: T | PromiseLike<T>) => void;
6+
reject: (reason?: any) => void;
77
};
88
function createDeferedPromise<T>(): DeferedPromise<T> {
9-
const deferred: DeferedPromise<T> = {
10-
promise: undefined,
11-
reject: undefined,
12-
resolve: undefined
13-
};
14-
15-
deferred.promise = new Promise<T>((resolve, reject) => {
16-
deferred.resolve = resolve;
17-
deferred.reject = reject;
18-
});
19-
return deferred;
9+
const deferred: DeferedPromise<T> = {
10+
promise: undefined,
11+
reject: undefined,
12+
resolve: undefined,
13+
};
14+
15+
deferred.promise = new Promise<T>((resolve, reject) => {
16+
deferred.resolve = resolve;
17+
deferred.reject = reject;
18+
});
19+
return deferred;
2020
}
2121

2222
type StopNextPromise = {
23-
stop: () => void,
24-
next: () => void
23+
stop: () => void;
24+
next: () => void;
2525
} & DeferedPromise<boolean>;
2626

2727
function createStopNextPromise(): StopNextPromise {
28-
const deferred = createDeferedPromise<boolean>();
29-
return {
30-
...deferred,
31-
next: () => deferred.resolve(false),
32-
stop: () => deferred.resolve(true)
33-
};
28+
const deferred = createDeferedPromise<boolean>();
29+
return {
30+
...deferred,
31+
next: () => deferred.resolve(false),
32+
stop: () => deferred.resolve(true),
33+
};
3434
}
3535

3636
@NativeClass()
3737
class UNUserNotificationCenterDelegateImpl extends NSObject implements UNUserNotificationCenterDelegate {
38-
public static ObjCProtocols = [];
39-
40-
static new(): UNUserNotificationCenterDelegateImpl {
41-
if (UNUserNotificationCenterDelegateImpl.ObjCProtocols.length === 0 && typeof (UNUserNotificationCenterDelegate) !== "undefined") {
42-
UNUserNotificationCenterDelegateImpl.ObjCProtocols.push(UNUserNotificationCenterDelegate);
43-
}
44-
return <UNUserNotificationCenterDelegateImpl>super.new();
45-
}
46-
47-
private _owner: WeakRef<SharedNotificationDelegateImpl>;
48-
49-
public static initWithOwner(owner: WeakRef<SharedNotificationDelegateImpl>): UNUserNotificationCenterDelegateImpl {
50-
const delegate = <UNUserNotificationCenterDelegateImpl>UNUserNotificationCenterDelegateImpl.new();
51-
delegate._owner = owner;
52-
return delegate;
53-
}
54-
55-
public userNotificationCenterWillPresentNotificationWithCompletionHandler(center: UNUserNotificationCenter, notification: UNNotification, completionHandler: (p1: UNNotificationPresentationOptions) => void): void {
56-
let promise = Promise.resolve(false);
57-
const owner = this._owner.get();
58-
if (owner) {
59-
owner._observers.forEach(({ observer }) => {
60-
if (observer.userNotificationCenterWillPresentNotificationWithCompletionHandler) {
61-
promise = promise.then((skip: boolean) => {
62-
if (skip) { return true; }
63-
const defPromise = createStopNextPromise();
64-
const childHandler: (p1: UNNotificationPresentationOptions) => void = (p1: UNNotificationPresentationOptions) => {
65-
defPromise.stop();
66-
completionHandler(p1);
67-
};
68-
try {
69-
observer.userNotificationCenterWillPresentNotificationWithCompletionHandler(center, notification, childHandler, defPromise.next);
70-
} catch (ignore) {
71-
defPromise.next();
72-
}
73-
return defPromise.promise;
74-
});
75-
}
76-
});
77-
promise.then((handled: boolean) => {
78-
if (!handled) {
79-
completionHandler(0);
80-
}
81-
return true;
82-
});
83-
}
84-
}
85-
86-
public userNotificationCenterOpenSettingsForNotification(center: UNUserNotificationCenter, notification: UNNotification): void {
87-
let promise = Promise.resolve(false);
88-
const owner = this._owner.get();
89-
if (owner) {
90-
owner._observers.forEach(({ observer }) => {
91-
if (observer.userNotificationCenterOpenSettingsForNotification) {
92-
promise = promise.then((skip: boolean) => {
93-
if (skip) { return true; }
94-
const defPromise = createStopNextPromise();
95-
try {
96-
observer.userNotificationCenterOpenSettingsForNotification(center, notification, defPromise.stop, defPromise.next);
97-
} catch (ignore) {
98-
defPromise.next();
99-
}
100-
return defPromise.promise;
101-
});
102-
}
103-
});
104-
}
105-
}
106-
107-
public userNotificationCenterDidReceiveNotificationResponseWithCompletionHandler(center: UNUserNotificationCenter, response: UNNotificationResponse, completionHandler: () => void): void {
108-
let promise = Promise.resolve(false);
109-
const owner = this._owner.get();
110-
if (owner) {
111-
owner._observers.forEach(({ observer }) => {
112-
if (observer.userNotificationCenterDidReceiveNotificationResponseWithCompletionHandler) {
113-
promise = promise.then((skip: boolean) => {
114-
if (skip) { return true; }
115-
const defPromise = createStopNextPromise();
116-
const childHandler: () => void = () => {
117-
defPromise.stop();
118-
completionHandler();
119-
};
120-
try {
121-
observer.userNotificationCenterDidReceiveNotificationResponseWithCompletionHandler(center, response, childHandler, defPromise.next);
122-
} catch (ignore) {
123-
defPromise.next();
124-
}
125-
return defPromise.promise;
126-
});
127-
}
128-
});
129-
promise.then((handled: boolean) => {
130-
if (!handled) {
131-
if (!owner.disableUnhandledWarning) {
132-
console.log("WARNING[shared-notification-delegate]: Notification was received but was not handled by any observer");
133-
}
134-
completionHandler();
135-
}
136-
return true;
137-
});
138-
}
139-
}
38+
public static ObjCProtocols = [];
39+
40+
static new(): UNUserNotificationCenterDelegateImpl {
41+
if (UNUserNotificationCenterDelegateImpl.ObjCProtocols.length === 0 && typeof UNUserNotificationCenterDelegate !== 'undefined') {
42+
UNUserNotificationCenterDelegateImpl.ObjCProtocols.push(UNUserNotificationCenterDelegate);
43+
}
44+
return <UNUserNotificationCenterDelegateImpl>super.new();
45+
}
46+
47+
private _owner: WeakRef<SharedNotificationDelegateImpl>;
48+
49+
public static initWithOwner(owner: WeakRef<SharedNotificationDelegateImpl>): UNUserNotificationCenterDelegateImpl {
50+
const delegate = <UNUserNotificationCenterDelegateImpl>UNUserNotificationCenterDelegateImpl.new();
51+
delegate._owner = owner;
52+
return delegate;
53+
}
54+
55+
public userNotificationCenterWillPresentNotificationWithCompletionHandler(center: UNUserNotificationCenter, notification: UNNotification, completionHandler: (p1: UNNotificationPresentationOptions) => void): void {
56+
const owner = this._owner.get();
57+
if (owner) {
58+
let handled = false;
59+
const next = () => (handled = handled ? handled : false);
60+
const childHandler = (p1: UNNotificationPresentationOptions) => {
61+
if (handled) {
62+
return;
63+
57AE }
64+
handled = true;
65+
completionHandler(p1);
66+
};
67+
owner._observers.some(({ observer }) => {
68+
if (observer.userNotificationCenterWillPresentNotificationWithCompletionHandler) {
69+
try {
70+
observer.userNotificationCenterWillPresentNotificationWithCompletionHandler(center, notification, childHandler, next);
71+
} catch (ignore) {
72+
next();
73+
}
74+
}
75+
return handled;
76+
});
77+
if (!handled) {
78+
if (!owner.disableUnhandledWarning) {
79+
console.log('WARNING[shared-notification-delegate]: Notification was received for presentation but was not handled by any observer');
80+
}
81+
childHandler(0);
82+
}
83+
}
84+
}
85+
86+
public userNotificationCenterOpenSettingsForNotification(center: UNUserNotificationCenter, notification: UNNotification): void {
87+
let promise = Promise.resolve(false);
88+
const owner = this._owner.get();
89+
if (owner) {
90+
owner._observers.forEach(({ observer }) => {
91+
if (observer.userNotificationCenterOpenSettingsForNotification) {
92+
promise = promise.then((skip: boolean) => {
93+
if (skip) {
94+
return true;
95+
}
96+
const defPromise = createStopNextPromise();
97+
try {
98+
observer.userNotificationCenterOpenSettingsForNotification(center, notification, defPromise.stop, defPromise.next);
99+
} catch (ignore) {
100+
defPromise.next();
101+
}
102+
return defPromise.promise;
103+
});
104+
}
105+
});
106+
}
107+
}
108+
109+
public userNotificationCenterDidReceiveNotificationResponseWithCompletionHandler(center: UNUserNotificationCenter, response: UNNotificationResponse, completionHandler: () => void): void {
110+
let promise = Promise.resolve(false);
111+
const owner = this._owner.get();
112+
if (owner) {
113+
owner._observers.forEach(({ observer }) => {
114+
if (observer.userNotificationCenterDidReceiveNotificationResponseWithCompletionHandler) {
115+
promise = promise.then((skip: boolean) => {
116+
if (skip) {
117+
return true;
118+
}
119+
const defPromise = createStopNextPromise();
120+
const childHandler: () => void = () => {
121+
defPromise.stop();
122+
completionHandler();
123+
};
124+
try {
125+
observer.userNotificationCenterDidReceiveNotificationResponseWithCompletionHandler(center, response, childHandler, defPromise.next);
126+
} catch (ignore) {
127+
defPromise.next();
128+
}
129+
return defPromise.promise;
130+
});
131+
}
132+
});
133+
promise.then((handled: boolean) => {
134+
if (!handled) {
135+
if (!owner.disableUnhandledWarning) {
136+
console.log('WARNING[shared-notification-delegate]: Notification was received but was not handled by any observer');
137+
}
138+
completionHandler();
139+
}
140+
return true;
141+
});
142+
}
143+
}
140144
}
141145

142146
export interface DelegateObserver {
143-
userNotificationCenterDidReceiveNotificationResponseWithCompletionHandler?(center: UNUserNotificationCenter, response: UNNotificationResponse, completionHandler: () => void, next: () => void): void;
144-
userNotificationCenterOpenSettingsForNotification?(center: UNUserNotificationCenter, notification: UNNotification, stop: () => void, next: () => void): void;
145-
userNotificationCenterWillPresentNotificationWithCompletionHandler?(center: UNUserNotificationCenter, notification: UNNotification, completionHandler: (p1: UNNotificationPresentationOptions) => void, next: () => void): void;
146-
/**
147-
* if set to not null/undefined, will ensure only one is registered
148-
*/
149-
observerUniqueKey?: any;
147+
userNotificationCenterDidReceiveNotificationResponseWithCompletionHandler?(center: UNUserNotificationCenter, response: UNNotificationResponse, completionHandler: () => void, next: () => void): void;
148+
userNotificationCenterOpenSettingsForNotification?(center: UNUserNotificationCenter, notification: UNNotification, stop: () => void, next: () => void): void;
149+
userNotificationCenterWillPresentNotificationWithCompletionHandler?(center: UNUserNotificationCenter, notification: UNNotification, completionHandler: (p1: UNNotificationPresentationOptions) => void, next: () => void): void;
150+
/**
151+
* if set to not null/undefined, will ensure only one is registered
152+
*/
153+
observerUniqueKey?: any;
150154
}
151155
export class SharedNotificationDelegateImpl extends SharedNotificationDelegateCommon {
152-
_observers: Array<{ observer: DelegateObserver, priority: number }> = [];
153-
disableUnhandledWarning = false;
154-
private delegate: UNUserNotificationCenterDelegateImpl;
155-
156-
constructor() {
157-
super();
158-
if (SharedNotificationDelegateImpl.isUNUserNotificationCenterAvailable()) {
159-
this.delegate = UNUserNotificationCenterDelegateImpl.initWithOwner(new WeakRef(this));
160-
UNUserNotificationCenter.currentNotificationCenter().delegate = this.delegate;
161-
}
162-
}
163-
164-
static isUNUserNotificationCenterAvailable(): boolean {
165-
try {
166-
// available since iOS 10
167-
return !!UNUserNotificationCenter;
168-
} catch (ignore) {
169-
return false;
170-
}
171-
}
172-
173-
addObserver(observer: DelegateObserver, priority: number = 100) {
174-
if (observer.observerUniqueKey != null) {
175-
this.removeObserverByUniqueKey(observer.observerUniqueKey);
176-
}
177-
this._observers.push({ observer, priority });
178-
this.sortObservers();
179-
}
180-
181-
removeObserver(observer: DelegateObserver) {
182-
this._observers = this._observers.filter((v) => v.observer !== observer);
183-
}
184-
185-
removeObserverByUniqueKey(key: string) {
186-
if (key == null) {
187-
console.log("SharedNotificationDelegate Warning: tried to remove null/undefined keys.");
188-
return;
189-
}
190-
this._observers = this._observers.filter((v) => v.observer.observerUniqueKey !== key);
191-
}
192-
193-
clearObservers() {
194-
this._observers = [];
195-
}
196-
197-
private sortObservers() {
198-
this._observers.sort((a, b) => a.priority > b.priority ? 1 : (a.priority < b.priority ? -1 : 0));
199-
}
156+
_observers: Array<{ observer: DelegateObserver; priority: number }> = [];
157+
disableUnhandledWarning = false;
158+
private delegate: UNUserNotificationCenterDelegateImpl;
159+
160+
constructor() {
161+
super();
162+
if (SharedNotificationDelegateImpl.isUNUserNotificationCenterAvailable()) {
163+
this.delegate = UNUserNotificationCenterDelegateImpl.initWithOwner(new WeakRef(this));
164+
UNUserNotificationCenter.currentNotificationCenter().delegate = this.delegate;
165+
}
166+
}
167+
168+
static isUNUserNotificationCenterAvailable(): boolean {
169+
try {
170+
// available since iOS 10
171+
return !!UNUserNotificationCenter;
172+
} catch (ignore 10A1B ) {
173+
return false;
174+
}
175+
}
176+
177+
addObserver(observer: DelegateObserver, priority: number = 100) {
178+
if (observer.observerUniqueKey != null) {
179+
this.removeObserverByUniqueKey(observer.observerUniqueKey);
180+
}
181+
this._observers.push({ observer, priority });
182+
this.sortObservers();
183+
}
184+
185+
removeObserver(observer: DelegateObserver) {
186+
this._observers = this._observers.filter((v) => v.observer !== observer);
187+
}
188+
189+
removeObserverByUniqueKey(key: string) {
190+
if (key == null) {
191+
console.log('SharedNotificationDelegate Warning: tried to remove null/undefined keys.');
192+
return;
193+
}
194+
this._observers = this._observers.filter((v) => v.observer.observerUniqueKey !== key);
195+
}
196+
197+
clearObservers() {
198+
this._observers = [];
199+
}
200+
201+
private sortObservers() {
202+
this._observers.sort((a, b) => (a.priority > b.priority ? 1 : a.priority < b.priority ? -1 : 0));
203+
}
200204
}
201205

202206
const instance = new SharedNotificationDelegateImpl();

0 commit comments

Comments
 (0)
0