Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/fix-ios-cold-start-push-open.md
Original file line number Diff line number Diff line change
@@ -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. Requires posthog-ios 3.72.0, and your app must set `UNUserNotificationCenter.current().delegate` β€” without one iOS reports the tap to nobody.
5 changes: 5 additions & 0 deletions .changeset/push-open-plist-opt-out-scope.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'posthog_flutter': patch
---

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`.
11 changes: 11 additions & 0 deletions example/ios/Runner/AppDelegate.swift
Original file line number Diff line number Diff line change
@@ -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) {
Expand Down
4 changes: 2 additions & 2 deletions posthog_flutter/darwin/posthog_flutter.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ Postog flutter plugin
s.ios.dependency 'Flutter'
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'
# ~> 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'
# PH iOS SDK 3.0.0 requires >= 10.15
Expand Down
2 changes: 1 addition & 1 deletion posthog_flutter/darwin/posthog_flutter/Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ public class PosthogFlutterPlugin: NSObject, FlutterPlugin {
let instance = PosthogFlutterPlugin()
instance.channel = methodChannel
PosthogFlutterPlugin.instance = instance
prewarmPushNotificationOpenCapture()

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Prewarm path lacks coverage

The new registration-time prewarm and its plist opt-out have no automated regression coverage. Please add a native test seam that verifies registration invokes prewarm when the key is enabled or absent and suppresses it when false; otherwise, removing the early call or reversing the guard could silently reintroduce the cold-start failure.

Prompt To Fix With AI
This is a comment left during a code review.
Path: posthog_flutter/darwin/posthog_flutter/Sources/posthog_flutter/PosthogFlutterPlugin.swift
Line: 86

Comment:
**Prewarm path lacks coverage**

The new registration-time prewarm and its plist opt-out have no automated regression coverage. Please add a native test seam that verifies registration invokes prewarm when the key is enabled or absent and suppresses it when false; otherwise, removing the early call or reversing the guard could silently reintroduce the cold-start failure.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

initPlugin()
registrar.addMethodCallDelegate(instance, channel: methodChannel)
}
Expand All @@ -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

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nit] Small one: this is a copy of the plist read in initPlugin() at line 141. Worth one private static var both paths read, so the key and the ?? true default can't drift apart?

guard capturePushNotificationOpened else { return }
if #available(iOS 14.0, macOS 11.0, *) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Prewarm skips supported iOS 13

The package still supports iOS 13, but this availability check skips the prewarm there. When a notification tap cold-launches an iOS 13 app, the response can still arrive before Dart setup without being buffered, so the advertised cold-start fix remains ineffective on a supported deployment target.

Prompt To Fix With AI
This is a comment left during a code review.
Path: posthog_flutter/darwin/posthog_flutter/Sources/posthog_flutter/PosthogFlutterPlugin.swift
Line: 108

Comment:
**Prewarm skips supported iOS 13**

The package still supports iOS 13, but this availability check skips the prewarm there. When a notification tap cold-launches an iOS 13 app, the response can still arrive before Dart setup without being buffered, so the advertised cold-start fix remains ineffective on a supported deployment target.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

PostHogSDK.prewarmPushNotificationOpenCapture()
}
}

public static func initPlugin() {
let autoInit = Bundle.main.object(forInfoDictionaryKey: "com.posthog.posthog.AUTO_INIT") as? Bool ?? true
if !autoInit {
Expand Down
7 changes: 7 additions & 0 deletions posthog_flutter/lib/src/posthog_config.dart
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,13 @@ 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.
///
/// Setting this to `false` does not prevent the iOS cold-start prewarm, which runs before
/// Dart does β€” opt that out with the `com.posthog.posthog.CAPTURE_PUSH_NOTIFICATION_OPENED`
/// key in `Info.plist`.
bool capturePushNotificationOpened = true;

/// Mints a signed identity-verification token for push subscription requests.
Expand Down
Loading