Fix stale push notification replay after account switch
The native lastResponse cache is only cleared when handlePushNotificationEntry consumes it on cold start. Foreground/background taps handled by the response listener never cleared it, so a later getLastNotificationResponse call (fired by onNavigationReady when the tree remounts on account switch) would replay the stale payload and ping-pong the user back to the previous account. Clear lastResponse from the response listener, and guard handlePushNotificationEntry behind a once-per-runtime flag so remounts don't re-consume a launching notification.
This commit is contained in:
@@ -844,6 +844,8 @@ const LINKING = {
|
|||||||
},
|
},
|
||||||
} satisfies LinkingOptions<AllNavigatorParams>
|
} satisfies LinkingOptions<AllNavigatorParams>
|
||||||
|
|
||||||
|
let didHandlePushNotificationEntry = false
|
||||||
|
|
||||||
function RoutesContainer({children}: React.PropsWithChildren<{}>) {
|
function RoutesContainer({children}: React.PropsWithChildren<{}>) {
|
||||||
const ax = useAnalytics()
|
const ax = useAnalytics()
|
||||||
// eslint-disable-next-line react-compiler/react-compiler
|
// eslint-disable-next-line react-compiler/react-compiler
|
||||||
@@ -904,6 +906,14 @@ function RoutesContainer({children}: React.PropsWithChildren<{}>) {
|
|||||||
function handlePushNotificationEntry() {
|
function handlePushNotificationEntry() {
|
||||||
if (!IS_NATIVE) return
|
if (!IS_NATIVE) return
|
||||||
|
|
||||||
|
// Only consume a launching notification once per JS runtime. Account
|
||||||
|
// switches remount the entire tree (see `key={currentAccount?.did}` in
|
||||||
|
// `App.native.tsx`), which re-fires `onNavigationReady` and would
|
||||||
|
// otherwise re-process whatever `getLastNotificationResponse` still has
|
||||||
|
// cached natively (APP-2338).
|
||||||
|
if (didHandlePushNotificationEntry) return
|
||||||
|
didHandlePushNotificationEntry = true
|
||||||
|
|
||||||
// intent urls are handled by `useIntentHandler`
|
// intent urls are handled by `useIntentHandler`
|
||||||
if (linkingUrl) return
|
if (linkingUrl) return
|
||||||
|
|
||||||
|
|||||||
@@ -380,6 +380,18 @@ export function useNotificationsHandler() {
|
|||||||
|
|
||||||
handleNotification(payload)
|
handleNotification(payload)
|
||||||
Notifications.dismissAllNotificationsAsync()
|
Notifications.dismissAllNotificationsAsync()
|
||||||
|
// Also clear the native `lastResponse` cache. Otherwise a subsequent
|
||||||
|
// `getLastNotificationResponse()` (e.g. on an account-switch remount,
|
||||||
|
// which re-runs `handlePushNotificationEntry`) would replay this
|
||||||
|
// payload and ping-pong the user back to the previous account/chat.
|
||||||
|
try {
|
||||||
|
Notifications.clearLastNotificationResponse()
|
||||||
|
} catch (error) {
|
||||||
|
notyLogger.error(
|
||||||
|
`useNotificationsHandler: error clearing notification response`,
|
||||||
|
{error},
|
||||||
|
)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
logger.error('useNotificationsHandler: received no payload', {
|
logger.error('useNotificationsHandler: received no payload', {
|
||||||
identifier: e.notification.request.identifier,
|
identifier: e.notification.request.identifier,
|
||||||
|
|||||||
Reference in New Issue
Block a user