feat(push): hold a notification tap that arrives before setup() - #792
Draft
turnipdabeets wants to merge 3 commits into
Draft
feat(push): hold a notification tap that arrives before setup()#792turnipdabeets wants to merge 3 commits into
turnipdabeets wants to merge 3 commits into
Conversation
A cold launch from a notification tap delivers the response ~150ms in, before a Flutter or React Native host can reach setup() from its own runtime, so the swizzles were not yet installed and the open was lost. Adds prewarmPushNotificationOpenCapture() to install the notification delegate swizzles early and hold one response until the integration subscribes, and warns when no UNUserNotificationCenter delegate exists at all — the case where taps reach nobody and nothing is capturable. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012txiHBCZRkShMdE7V25Jrd
5 tasks
Contributor
posthog-ios Compliance ReportDate: 2026-09-02 16:17:34 UTC ✅ All Tests Passed!45/45 tests passed Capture Tests✅ 29/29 tests passed View Details
Feature_Flags Tests✅ 16/16 tests passed View Details
|
hedgeLogEnabled defaults to false, so the warning only prints when config.debug is on — a release build sees nothing. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012txiHBCZRkShMdE7V25Jrd
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012txiHBCZRkShMdE7V25Jrd
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
💡 Motivation and Context
Fixes the native half of PostHog/posthog-flutter#555 —
$push_notification_openedis never captured in a stock Flutter app on iOS. Two independent causes, both reproduced on a simulator:UNUserNotificationCenterdelegate, so iOS reports the tap to nobody and our swizzling has nothing to attach to. The integration logsinstalledand then stays silent forever, which is near-impossible to diagnose from outside.didReceivearrives ~150 ms in — about 90 ms before a Dart/JS host can reachsetup(). The swizzles aren't in place yet.Native iOS apps that call
setup()fromdidFinishLaunchingWithOptionsare unaffected by (2) and need none of this.💚 How did you test it?
make test— 774 tests pass.make testOniOSSimulator—** TEST SUCCEEDED **, 190 cases, 0 failures.setup()discard gate. The opted-out one is a real regression test — reverting the fix makes it fail.Testing
Beyond the unit suites, verified on an iPhone 17 Pro simulator (iOS 26.4) through two hosts, with events confirmed in a real PostHog project:
posthog-ios's own
PostHogExample(setup()indidFinishLaunchingWithOptions, delegate wired) — the configuration this change does not need to alter:A Flutter host, where
setup()runs from Dart ~90ms after the tap is delivered: cold start went from 0 captures to 1, repeatedly, across four rounds.Also checked: with the app's
UNUserNotificationCenterdelegate removed, nothing is captured in any app state and the new warning fires; with it present, no warning.capturePushNotificationOpened: falseinstalls no integration and captures nothing.📝 Checklist
If releasing new changes
pnpm changesetto generate a changeset file🤖 Agent context
Autonomy: Human-driven (agent-assisted)
Built with Claude Code (session), driven by @turnipdabeets. Investigation started from posthog-flutter#555 and reproduced both causes on a simulator before any code was written.
Three review/triage rounds ran over the branch, and each caught something material:
setup()→close()a tap was retained in the process-wide publisher and replayed into the nextsetup()within 30s — a silent behaviour change for all posthog-ios users, with a consent dimension. Now the buffer only lives inside the prewarm window.installIntegrations(), whichsetup()only calls when not opted out — so it never ran for anyone with a persisted opt-out. Moved intosetup()with the gate widened.test-ios-simulatorlane (a new test called the iOS-14-only API unguarded).swift teston macOS hides this because Swift raises the arm64 floor to 11.0.Two alternatives were considered and rejected: a
hasEverHadSubscriberlatch to close the window permanently (it would silently kill cold-start capture forever for a Flutter add-to-app host that prewarms afterclose()), and replayinglaunchOptions[.remoteNotification](verified on iOS 26 — that key is not populated for a user tap).Not done here, deliberately: docs. The
posthog_flutterside is PostHog/posthog-flutter#556 and needs a release of this one first.🤖 Generated with Claude Code
https://claude.ai/code/session_012txiHBCZRkShMdE7V25Jrd