-
Notifications
You must be signed in to change notification settings - Fork 381
fix: [SDK-5139] display foreground notifications by default #1989
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
79c5bee
17fbde3
8691d6c
fbb3b0b
5d6ba24
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -24,7 +24,10 @@ import type { | |
| import type { NotificationClickEvent } from '../types/notificationEvents'; | ||
| import type { PushSubscriptionChangedState } from '../types/subscription'; | ||
| import type { UserChangedState } from '../types/user'; | ||
| import NotificationWillDisplayEvent from './NotificationWillDisplayEvent'; | ||
| import NotificationWillDisplayEvent, { | ||
| isDefaultPrevented, | ||
| isDisplayRequested, | ||
| } from './NotificationWillDisplayEvent'; | ||
|
|
||
| export interface EventListenerMap { | ||
| [PERMISSION_CHANGED]: (event: boolean) => void; | ||
|
|
@@ -72,10 +75,14 @@ export default class EventManager { | |
| this.dispatchHandlers(USER_STATE_CHANGED, payload); | ||
| }), | ||
| this.RNOneSignal.onNotificationWillDisplay((payload) => { | ||
| this.dispatchHandlers( | ||
| NOTIFICATION_WILL_DISPLAY, | ||
| new NotificationWillDisplayEvent(payload as OSNotification), | ||
| ); | ||
| const event = new NotificationWillDisplayEvent(payload as OSNotification); | ||
| try { | ||
| this.dispatchNotificationWillDisplayHandlers(event); | ||
| } finally { | ||
| if (!isDefaultPrevented(event) && !isDisplayRequested(event)) { | ||
| event.getNotification().display(); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should-fix: this path bypasses the injected native module.
The test file shows the effect: Both handles resolve to the same module in production, so there is no runtime bug. But the injection is now misleading. Two options:
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Both handles are the same singleton in production because EventManager is constructed with RNOneSignal. OSNotification.display() and NotificationWillDisplayEvent.preventDefault() already use that singleton, while the injected handle is used for event subscriptions. Calling the injected module only for automatic display would split display behavior and bypass the notification wrapper’s idempotency tracking, and passing Spec into the exported event would change its public constructor. I’m keeping the existing notification action pattern. |
||
| } | ||
| } | ||
| }), | ||
| this.RNOneSignal.onNotificationClicked((payload) => { | ||
| this.dispatchHandlers(NOTIFICATION_CLICKED, payload); | ||
|
|
@@ -124,6 +131,28 @@ export default class EventManager { | |
| } | ||
| } | ||
|
|
||
| private dispatchNotificationWillDisplayHandlers(event: NotificationWillDisplayEvent) { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should-fix: this method duplicates It is
Suggest one of two things: fold the behavior into
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Added a comment explaining that every foreground handler must run because any one can prevent automatic display. I kept this path separate to avoid changing error behavior for unrelated events. |
||
| // Every handler must run because any one of them can prevent automatic display. | ||
| const handlers = [...(this.eventListenerArrayMap.get(NOTIFICATION_WILL_DISPLAY) ?? [])]; | ||
| let firstError: unknown; | ||
| let handlerThrew = false; | ||
|
|
||
| handlers.forEach((handler) => { | ||
| try { | ||
| handler(event); | ||
| } catch (error) { | ||
| if (!handlerThrew) { | ||
| firstError = error; | ||
| handlerThrew = true; | ||
| } | ||
| } | ||
| }); | ||
|
|
||
| if (handlerThrew) { | ||
| throw firstError; | ||
| } | ||
| } | ||
|
|
||
| private dispatchHandlers(eventName: string, payload: unknown) { | ||
| const handlerArray = this.eventListenerArrayMap.get(eventName); | ||
| if (handlerArray) { | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should-fix: a throw from this
finallyblock discards the handler error.If
display()fails (for example, the native module is not loaded), the new exception replaces the pending exception fromdispatchNotificationWillDisplayHandlers, and the original handler error is lost.A local try/catch keeps the handler error as the visible one:
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is technically possible, but it requires both a handler and the native display bridge to throw. A missing module fails earlier at getEnforcing(), and both native display implementations log and return on cache misses rather than throwing. The suggested catch would also swallow a real display failure when no handler error exists, so I’m keeping the current propagation behavior.