From 553ae8002d027cc0472f3036d6ca76fa6b57f5f2 Mon Sep 17 00:00:00 2001 From: Anna Garcia Date: Tue, 1 Sep 2026 17:33:30 -0400 Subject: [PATCH 1/3] fix(push): capture $push_notification_opened on iOS cold start MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Plugin registration runs inside didFinishLaunchingWithOptions, early enough to prewarm the native push-open swizzles before the tap response is delivered — Dart-side setup() lands about 90ms too late. Also wires UNUserNotificationCenter.current().delegate into the example app; without a delegate iOS reports the tap to nobody and no open is capturable at all. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_012txiHBCZRkShMdE7V25Jrd --- .changeset/fix-ios-cold-start-push-open.md | 5 +++++ .changeset/push-open-plist-opt-out-scope.md | 5 +++++ example/ios/Runner/AppDelegate.swift | 11 +++++++++++ .../posthog_flutter/PosthogFlutterPlugin.swift | 16 ++++++++++++++++ 4 files changed, 37 insertions(+) create mode 100644 .changeset/fix-ios-cold-start-push-open.md create mode 100644 .changeset/push-open-plist-opt-out-scope.md diff --git a/.changeset/fix-ios-cold-start-push-open.md b/.changeset/fix-ios-cold-start-push-open.md new file mode 100644 index 00000000..8625449e --- /dev/null +++ b/.changeset/fix-ios-cold-start-push-open.md @@ -0,0 +1,5 @@ +--- +'posthog_flutter': patch +--- + +Fix `$push_notification_opened` not being captured on iOS when the app is cold-launched from a notification tap. diff --git a/.changeset/push-open-plist-opt-out-scope.md b/.changeset/push-open-plist-opt-out-scope.md new file mode 100644 index 00000000..6561f5ca --- /dev/null +++ b/.changeset/push-open-plist-opt-out-scope.md @@ -0,0 +1,5 @@ +--- +'posthog_flutter': patch +--- + +Change `com.posthog.posthog.CAPTURE_PUSH_NOTIFICATION_OPENED` to opt out of iOS push-open capture in every app, not only those using `com.posthog.posthog.AUTO_INIT`. diff --git a/example/ios/Runner/AppDelegate.swift b/example/ios/Runner/AppDelegate.swift index 2c255682..ef87eb12 100644 --- a/example/ios/Runner/AppDelegate.swift +++ b/example/ios/Runner/AppDelegate.swift @@ -1,9 +1,20 @@ import UIKit import Flutter +import UserNotifications @main @objc class AppDelegate: FlutterAppDelegate, FlutterImplicitEngineDelegate { + // Notification taps only reach the app through a UNUserNotificationCenter delegate; without this + // the SDK has nothing to observe and never captures $push_notification_opened. + override func application( + _ application: UIApplication, + didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? + ) -> Bool { + UNUserNotificationCenter.current().delegate = self + return super.application(application, didFinishLaunchingWithOptions: launchOptions) + } + private var ownWindow: UIWindow? func didInitializeImplicitFlutterEngine(_ engineBridge: FlutterImplicitEngineBridge) { diff --git a/posthog_flutter/darwin/posthog_flutter/Sources/posthog_flutter/PosthogFlutterPlugin.swift b/posthog_flutter/darwin/posthog_flutter/Sources/posthog_flutter/PosthogFlutterPlugin.swift index 99e20676..07ec4071 100644 --- a/posthog_flutter/darwin/posthog_flutter/Sources/posthog_flutter/PosthogFlutterPlugin.swift +++ b/posthog_flutter/darwin/posthog_flutter/Sources/posthog_flutter/PosthogFlutterPlugin.swift @@ -83,6 +83,7 @@ public class PosthogFlutterPlugin: NSObject, FlutterPlugin { let instance = PosthogFlutterPlugin() instance.channel = methodChannel PosthogFlutterPlugin.instance = instance + prewarmPushNotificationOpenCapture() initPlugin() registrar.addMethodCallDelegate(instance, channel: methodChannel) } @@ -94,6 +95,21 @@ public class PosthogFlutterPlugin: NSObject, FlutterPlugin { private let dispatchQueue = DispatchQueue(label: "com.posthog.PosthogFlutterPlugin", target: .global(qos: .utility)) + /// A cold launch from a notification tap delivers the response about 150ms in, before Dart can + /// reach `Posthog().setup()`. Registration runs inside `didFinishLaunchingWithOptions`, early + /// enough for the native SDK to hold that response until setup() installs the integration. + /// + /// The Info.plist key is the only opt-out reachable this early. `setup()` releases an unwanted + /// prewarm afterwards, except when PostHog is already set up with push-open capture disabled and + /// a later `FlutterEngine` registers — that setup() has already run, so use the plist key there. + private static func prewarmPushNotificationOpenCapture() { + let capturePushNotificationOpened = Bundle.main.object(forInfoDictionaryKey: "com.posthog.posthog.CAPTURE_PUSH_NOTIFICATION_OPENED") as? Bool ?? true + guard capturePushNotificationOpened else { return } + if #available(iOS 14.0, macOS 11.0, *) { + PostHogSDK.prewarmPushNotificationOpenCapture() + } + } + public static func initPlugin() { let autoInit = Bundle.main.object(forInfoDictionaryKey: "com.posthog.posthog.AUTO_INIT") as? Bool ?? true if !autoInit { From d70df2c9209f4fed58f7c06f56a9ea71360f147f Mon Sep 17 00:00:00 2001 From: Anna Garcia Date: Tue, 1 Sep 2026 20:38:34 -0400 Subject: [PATCH 2/3] fix(push): require posthog-ios 3.72.0 and document the delegate prerequisite The podspec and Package.swift still allowed 3.70.0/3.71.0, neither of which has prewarmPushNotificationOpenCapture(), so a consumer with a locked Podfile.lock would have hit a compile error rather than the fix. Also names the UNUserNotificationCenter delegate requirement, which is the other half of the reported bug and was previously only fixed in the example. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_012txiHBCZRkShMdE7V25Jrd --- .changeset/fix-ios-cold-start-push-open.md | 2 +- .changeset/push-open-plist-opt-out-scope.md | 2 +- posthog_flutter/darwin/posthog_flutter.podspec | 2 +- posthog_flutter/darwin/posthog_flutter/Package.swift | 2 +- posthog_flutter/lib/src/posthog_config.dart | 3 +++ 5 files changed, 7 insertions(+), 4 deletions(-) diff --git a/.changeset/fix-ios-cold-start-push-open.md b/.changeset/fix-ios-cold-start-push-open.md index 8625449e..e4c0aea3 100644 --- a/.changeset/fix-ios-cold-start-push-open.md +++ b/.changeset/fix-ios-cold-start-push-open.md @@ -2,4 +2,4 @@ 'posthog_flutter': patch --- -Fix `$push_notification_opened` not being captured on iOS when the app is cold-launched from a notification tap. +Fix `$push_notification_opened` not being captured on iOS when the app is cold-launched from a notification tap. Requires posthog-ios 3.72.0, and your app must set `UNUserNotificationCenter.current().delegate` — without one iOS reports the tap to nobody. diff --git a/.changeset/push-open-plist-opt-out-scope.md b/.changeset/push-open-plist-opt-out-scope.md index 6561f5ca..b2ca43ca 100644 --- a/.changeset/push-open-plist-opt-out-scope.md +++ b/.changeset/push-open-plist-opt-out-scope.md @@ -2,4 +2,4 @@ 'posthog_flutter': patch --- -Change `com.posthog.posthog.CAPTURE_PUSH_NOTIFICATION_OPENED` to opt out of iOS push-open capture in every app, not only those using `com.posthog.posthog.AUTO_INIT`. +Change `com.posthog.posthog.CAPTURE_PUSH_NOTIFICATION_OPENED` to also suppress the new iOS cold-start prewarm in apps that do not use `com.posthog.posthog.AUTO_INIT`. diff --git a/posthog_flutter/darwin/posthog_flutter.podspec b/posthog_flutter/darwin/posthog_flutter.podspec index 19fc5ef4..13bdf70e 100644 --- a/posthog_flutter/darwin/posthog_flutter.podspec +++ b/posthog_flutter/darwin/posthog_flutter.podspec @@ -22,7 +22,7 @@ Postog flutter plugin s.osx.dependency 'FlutterMacOS' # ~> Version 3.70.0 up to, but not including, 4.0.0 - s.dependency 'PostHog', '>= 3.70.0', '< 4.0.0' + s.dependency 'PostHog', '>= 3.72.0', '< 4.0.0' s.ios.deployment_target = '13.0' # PH iOS SDK 3.0.0 requires >= 10.15 diff --git a/posthog_flutter/darwin/posthog_flutter/Package.swift b/posthog_flutter/darwin/posthog_flutter/Package.swift index e4a24d60..fb7ba28b 100644 --- a/posthog_flutter/darwin/posthog_flutter/Package.swift +++ b/posthog_flutter/darwin/posthog_flutter/Package.swift @@ -14,7 +14,7 @@ let package = Package( ], dependencies: [ .package(name: "FlutterFramework", path: "../FlutterFramework"), - .package(url: "https://github.com/PostHog/posthog-ios", "3.70.0" ..< "4.0.0"), + .package(url: "https://github.com/PostHog/posthog-ios", "3.72.0" ..< "4.0.0"), ], targets: [ .target( diff --git a/posthog_flutter/lib/src/posthog_config.dart b/posthog_flutter/lib/src/posthog_config.dart index 195de8d4..0da2c666 100644 --- a/posthog_flutter/lib/src/posthog_config.dart +++ b/posthog_flutter/lib/src/posthog_config.dart @@ -251,6 +251,9 @@ class PostHogConfig { /// warm-start taps on Android. /// /// **Flutter web:** not supported. Defaults to `true`. + /// + /// On iOS this requires your app to set `UNUserNotificationCenter.current().delegate`. + /// Without one, iOS reports the tap to nobody and no open can be captured. bool capturePushNotificationOpened = true; /// Mints a signed identity-verification token for push subscription requests. From 88487dff723f581d865fabffc0890a0cfe5b0d7a Mon Sep 17 00:00:00 2001 From: Anna Garcia Date: Wed, 2 Sep 2026 11:46:23 -0400 Subject: [PATCH 3/3] docs(push): correct the podspec version comment It still named 3.70.0 directly above the raised 3.72.0 requirement. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_012txiHBCZRkShMdE7V25Jrd --- posthog_flutter/darwin/posthog_flutter.podspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/posthog_flutter/darwin/posthog_flutter.podspec b/posthog_flutter/darwin/posthog_flutter.podspec index 13bdf70e..2b98355a 100644 --- a/posthog_flutter/darwin/posthog_flutter.podspec +++ b/posthog_flutter/darwin/posthog_flutter.podspec @@ -21,7 +21,7 @@ Postog flutter plugin s.ios.dependency 'Flutter' s.osx.dependency 'FlutterMacOS' - # ~> Version 3.70.0 up to, but not including, 4.0.0 + # ~> Version 3.72.0 up to, but not including, 4.0.0 s.dependency 'PostHog', '>= 3.72.0', '< 4.0.0' s.ios.deployment_target = '13.0'