From 00b69ea07a6a69329235392daae10f3d33323599 Mon Sep 17 00:00:00 2001 From: Anna Garcia Date: Fri, 2 Oct 2026 19:02:45 -0400 Subject: [PATCH 1/7] chore!: remove deprecated APIs for v6 - Remove PostHogConfig.apiKey and the API_KEY manifest/Info.plist fallback. - Remove getFeatureFlagPayload() across Dart, web and native handlers. - Remove the debouncerDelay setter and PostHogDataMode.cellular. Co-Authored-By: Claude Opus 5.5 (1M context) --- .changeset/v6-remove-deprecated-apis.md | 8 ++ api/posthog_flutter.api.json | 99 ------------------- .../posthog/flutter/PosthogFlutterPlugin.kt | 47 +-------- .../PosthogFlutterPlugin.swift | 36 +------ posthog_flutter/lib/posthog_flutter_web.dart | 7 -- posthog_flutter/lib/src/posthog.dart | 10 -- posthog_flutter/lib/src/posthog_config.dart | 31 ------ .../lib/src/posthog_flutter_io.dart | 16 --- .../posthog_flutter_platform_interface.dart | 6 -- .../lib/src/posthog_flutter_web_handler.dart | 6 -- .../test/posthog_flutter_io_test.dart | 4 +- ...sthog_flutter_platform_interface_fake.dart | 6 -- posthog_flutter/test/posthog_test.dart | 2 - .../test/snapshots/setup_request.json | 1 - 14 files changed, 19 insertions(+), 260 deletions(-) create mode 100644 .changeset/v6-remove-deprecated-apis.md diff --git a/.changeset/v6-remove-deprecated-apis.md b/.changeset/v6-remove-deprecated-apis.md new file mode 100644 index 00000000..d291102a --- /dev/null +++ b/.changeset/v6-remove-deprecated-apis.md @@ -0,0 +1,8 @@ +--- +"posthog_flutter": major +--- + +- **Breaking:** remove `PostHogConfig.apiKey` and the `com.posthog.posthog.API_KEY` manifest/Info.plist key — use `projectToken` and `com.posthog.posthog.PROJECT_TOKEN` +- **Breaking:** remove `Posthog().getFeatureFlagPayload()` — use `getFeatureFlagResult(key, sendEvent: false)` and read `payload` +- **Breaking:** remove the `PostHogSessionReplayConfig.debouncerDelay` setter — use `PostHogSessionReplayConfig.throttleDelay` +- **Breaking:** remove `PostHogDataMode.cellular` — use `PostHogDataMode.any`, which it always behaved like diff --git a/api/posthog_flutter.api.json b/api/posthog_flutter.api.json index 33cae6ee..b07cfe8f 100644 --- a/api/posthog_flutter.api.json +++ b/api/posthog_flutter.api.json @@ -876,28 +876,6 @@ "type": "method", "typeParameterNames": [] }, - { - "entryPoints": [], - "isDeprecated": false, - "isExperimental": false, - "isStatic": false, - "name": "getFeatureFlagPayload", - "parameters": [ - { - "isDeprecated": false, - "isExperimental": false, - "isNamed": true, - "isRequired": true, - "name": "key", - "relativePath": "lib/src/posthog_flutter_platform_interface.dart", - "typeName": "String" - } - ], - "relativePath": "lib/src/posthog_flutter_platform_interface.dart", - "returnTypeName": "Future", - "type": "method", - "typeParameterNames": [] - }, { "entryPoints": [], "isDeprecated": false, @@ -1859,28 +1837,6 @@ "type": "method", "typeParameterNames": [] }, - { - "entryPoints": [], - "isDeprecated": false, - "isExperimental": false, - "isStatic": false, - "name": "getFeatureFlagPayload", - "parameters": [ - { - "isDeprecated": false, - "isExperimental": false, - "isNamed": true, - "isRequired": true, - "name": "key", - "relativePath": "lib/src/posthog_flutter_platform_interface.dart", - "typeName": "String" - } - ], - "relativePath": "lib/src/posthog_flutter_platform_interface.dart", - "returnTypeName": "Future", - "type": "method", - "typeParameterNames": [] - }, { "entryPoints": [], "isDeprecated": false, @@ -2173,17 +2129,6 @@ "relativePath": "lib/src/posthog_config.dart", "typeName": "String" }, - { - "entryPoints": [], - "isDeprecated": true, - "isExperimental": false, - "isReadable": true, - "isStatic": false, - "isWriteable": false, - "name": "apiKey", - "relativePath": "lib/src/posthog_config.dart", - "typeName": "String" - }, { "entryPoints": [], "isDeprecated": false, @@ -2770,17 +2715,6 @@ "relativePath": "lib/src/posthog_config.dart", "typeName": "PostHogTextMask Function(String, Widget)?" }, - { - "entryPoints": [], - "isDeprecated": true, - "isExperimental": false, - "isReadable": false, - "isStatic": false, - "isWriteable": true, - "name": "debouncerDelay", - "relativePath": "lib/src/posthog_config.dart", - "typeName": "Duration" - }, { "entryPoints": [], "isDeprecated": false, @@ -2950,17 +2884,6 @@ "relativePath": "lib/src/posthog_config.dart", "typeName": "PostHogDataMode" }, - { - "entryPoints": [], - "isDeprecated": true, - "isExperimental": false, - "isReadable": true, - "isStatic": true, - "isWriteable": false, - "name": "cellular", - "relativePath": "lib/src/posthog_config.dart", - "typeName": "PostHogDataMode" - }, { "entryPoints": [], "isDeprecated": false, @@ -4826,28 +4749,6 @@ "type": "method", "typeParameterNames": [] }, - { - "entryPoints": [], - "isDeprecated": true, - "isExperimental": false, - "isStatic": false, - "name": "getFeatureFlagPayload", - "parameters": [ - { - "isDeprecated": false, - "isExperimental": false, - "isNamed": false, - "isRequired": true, - "name": "key", - "relativePath": "lib/src/posthog.dart", - "typeName": "String" - } - ], - "relativePath": "lib/src/posthog.dart", - "returnTypeName": "Future", - "type": "method", - "typeParameterNames": [] - }, { "entryPoints": [], "isDeprecated": false, diff --git a/posthog_flutter/android/src/main/kotlin/com/posthog/flutter/PosthogFlutterPlugin.kt b/posthog_flutter/android/src/main/kotlin/com/posthog/flutter/PosthogFlutterPlugin.kt index 5474b8cd..378353bb 100644 --- a/posthog_flutter/android/src/main/kotlin/com/posthog/flutter/PosthogFlutterPlugin.kt +++ b/posthog_flutter/android/src/main/kotlin/com/posthog/flutter/PosthogFlutterPlugin.kt @@ -185,21 +185,10 @@ class PosthogFlutterPlugin : return } - val projectToken = - ( - bundle.getString("com.posthog.posthog.PROJECT_TOKEN") - ?: bundle.getString("com.posthog.posthog.API_KEY") - )?.trim() - - if (!bundle.containsKey("com.posthog.posthog.PROJECT_TOKEN") && bundle.containsKey("com.posthog.posthog.API_KEY")) { - Log.w( - "PostHog", - "com.posthog.posthog.API_KEY is deprecated and will be removed in the next major version. Use com.posthog.posthog.PROJECT_TOKEN instead!", - ) - } + val projectToken = bundle.getString("com.posthog.posthog.PROJECT_TOKEN")?.trim() if (projectToken.isNullOrEmpty()) { - Log.e("PostHog", "Either com.posthog.posthog.PROJECT_TOKEN or com.posthog.posthog.API_KEY must be provided!") + Log.e("PostHog", "com.posthog.posthog.PROJECT_TOKEN must be provided!") return } @@ -224,7 +213,6 @@ class PosthogFlutterPlugin : val posthogConfig = mutableMapOf() posthogConfig["projectToken"] = projectToken - posthogConfig["apiKey"] = projectToken posthogConfig["host"] = host posthogConfig["captureApplicationLifecycleEvents"] = captureApplicationLifecycleEvents posthogConfig["debug"] = debug @@ -322,10 +310,6 @@ class PosthogFlutterPlugin : getFeatureFlag(call, result) } - "getFeatureFlagPayload" -> { - getFeatureFlagPayload(call, result) - } - "getFeatureFlagResult" -> { getFeatureFlagResult(call, result) } @@ -552,19 +536,9 @@ class PosthogFlutterPlugin : } private fun setupPostHog(posthogConfig: Map) { - val projectToken = - ( - (posthogConfig["projectToken"] as String?) - ?: (posthogConfig["apiKey"] as String?) - )?.trim() - if (!posthogConfig.containsKey("projectToken") && posthogConfig.containsKey("apiKey")) { - Log.w( - "PostHog", - "apiKey is deprecated and will be removed in the next major version. Use projectToken instead!", - ) - } + val projectToken = (posthogConfig["projectToken"] as String?)?.trim() if (projectToken.isNullOrEmpty()) { - Log.e("PostHog", "Either projectToken or apiKey must be provided!") + Log.e("PostHog", "projectToken must be provided!") return } @@ -1670,19 +1644,6 @@ class PosthogFlutterPlugin : } } - private fun getFeatureFlagPayload( - call: MethodCall, - result: Result, - ) { - try { - val featureFlagKey: String = call.argument("key")!! - val flag = PostHog.getFeatureFlagResult(featureFlagKey, sendFeatureFlagEvent = false)?.payload - result.success(flag) - } catch (e: Throwable) { - result.error("PosthogFlutterException", e.localizedMessage, null) - } - } - private fun getFeatureFlagResult( call: MethodCall, result: Result, 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 f00c34e9..6054770d 100644 --- a/posthog_flutter/darwin/posthog_flutter/Sources/posthog_flutter/PosthogFlutterPlugin.swift +++ b/posthog_flutter/darwin/posthog_flutter/Sources/posthog_flutter/PosthogFlutterPlugin.swift @@ -120,17 +120,11 @@ public class PosthogFlutterPlugin: NSObject, FlutterPlugin { return } - let projectToken = ((Bundle.main.object(forInfoDictionaryKey: "com.posthog.posthog.PROJECT_TOKEN") as? String) ?? (Bundle.main.object(forInfoDictionaryKey: "com.posthog.posthog.API_KEY") as? String) ?? "") + let projectToken = (Bundle.main.object(forInfoDictionaryKey: "com.posthog.posthog.PROJECT_TOKEN") as? String ?? "") .trimmingCharacters(in: .whitespacesAndNewlines) - if Bundle.main.object(forInfoDictionaryKey: "com.posthog.posthog.PROJECT_TOKEN") == nil, - Bundle.main.object(forInfoDictionaryKey: "com.posthog.posthog.API_KEY") != nil - { - print("[PostHog] com.posthog.posthog.API_KEY is deprecated and will be removed in the next major version. Use com.posthog.posthog.PROJECT_TOKEN instead!") - } - if projectToken.isEmpty { - print("[PostHog] Either com.posthog.posthog.PROJECT_TOKEN or com.posthog.posthog.API_KEY must be provided!") + print("[PostHog] com.posthog.posthog.PROJECT_TOKEN must be provided!") return } @@ -144,7 +138,6 @@ public class PosthogFlutterPlugin: NSObject, FlutterPlugin { setupPostHog([ "projectToken": projectToken, - "apiKey": projectToken, "host": host, "captureApplicationLifecycleEvents": captureApplicationLifecycleEvents, "debug": debug, @@ -161,13 +154,10 @@ public class PosthogFlutterPlugin: NSObject, FlutterPlugin { print("[PostHog] Plugin instance not found!") return } - let projectToken = ((posthogConfig["projectToken"] as? String) ?? (posthogConfig["apiKey"] as? String) ?? "") + let projectToken = (posthogConfig["projectToken"] as? String ?? "") .trimmingCharacters(in: .whitespacesAndNewlines) - if posthogConfig["projectToken"] == nil, posthogConfig["apiKey"] != nil { - print("[PostHog] apiKey is deprecated and will be removed in the next major version. Use projectToken instead!") - } if projectToken.isEmpty { - print("[PostHog] Either projectToken or apiKey must be provided!") + print("[PostHog] projectToken must be provided!") return } @@ -235,7 +225,7 @@ public class PosthogFlutterPlugin: NSObject, FlutterPlugin { switch dataMode { case "wifi": config.dataMode = .wifi - case "any", "cellular": + case "any": config.dataMode = .any default: break @@ -457,8 +447,6 @@ public class PosthogFlutterPlugin: NSObject, FlutterPlugin { getFeatureFlag(call, result: result) case "isFeatureEnabled": isFeatureEnabled(call, result: result) - case "getFeatureFlagPayload": - getFeatureFlagPayload(call, result: result) case "getFeatureFlagResult": getFeatureFlagResult(call, result: result) case "identify": @@ -1352,20 +1340,6 @@ extension PosthogFlutterPlugin { } } - private func getFeatureFlagPayload( - _ call: FlutterMethodCall, - result: @escaping FlutterResult - ) { - if let args = call.arguments as? [String: Any], - let featureFlagKey = args["key"] as? String - { - let value = PostHogSDK.shared.getFeatureFlagResult(featureFlagKey, sendFeatureFlagEvent: false)?.payload - result(value) - } else { - _badArgumentError(result) - } - } - private func getFeatureFlagResult( _ call: FlutterMethodCall, result: @escaping FlutterResult diff --git a/posthog_flutter/lib/posthog_flutter_web.dart b/posthog_flutter/lib/posthog_flutter_web.dart index 698c9585..48cece36 100644 --- a/posthog_flutter/lib/posthog_flutter_web.dart +++ b/posthog_flutter/lib/posthog_flutter_web.dart @@ -420,13 +420,6 @@ class PosthogFlutterWeb extends PosthogFlutterPlatformInterface { return handleWebMethodCall(MethodCall('getFeatureFlag', {'key': key})); } - @override - Future getFeatureFlagPayload({required String key}) async { - return handleWebMethodCall( - MethodCall('getFeatureFlagPayload', {'key': key}), - ); - } - @override Future getFeatureFlagResult({ required String key, diff --git a/posthog_flutter/lib/src/posthog.dart b/posthog_flutter/lib/src/posthog.dart index 5546bd0c..65f4211a 100644 --- a/posthog_flutter/lib/src/posthog.dart +++ b/posthog_flutter/lib/src/posthog.dart @@ -779,16 +779,6 @@ class Posthog { }) => _posthog.getFeatureFlagResult(key: key, sendEvent: sendEvent); - /// Returns the payload for the feature flag [key]. - /// - /// Returns `null` when the flag does not exist, has no payload, or the payload - /// cannot be loaded. - @Deprecated( - 'Use getFeatureFlagResult instead, which returns both value and payload.', - ) - Future getFeatureFlagPayload(String key) => - _posthog.getFeatureFlagPayload(key: key); - /// Flushes queued events immediately where supported by the platform. /// /// Returns a [Future] that completes when the flush request has finished. diff --git a/posthog_flutter/lib/src/posthog_config.dart b/posthog_flutter/lib/src/posthog_config.dart index 93284849..5bd9230b 100644 --- a/posthog_flutter/lib/src/posthog_config.dart +++ b/posthog_flutter/lib/src/posthog_config.dart @@ -72,17 +72,6 @@ enum PostHogDataMode { /// Send data only on Wi-Fi connections. wifi, - /// Send data on any available connection, same as [any]. - /// - /// Despite its name, this never restricted sending to cellular connections. - /// It will be removed in the next major version. - /// - /// ```dart - /// config.dataMode = PostHogDataMode.any; - /// ``` - @Deprecated('Behaves like `any`. Use `PostHogDataMode.any` instead.') - cellular, - /// Send data on any available connection. any, } @@ -98,16 +87,8 @@ class PostHogConfig { /// /// You can find it at: /// https://us.posthog.com/settings/project-details#variables - /// - /// This field was formerly named [apiKey]. final String projectToken; - /// Deprecated alias for [projectToken]. - @Deprecated( - 'Deprecated in favor of [projectToken]. This will be removed in the next major version.', - ) - String get apiKey => projectToken; - String _host = _defaultHost; /// The PostHog ingestion host. @@ -431,7 +412,6 @@ class PostHogConfig { Map toMap() { return { 'projectToken': projectToken, - 'apiKey': projectToken, 'host': host, 'flushAt': flushAt, 'maxQueueSize': maxQueueSize, @@ -865,17 +845,6 @@ class PostHogSessionReplayConfig { /// Default: null. PostHogTextMaskPolicy? textMaskPolicy; - /// Deprecated setter that forwards assigned values to [throttleDelay]. - /// - /// Debouncer delay used to reduce the number of snapshots captured and reduce - /// performance impact. This is used for capturing the view as a screenshot. - /// The lower the number, the more snapshots will be captured but higher the - /// performance impact. Defaults to 1s. - @Deprecated('Deprecated in favor of [throttleDelay] from v4.8.0.') - set debouncerDelay(Duration debouncerDelay) { - throttleDelay = debouncerDelay; - } - /// Throttling delay used to reduce the number of snapshots captured and reduce /// performance impact. /// diff --git a/posthog_flutter/lib/src/posthog_flutter_io.dart b/posthog_flutter/lib/src/posthog_flutter_io.dart index 4ed438be..a30f287f 100644 --- a/posthog_flutter/lib/src/posthog_flutter_io.dart +++ b/posthog_flutter/lib/src/posthog_flutter_io.dart @@ -683,22 +683,6 @@ class PosthogFlutterIO extends PosthogFlutterPlatformInterface { } } - @override - Future getFeatureFlagPayload({required String key}) async { - if (!isSupportedPlatform()) { - return null; - } - - try { - return await _methodChannel.invokeMethod('getFeatureFlagPayload', { - 'key': key, - }); - } on PlatformException catch (exception) { - printIfDebug('Exeption on getFeatureFlagPayload: $exception'); - return null; - } - } - @override Future getFeatureFlagResult({ required String key, diff --git a/posthog_flutter/lib/src/posthog_flutter_platform_interface.dart b/posthog_flutter/lib/src/posthog_flutter_platform_interface.dart index ee37df82..4c865355 100644 --- a/posthog_flutter/lib/src/posthog_flutter_platform_interface.dart +++ b/posthog_flutter/lib/src/posthog_flutter_platform_interface.dart @@ -204,12 +204,6 @@ abstract class PosthogFlutterPlatformInterface extends PlatformInterface { throw UnimplementedError('getFeatureFlag() has not been implemented.'); } - Future getFeatureFlagPayload({required String key}) { - throw UnimplementedError( - 'getFeatureFlagPayload() has not been implemented.', - ); - } - Future getFeatureFlagResult({ required String key, bool sendEvent = true, diff --git a/posthog_flutter/lib/src/posthog_flutter_web_handler.dart b/posthog_flutter/lib/src/posthog_flutter_web_handler.dart index 211a8dca..7f0b5406 100644 --- a/posthog_flutter/lib/src/posthog_flutter_web_handler.dart +++ b/posthog_flutter/lib/src/posthog_flutter_web_handler.dart @@ -57,7 +57,6 @@ extension PostHogExtension on PostHog { // ignore: non_constant_identifier_names external bool has_opted_out_capturing(); external JSAny? getFeatureFlag(JSAny key); - external JSAny? getFeatureFlagPayload(JSAny key); external JSAny? getFeatureFlagResult(JSAny key, [JSAny? options]); external void register(JSAny properties); external void unregister(JSAny key); @@ -367,11 +366,6 @@ Future handleWebMethodCall(MethodCall call) async { final featureFlag = posthog?.getFeatureFlag(stringToJSAny(key)); return featureFlag?.dartify(); - case 'getFeatureFlagPayload': - final key = args['key'] as String; - - final featureFlag = posthog?.getFeatureFlagPayload(stringToJSAny(key)); - return featureFlag?.dartify(); case 'getFeatureFlagResult': final key = args['key'] as String; final sendEvent = args['sendEvent'] as bool? ?? true; diff --git a/posthog_flutter/test/posthog_flutter_io_test.dart b/posthog_flutter/test/posthog_flutter_io_test.dart index b2469903..ca4e9316 100644 --- a/posthog_flutter/test/posthog_flutter_io_test.dart +++ b/posthog_flutter/test/posthog_flutter_io_test.dart @@ -112,14 +112,14 @@ void main() { }, ); - test('setup sends projectToken and deprecated apiKey alias', () async { + test('setup sends projectToken', () async { testConfig = PostHogConfig(' \n test_project_token\t '); await posthogFlutterIO.setup(testConfig); final call = log.firstWhere((c) => c.method == 'setup'); final args = Map.from(call.arguments as Map); expect(args['projectToken'], equals('test_project_token')); - expect(args['apiKey'], equals('test_project_token')); + expect(args.containsKey('apiKey'), isFalse); }); test( diff --git a/posthog_flutter/test/posthog_flutter_platform_interface_fake.dart b/posthog_flutter/test/posthog_flutter_platform_interface_fake.dart index 8b0bb563..2fad6e75 100644 --- a/posthog_flutter/test/posthog_flutter_platform_interface_fake.dart +++ b/posthog_flutter/test/posthog_flutter_platform_interface_fake.dart @@ -95,7 +95,6 @@ class PosthogFlutterPlatformFake extends PosthogFlutterPlatformInterface { // Feature flag test data final Map featureFlagValues = {}; - final Map featureFlagPayloads = {}; // Call tracking for getFeatureFlagResult final List> getFeatureFlagResultCalls = []; @@ -255,11 +254,6 @@ class PosthogFlutterPlatformFake extends PosthogFlutterPlatformInterface { return featureFlagValues[key]; } - @override - Future getFeatureFlagPayload({required String key}) async { - return featureFlagPayloads[key]; - } - PostHogFeatureFlagResult? featureFlagResult; @override diff --git a/posthog_flutter/test/posthog_test.dart b/posthog_flutter/test/posthog_test.dart index f526f3bd..7c249234 100644 --- a/posthog_flutter/test/posthog_test.dart +++ b/posthog_flutter/test/posthog_test.dart @@ -176,10 +176,8 @@ void main() { config.host = ' \nhttps://eu.i.posthog.com/\t '; expect(config.projectToken, equals('test_project_token')); - expect(config.apiKey, equals('test_project_token')); expect(config.host, equals('https://eu.i.posthog.com/')); expect(config.toMap()['projectToken'], equals('test_project_token')); - expect(config.toMap()['apiKey'], equals('test_project_token')); expect(config.toMap()['host'], equals('https://eu.i.posthog.com/')); }); diff --git a/posthog_flutter/test/snapshots/setup_request.json b/posthog_flutter/test/snapshots/setup_request.json index 58543998..367138b4 100644 --- a/posthog_flutter/test/snapshots/setup_request.json +++ b/posthog_flutter/test/snapshots/setup_request.json @@ -3,7 +3,6 @@ "method": "setup", "arguments": { "projectToken": "snapshot_project_token", - "apiKey": "snapshot_project_token", "host": "https://eu.i.posthog.com", "flushAt": 12, "maxQueueSize": 800, From df5e33eb3a2de303093a31ae1432f173411c9d1a Mon Sep 17 00:00:00 2001 From: Anna Garcia Date: Mon, 5 Oct 2026 16:01:33 -0400 Subject: [PATCH 2/7] chore(android): declare minSdkVersion 23 to match posthog-android posthog-android has required minSdk 23 since 3.39.0, and the plugin's dependency range [3.71.0, 4.0.0) only resolves to versions that need it. Apps below 23 already fail the manifest merge, so this only corrects the declared value. Co-Authored-By: Claude Opus 5.5 (1M context) --- .changeset/v6-remove-deprecated-apis.md | 1 + api/posthog_flutter.api.json | 2 +- posthog_flutter/android/build.gradle | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.changeset/v6-remove-deprecated-apis.md b/.changeset/v6-remove-deprecated-apis.md index d291102a..828de674 100644 --- a/.changeset/v6-remove-deprecated-apis.md +++ b/.changeset/v6-remove-deprecated-apis.md @@ -6,3 +6,4 @@ - **Breaking:** remove `Posthog().getFeatureFlagPayload()` — use `getFeatureFlagResult(key, sendEvent: false)` and read `payload` - **Breaking:** remove the `PostHogSessionReplayConfig.debouncerDelay` setter — use `PostHogSessionReplayConfig.throttleDelay` - **Breaking:** remove `PostHogDataMode.cellular` — use `PostHogDataMode.any`, which it always behaved like +- Declare Android `minSdkVersion` 23 to match `posthog-android`, which has required it since 3.39.0. Apps on minSdk 21 or 22 already could not build with this plugin, so nothing changes for them diff --git a/api/posthog_flutter.api.json b/api/posthog_flutter.api.json index b07cfe8f..aa0a9fde 100644 --- a/api/posthog_flutter.api.json +++ b/api/posthog_flutter.api.json @@ -13,7 +13,7 @@ "packageApi": { "androidPlatformConstraints": { "compileSdkVersion": null, - "minSdkVersion": 21, + "minSdkVersion": 23, "targetSdkVersion": null }, "executableDeclarations": [ diff --git a/posthog_flutter/android/build.gradle b/posthog_flutter/android/build.gradle index ba6dcb54..2ae6e792 100644 --- a/posthog_flutter/android/build.gradle +++ b/posthog_flutter/android/build.gradle @@ -58,7 +58,7 @@ android { } defaultConfig { - minSdkVersion 21 + minSdkVersion 23 } dependencies { From 10b7f9e7f58aa2991426f93c0c0d4e34664d6ae7 Mon Sep 17 00:00:00 2001 From: Anna Garcia <11654201+turnipdabeets@users.noreply.github.com> Date: Tue, 6 Oct 2026 20:35:01 -0400 Subject: [PATCH 3/7] chore!: remove enable/disable and sendFeatureFlagEvents (#638) Removes the names deprecated in 5.x in favor of optIn/optOut and sendFeatureFlagEvent. Co-authored-by: Claude Opus 5.5 (1M context) --- .changeset/v6-remove-5x-deprecations.md | 6 ++++ api/posthog_flutter.api.json | 35 --------------------- posthog_flutter/lib/src/posthog.dart | 12 ------- posthog_flutter/lib/src/posthog_config.dart | 11 ------- posthog_flutter/test/posthog_test.dart | 10 ------ 5 files changed, 6 insertions(+), 68 deletions(-) create mode 100644 .changeset/v6-remove-5x-deprecations.md diff --git a/.changeset/v6-remove-5x-deprecations.md b/.changeset/v6-remove-5x-deprecations.md new file mode 100644 index 00000000..7cde3baa --- /dev/null +++ b/.changeset/v6-remove-5x-deprecations.md @@ -0,0 +1,6 @@ +--- +"posthog_flutter": major +--- + +- **Breaking:** remove `Posthog().enable()` and `Posthog().disable()` — use `optIn()` and `optOut()` +- **Breaking:** remove `PostHogConfig.sendFeatureFlagEvents` — use `sendFeatureFlagEvent` diff --git a/api/posthog_flutter.api.json b/api/posthog_flutter.api.json index aa0a9fde..459d349e 100644 --- a/api/posthog_flutter.api.json +++ b/api/posthog_flutter.api.json @@ -2195,17 +2195,6 @@ "relativePath": "lib/src/posthog_config.dart", "typeName": "bool" }, - { - "entryPoints": [], - "isDeprecated": true, - "isExperimental": false, - "isReadable": true, - "isStatic": false, - "isWriteable": true, - "name": "sendFeatureFlagEvents", - "relativePath": "lib/src/posthog_config.dart", - "typeName": "bool" - }, { "entryPoints": [], "isDeprecated": false, @@ -4286,30 +4275,6 @@ "type": "method", "typeParameterNames": [] }, - { - "entryPoints": [], - "isDeprecated": true, - "isExperimental": false, - "isStatic": false, - "name": "disable", - "parameters": [], - "relativePath": "lib/src/posthog.dart", - "returnTypeName": "Future", - "type": "method", - "typeParameterNames": [] - }, - { - "entryPoints": [], - "isDeprecated": true, - "isExperimental": false, - "isStatic": false, - "name": "enable", - "parameters": [], - "relativePath": "lib/src/posthog.dart", - "returnTypeName": "Future", - "type": "method", - "typeParameterNames": [] - }, { "entryPoints": [], "isDeprecated": false, diff --git a/posthog_flutter/lib/src/posthog.dart b/posthog_flutter/lib/src/posthog.dart index 65f4211a..04a2e933 100644 --- a/posthog_flutter/lib/src/posthog.dart +++ b/posthog_flutter/lib/src/posthog.dart @@ -427,18 +427,6 @@ class Posthog { } } - /// Opts the current user out of data collection. - @Deprecated( - 'Use optOut() instead. This will be removed in the next major version.', - ) - Future disable() => optOut(); - - /// Opts the current user back in to data collection. - @Deprecated( - 'Use optIn() instead. This will be removed in the next major version.', - ) - Future enable() => optIn(); - /// Returns whether the current user has opted out of data collection. Future isOptOut() => _posthog.isOptOut(); diff --git a/posthog_flutter/lib/src/posthog_config.dart b/posthog_flutter/lib/src/posthog_config.dart index 5bd9230b..78b2c2c8 100644 --- a/posthog_flutter/lib/src/posthog_config.dart +++ b/posthog_flutter/lib/src/posthog_config.dart @@ -124,17 +124,6 @@ class PostHogConfig { /// Defaults to `true`. var sendFeatureFlagEvent = true; - /// Deprecated alias for [sendFeatureFlagEvent]. - @Deprecated( - 'Use sendFeatureFlagEvent instead. This will be removed in the next major version.', - ) - bool get sendFeatureFlagEvents => sendFeatureFlagEvent; - - @Deprecated( - 'Use sendFeatureFlagEvent instead. This will be removed in the next major version.', - ) - set sendFeatureFlagEvents(bool value) => sendFeatureFlagEvent = value; - /// Whether feature flags are loaded when the SDK starts. /// /// Defaults to `true`, which means every SDK start issues a `/flags` request. diff --git a/posthog_flutter/test/posthog_test.dart b/posthog_flutter/test/posthog_test.dart index 7c249234..fcec7dcf 100644 --- a/posthog_flutter/test/posthog_test.dart +++ b/posthog_flutter/test/posthog_test.dart @@ -161,16 +161,6 @@ void main() { }); group('PostHogConfig', () { - test('sendFeatureFlagEvents forwards to sendFeatureFlagEvent', () { - final config = PostHogConfig('test_project_token'); - - // ignore: deprecated_member_use_from_same_package - config.sendFeatureFlagEvents = false; - - expect(config.sendFeatureFlagEvent, isFalse); - expect(config.toMap()['sendFeatureFlagEvents'], isFalse); - }); - test('trims whitespace-sensitive config values in config and toMap', () { final config = PostHogConfig(' \n test_project_token\t '); config.host = ' \nhttps://eu.i.posthog.com/\t '; From 47fe85b9ff5ce8c73b4c18e1739c9ae7ffb3b1ef Mon Sep 17 00:00:00 2001 From: Anna Garcia <11654201+turnipdabeets@users.noreply.github.com> Date: Wed, 7 Oct 2026 13:57:55 -0400 Subject: [PATCH 4/7] chore!: rename getFeatureFlagResult sendEvent to sendFeatureFlagEvent (#647) Matches PostHogConfig.sendFeatureFlagEvent and the iOS/Android getFeatureFlagResult parameter. The method-channel key stays 'sendEvent'. Co-authored-by: Claude Opus 5.5 (1M context) --- .changeset/v6-remove-deprecated-apis.md | 2 +- .changeset/v6-send-feature-flag-event-param.md | 5 +++++ api/posthog_flutter.api.json | 6 +++--- posthog_flutter/lib/posthog_flutter_web.dart | 5 +++-- posthog_flutter/lib/src/posthog.dart | 11 ++++++----- posthog_flutter/lib/src/posthog_flutter_io.dart | 4 ++-- .../src/posthog_flutter_platform_interface.dart | 2 +- .../test/posthog_flutter_io_test.dart | 2 +- .../posthog_flutter_platform_interface_fake.dart | 5 +++-- posthog_flutter/test/posthog_test.dart | 16 +++++++++------- 10 files changed, 34 insertions(+), 24 deletions(-) create mode 100644 .changeset/v6-send-feature-flag-event-param.md diff --git a/.changeset/v6-remove-deprecated-apis.md b/.changeset/v6-remove-deprecated-apis.md index 828de674..52ef0668 100644 --- a/.changeset/v6-remove-deprecated-apis.md +++ b/.changeset/v6-remove-deprecated-apis.md @@ -3,7 +3,7 @@ --- - **Breaking:** remove `PostHogConfig.apiKey` and the `com.posthog.posthog.API_KEY` manifest/Info.plist key — use `projectToken` and `com.posthog.posthog.PROJECT_TOKEN` -- **Breaking:** remove `Posthog().getFeatureFlagPayload()` — use `getFeatureFlagResult(key, sendEvent: false)` and read `payload` +- **Breaking:** remove `Posthog().getFeatureFlagPayload()` — use `getFeatureFlagResult(key, sendFeatureFlagEvent: false)` and read `payload` - **Breaking:** remove the `PostHogSessionReplayConfig.debouncerDelay` setter — use `PostHogSessionReplayConfig.throttleDelay` - **Breaking:** remove `PostHogDataMode.cellular` — use `PostHogDataMode.any`, which it always behaved like - Declare Android `minSdkVersion` 23 to match `posthog-android`, which has required it since 3.39.0. Apps on minSdk 21 or 22 already could not build with this plugin, so nothing changes for them diff --git a/.changeset/v6-send-feature-flag-event-param.md b/.changeset/v6-send-feature-flag-event-param.md new file mode 100644 index 00000000..677d86fb --- /dev/null +++ b/.changeset/v6-send-feature-flag-event-param.md @@ -0,0 +1,5 @@ +--- +"posthog_flutter": major +--- + +- **Breaking:** `getFeatureFlagResult(sendEvent:)` is now `getFeatureFlagResult(sendFeatureFlagEvent:)`, matching `PostHogConfig.sendFeatureFlagEvent` and the native SDKs diff --git a/api/posthog_flutter.api.json b/api/posthog_flutter.api.json index 459d349e..cf8b6a68 100644 --- a/api/posthog_flutter.api.json +++ b/api/posthog_flutter.api.json @@ -897,7 +897,7 @@ "isExperimental": false, "isNamed": true, "isRequired": false, - "name": "sendEvent", + "name": "sendFeatureFlagEvent", "relativePath": "lib/src/posthog_flutter_platform_interface.dart", "typeName": "bool" } @@ -1858,7 +1858,7 @@ "isExperimental": false, "isNamed": true, "isRequired": false, - "name": "sendEvent", + "name": "sendFeatureFlagEvent", "relativePath": "lib/src/posthog_flutter_platform_interface.dart", "typeName": "bool" } @@ -4704,7 +4704,7 @@ "isExperimental": false, "isNamed": true, "isRequired": false, - "name": "sendEvent", + "name": "sendFeatureFlagEvent", "relativePath": "lib/src/posthog.dart", "typeName": "bool" } diff --git a/posthog_flutter/lib/posthog_flutter_web.dart b/posthog_flutter/lib/posthog_flutter_web.dart index 48cece36..527bbe6f 100644 --- a/posthog_flutter/lib/posthog_flutter_web.dart +++ b/posthog_flutter/lib/posthog_flutter_web.dart @@ -423,10 +423,11 @@ class PosthogFlutterWeb extends PosthogFlutterPlatformInterface { @override Future getFeatureFlagResult({ required String key, - bool sendEvent = true, + bool sendFeatureFlagEvent = true, }) async { final result = await handleWebMethodCall( - MethodCall('getFeatureFlagResult', {'key': key, 'sendEvent': sendEvent}), + MethodCall('getFeatureFlagResult', + {'key': key, 'sendEvent': sendFeatureFlagEvent}), ); // Web SDK returns: { key, enabled, variant, payload } diff --git a/posthog_flutter/lib/src/posthog.dart b/posthog_flutter/lib/src/posthog.dart index 04a2e933..007f235e 100644 --- a/posthog_flutter/lib/src/posthog.dart +++ b/posthog_flutter/lib/src/posthog.dart @@ -749,9 +749,9 @@ class Posthog { /// This is the canonical method for getting feature flag data. /// Returns `null` if the flag does not exist or cannot be loaded. /// - /// Set [sendEvent] to `false` to suppress the `$feature_flag_called` event. - /// This is useful when you only need the payload and do not want to emit the - /// event. + /// Set [sendFeatureFlagEvent] to `false` to suppress the + /// `$feature_flag_called` event. This is useful when you only need the + /// payload and do not want to emit the event. /// /// **Example:** /// ```dart @@ -763,9 +763,10 @@ class Posthog { /// ``` Future getFeatureFlagResult( String key, { - bool sendEvent = true, + bool sendFeatureFlagEvent = true, }) => - _posthog.getFeatureFlagResult(key: key, sendEvent: sendEvent); + _posthog.getFeatureFlagResult( + key: key, sendFeatureFlagEvent: sendFeatureFlagEvent); /// Flushes queued events immediately where supported by the platform. /// diff --git a/posthog_flutter/lib/src/posthog_flutter_io.dart b/posthog_flutter/lib/src/posthog_flutter_io.dart index a30f287f..dd42206b 100644 --- a/posthog_flutter/lib/src/posthog_flutter_io.dart +++ b/posthog_flutter/lib/src/posthog_flutter_io.dart @@ -686,7 +686,7 @@ class PosthogFlutterIO extends PosthogFlutterPlatformInterface { @override Future getFeatureFlagResult({ required String key, - bool sendEvent = true, + bool sendFeatureFlagEvent = true, }) async { if (!isSupportedPlatform()) { return null; @@ -695,7 +695,7 @@ class PosthogFlutterIO extends PosthogFlutterPlatformInterface { try { final result = await _methodChannel.invokeMethod('getFeatureFlagResult', { 'key': key, - 'sendEvent': sendEvent, + 'sendEvent': sendFeatureFlagEvent, }); // Native returns: { key, enabled, variant, payload } diff --git a/posthog_flutter/lib/src/posthog_flutter_platform_interface.dart b/posthog_flutter/lib/src/posthog_flutter_platform_interface.dart index 4c865355..703b390e 100644 --- a/posthog_flutter/lib/src/posthog_flutter_platform_interface.dart +++ b/posthog_flutter/lib/src/posthog_flutter_platform_interface.dart @@ -206,7 +206,7 @@ abstract class PosthogFlutterPlatformInterface extends PlatformInterface { Future getFeatureFlagResult({ required String key, - bool sendEvent = true, + bool sendFeatureFlagEvent = true, }) { throw UnimplementedError( 'getFeatureFlagResult() has not been implemented.', diff --git a/posthog_flutter/test/posthog_flutter_io_test.dart b/posthog_flutter/test/posthog_flutter_io_test.dart index ca4e9316..fa0b838d 100644 --- a/posthog_flutter/test/posthog_flutter_io_test.dart +++ b/posthog_flutter/test/posthog_flutter_io_test.dart @@ -67,7 +67,7 @@ void main() { }; }); final result = await posthogFlutterIO.getFeatureFlagResult( - key: 'flag', sendEvent: false); + key: 'flag', sendFeatureFlagEvent: false); expect(result, isNotNull); expect(result!.key, 'flag'); expect(result.enabled, enabled); diff --git a/posthog_flutter/test/posthog_flutter_platform_interface_fake.dart b/posthog_flutter/test/posthog_flutter_platform_interface_fake.dart index 2fad6e75..08c68d23 100644 --- a/posthog_flutter/test/posthog_flutter_platform_interface_fake.dart +++ b/posthog_flutter/test/posthog_flutter_platform_interface_fake.dart @@ -259,9 +259,10 @@ class PosthogFlutterPlatformFake extends PosthogFlutterPlatformInterface { @override Future getFeatureFlagResult({ required String key, - bool sendEvent = true, + bool sendFeatureFlagEvent = true, }) async { - getFeatureFlagResultCalls.add({'key': key, 'sendEvent': sendEvent}); + getFeatureFlagResultCalls + .add({'key': key, 'sendFeatureFlagEvent': sendFeatureFlagEvent}); return featureFlagResult; } diff --git a/posthog_flutter/test/posthog_test.dart b/posthog_flutter/test/posthog_test.dart index fcec7dcf..59874c98 100644 --- a/posthog_flutter/test/posthog_test.dart +++ b/posthog_flutter/test/posthog_test.dart @@ -375,7 +375,7 @@ void main() { final result = await Posthog().getFeatureFlagResult('non-existent'); expect(result, isNull); expect(fakePlatformInterface.getFeatureFlagResultCalls, [ - {'key': 'non-existent', 'sendEvent': true} + {'key': 'non-existent', 'sendFeatureFlagEvent': true} ]); }); @@ -390,24 +390,26 @@ void main() { expect( await Posthog().getFeatureFlagResult('variant-flag'), same(expected)); expect(fakePlatformInterface.getFeatureFlagResultCalls, [ - {'key': 'variant-flag', 'sendEvent': true} + {'key': 'variant-flag', 'sendFeatureFlagEvent': true} ]); }); - test('passes sendEvent=true by default', () async { + test('passes sendFeatureFlagEvent=true by default', () async { await Posthog().getFeatureFlagResult('test'); expect( - fakePlatformInterface.getFeatureFlagResultCalls.last['sendEvent'], + fakePlatformInterface + .getFeatureFlagResultCalls.last['sendFeatureFlagEvent'], isTrue, ); }); - test('passes sendEvent=false when specified', () async { - await Posthog().getFeatureFlagResult('test', sendEvent: false); + test('passes sendFeatureFlagEvent=false when specified', () async { + await Posthog().getFeatureFlagResult('test', sendFeatureFlagEvent: false); expect( - fakePlatformInterface.getFeatureFlagResultCalls.last['sendEvent'], + fakePlatformInterface + .getFeatureFlagResultCalls.last['sendFeatureFlagEvent'], isFalse, ); }); From 054e3deb1f5e17004129abc721d628198a748b55 Mon Sep 17 00:00:00 2001 From: Anna Garcia <11654201+turnipdabeets@users.noreply.github.com> Date: Wed, 7 Oct 2026 14:22:25 -0400 Subject: [PATCH 5/7] chore!: rename platform enable/disable to optIn/optOut (#645) * chore!: rename platform enable/disable to optIn/optOut PosthogFlutterPlatformInterface.enable()/disable() become optIn()/optOut() to match the public Posthog API renamed in #636/#638. The method-channel names sent to native stay 'enable'/'disable'. Co-Authored-By: Claude Opus 5.5 (1M context) * docs(changeset): cover direct platform callers in the opt-in/out rename Co-Authored-By: Claude Opus 5.5 (1M context) --------- Co-authored-by: Claude Opus 5.5 (1M context) --- .changeset/v6-platform-opt-in-out.md | 5 +++++ api/posthog_flutter.api.json | 8 ++++---- posthog_flutter/lib/posthog_flutter_web.dart | 4 ++-- posthog_flutter/lib/src/posthog.dart | 4 ++-- posthog_flutter/lib/src/posthog_flutter_io.dart | 4 ++-- .../lib/src/posthog_flutter_platform_interface.dart | 8 ++++---- .../test/posthog_flutter_platform_interface_fake.dart | 4 ++-- 7 files changed, 21 insertions(+), 16 deletions(-) create mode 100644 .changeset/v6-platform-opt-in-out.md diff --git a/.changeset/v6-platform-opt-in-out.md b/.changeset/v6-platform-opt-in-out.md new file mode 100644 index 00000000..0bdcaddf --- /dev/null +++ b/.changeset/v6-platform-opt-in-out.md @@ -0,0 +1,5 @@ +--- +"posthog_flutter": major +--- + +- **Breaking:** rename `enable()`/`disable()` to `optIn()`/`optOut()` on `PosthogFlutterPlatformInterface`, `PosthogFlutterIO` and `PosthogFlutterWeb`. Update direct calls to these platform classes, custom implementations, and test fakes/mocks. Calls to `Posthog().optIn()`/`optOut()` are unchanged diff --git a/api/posthog_flutter.api.json b/api/posthog_flutter.api.json index cf8b6a68..f13ca9d6 100644 --- a/api/posthog_flutter.api.json +++ b/api/posthog_flutter.api.json @@ -565,7 +565,7 @@ "isDeprecated": false, "isExperimental": false, "isStatic": false, - "name": "disable", + "name": "optOut", "parameters": [], "relativePath": "lib/src/posthog_flutter_platform_interface.dart", "returnTypeName": "Future", @@ -577,7 +577,7 @@ "isDeprecated": false, "isExperimental": false, "isStatic": false, - "name": "enable", + "name": "optIn", "parameters": [], "relativePath": "lib/src/posthog_flutter_platform_interface.dart", "returnTypeName": "Future", @@ -1526,7 +1526,7 @@ "isDeprecated": false, "isExperimental": false, "isStatic": false, - "name": "disable", + "name": "optOut", "parameters": [], "relativePath": "lib/src/posthog_flutter_platform_interface.dart", "returnTypeName": "Future", @@ -1538,7 +1538,7 @@ "isDeprecated": false, "isExperimental": false, "isStatic": false, - "name": "enable", + "name": "optIn", "parameters": [], "relativePath": "lib/src/posthog_flutter_platform_interface.dart", "returnTypeName": "Future", diff --git a/posthog_flutter/lib/posthog_flutter_web.dart b/posthog_flutter/lib/posthog_flutter_web.dart index 527bbe6f..cede7c5f 100644 --- a/posthog_flutter/lib/posthog_flutter_web.dart +++ b/posthog_flutter/lib/posthog_flutter_web.dart @@ -315,12 +315,12 @@ class PosthogFlutterWeb extends PosthogFlutterPlatformInterface { } @override - Future disable() async { + Future optOut() async { return handleWebMethodCall(const MethodCall('disable')); } @override - Future enable() async { + Future optIn() async { return handleWebMethodCall(const MethodCall('enable')); } diff --git a/posthog_flutter/lib/src/posthog.dart b/posthog_flutter/lib/src/posthog.dart index 007f235e..ed459a5e 100644 --- a/posthog_flutter/lib/src/posthog.dart +++ b/posthog_flutter/lib/src/posthog.dart @@ -402,7 +402,7 @@ class Posthog { stopReplay = _posthog.stopSessionRecording(); } - await Future.wait([if (stopReplay != null) stopReplay, _posthog.disable()]); + await Future.wait([if (stopReplay != null) stopReplay, _posthog.optOut()]); } /// Opts the current user back in to data collection. @@ -417,7 +417,7 @@ class Posthog { _installFlutterIntegrations(config); } - await _posthog.enable(); + await _posthog.optIn(); final restartReplay = _restartSessionReplayOnEnable; _restartSessionReplayOnEnable = false; if (restartReplay) { diff --git a/posthog_flutter/lib/src/posthog_flutter_io.dart b/posthog_flutter/lib/src/posthog_flutter_io.dart index dd42206b..2bf87a96 100644 --- a/posthog_flutter/lib/src/posthog_flutter_io.dart +++ b/posthog_flutter/lib/src/posthog_flutter_io.dart @@ -491,7 +491,7 @@ class PosthogFlutterIO extends PosthogFlutterPlatformInterface { } @override - Future disable() async { + Future optOut() async { if (!isSupportedPlatform()) { return; } @@ -504,7 +504,7 @@ class PosthogFlutterIO extends PosthogFlutterPlatformInterface { } @override - Future enable() async { + Future optIn() async { if (!isSupportedPlatform()) { return; } diff --git a/posthog_flutter/lib/src/posthog_flutter_platform_interface.dart b/posthog_flutter/lib/src/posthog_flutter_platform_interface.dart index 703b390e..729f4de3 100644 --- a/posthog_flutter/lib/src/posthog_flutter_platform_interface.dart +++ b/posthog_flutter/lib/src/posthog_flutter_platform_interface.dart @@ -129,12 +129,12 @@ abstract class PosthogFlutterPlatformInterface extends PlatformInterface { throw UnimplementedError('reset() has not been implemented.'); } - Future disable() { - throw UnimplementedError('disable() has not been implemented.'); + Future optOut() { + throw UnimplementedError('optOut() has not been implemented.'); } - Future enable() { - throw UnimplementedError('enable() has not been implemented.'); + Future optIn() { + throw UnimplementedError('optIn() has not been implemented.'); } Future isOptOut() { diff --git a/posthog_flutter/test/posthog_flutter_platform_interface_fake.dart b/posthog_flutter/test/posthog_flutter_platform_interface_fake.dart index 08c68d23..08b9c662 100644 --- a/posthog_flutter/test/posthog_flutter_platform_interface_fake.dart +++ b/posthog_flutter/test/posthog_flutter_platform_interface_fake.dart @@ -228,10 +228,10 @@ class PosthogFlutterPlatformFake extends PosthogFlutterPlatformInterface { } @override - Future disable() async {} + Future optOut() async {} @override - Future enable() async {} + Future optIn() async {} @override Future close() async { From 4737007a8c966ff58ec9c85fdca0e29fecf10a92 Mon Sep 17 00:00:00 2001 From: Anna Garcia <11654201+turnipdabeets@users.noreply.github.com> Date: Wed, 7 Oct 2026 14:49:16 -0400 Subject: [PATCH 6/7] chore!: remove serialization helpers from the public API (#646) toMap() on the config classes and PostHogFeatureFlagResult.fromMap() are the platform-channel wire format, not a user-facing data shape. Move them to extensions and a top-level function in an unexported src/utils/channel_serialization.dart so they drop out of the public API. Co-authored-by: Claude Opus 5.5 (1M context) --- .changeset/v6-hide-serialization.md | 5 + api/posthog_flutter.api.json | 115 ------------ posthog_flutter/lib/posthog_flutter_web.dart | 3 +- .../lib/src/feature_flag_result.dart | 19 -- posthog_flutter/lib/src/posthog_config.dart | 153 ---------------- .../lib/src/posthog_flutter_io.dart | 3 +- .../lib/src/utils/channel_serialization.dart | 171 ++++++++++++++++++ posthog_flutter/test/posthog_logs_test.dart | 1 + posthog_flutter/test/posthog_test.dart | 11 +- .../test/replay_capture_touches_test.dart | 1 + .../test/replay_screenshot_config_test.dart | 1 + 11 files changed, 189 insertions(+), 294 deletions(-) create mode 100644 .changeset/v6-hide-serialization.md create mode 100644 posthog_flutter/lib/src/utils/channel_serialization.dart diff --git a/.changeset/v6-hide-serialization.md b/.changeset/v6-hide-serialization.md new file mode 100644 index 00000000..9eb46db6 --- /dev/null +++ b/.changeset/v6-hide-serialization.md @@ -0,0 +1,5 @@ +--- +"posthog_flutter": major +--- + +- **Breaking:** remove `toMap()` from the config classes and `PostHogFeatureFlagResult.fromMap()` from the public API — they serialize the internal platform-channel wire format and were never meant for app code diff --git a/api/posthog_flutter.api.json b/api/posthog_flutter.api.json index f13ca9d6..c7ad8302 100644 --- a/api/posthog_flutter.api.json +++ b/api/posthog_flutter.api.json @@ -2064,18 +2064,6 @@ "posthog_flutter.dart" ], "executableDeclarations": [ - { - "entryPoints": [], - "isDeprecated": false, - "isExperimental": false, - "isStatic": false, - "name": "toMap", - "parameters": [], - "relativePath": "lib/src/posthog_config.dart", - "returnTypeName": "Map", - "type": "method", - "typeParameterNames": [] - }, { "entryPoints": [], "isDeprecated": false, @@ -2421,18 +2409,6 @@ "posthog_flutter.dart" ], "executableDeclarations": [ - { - "entryPoints": [], - "isDeprecated": false, - "isExperimental": false, - "isStatic": false, - "name": "toMap", - "parameters": [], - "relativePath": "lib/src/posthog_config.dart", - "returnTypeName": "Map", - "type": "method", - "typeParameterNames": [] - }, { "entryPoints": [], "isDeprecated": false, @@ -2623,18 +2599,6 @@ "posthog_flutter.dart" ], "executableDeclarations": [ - { - "entryPoints": [], - "isDeprecated": false, - "isExperimental": false, - "isStatic": false, - "name": "toMap", - "parameters": [], - "relativePath": "lib/src/posthog_config.dart", - "returnTypeName": "Map", - "type": "method", - "typeParameterNames": [] - }, { "entryPoints": [], "isDeprecated": false, @@ -2913,18 +2877,6 @@ "posthog_flutter.dart" ], "executableDeclarations": [ - { - "entryPoints": [], - "isDeprecated": false, - "isExperimental": false, - "isStatic": false, - "name": "toMap", - "parameters": [], - "relativePath": "lib/src/posthog_config.dart", - "returnTypeName": "Map", - "type": "method", - "typeParameterNames": [] - }, { "entryPoints": [], "isDeprecated": false, @@ -3066,18 +3018,6 @@ "posthog_flutter.dart" ], "executableDeclarations": [ - { - "entryPoints": [], - "isDeprecated": false, - "isExperimental": false, - "isStatic": false, - "name": "toMap", - "parameters": [], - "relativePath": "lib/src/posthog_config.dart", - "returnTypeName": "Map", - "type": "method", - "typeParameterNames": [] - }, { "entryPoints": [], "isDeprecated": false, @@ -3131,18 +3071,6 @@ "posthog_flutter.dart" ], "executableDeclarations": [ - { - "entryPoints": [], - "isDeprecated": false, - "isExperimental": false, - "isStatic": false, - "name": "toMap", - "parameters": [], - "relativePath": "lib/src/posthog_config.dart", - "returnTypeName": "Map", - "type": "method", - "typeParameterNames": [] - }, { "entryPoints": [], "isDeprecated": false, @@ -3295,18 +3223,6 @@ "posthog_flutter.dart" ], "executableDeclarations": [ - { - "entryPoints": [], - "isDeprecated": false, - "isExperimental": false, - "isStatic": false, - "name": "toMap", - "parameters": [], - "relativePath": "lib/src/posthog_config.dart", - "returnTypeName": "Map", - "type": "method", - "typeParameterNames": [] - }, { "entryPoints": [], "isDeprecated": false, @@ -3515,37 +3431,6 @@ "posthog_flutter.dart" ], "executableDeclarations": [ - { - "entryPoints": [], - "isDeprecated": false, - "isExperimental": false, - "isStatic": true, - "name": "fromMap", - "parameters": [ - { - "isDeprecated": false, - "isExperimental": false, - "isNamed": false, - "isRequired": true, - "name": "result", - "relativePath": "lib/src/feature_flag_result.dart", - "typeName": "Object?" - }, - { - "isDeprecated": false, - "isExperimental": false, - "isNamed": false, - "isRequired": true, - "name": "fallbackKey", - "relativePath": "lib/src/feature_flag_result.dart", - "typeName": "String" - } - ], - "relativePath": "lib/src/feature_flag_result.dart", - "returnTypeName": "PostHogFeatureFlagResult?", - "type": "method", - "typeParameterNames": [] - }, { "entryPoints": [], "isDeprecated": false, diff --git a/posthog_flutter/lib/posthog_flutter_web.dart b/posthog_flutter/lib/posthog_flutter_web.dart index cede7c5f..05483e49 100644 --- a/posthog_flutter/lib/posthog_flutter_web.dart +++ b/posthog_flutter/lib/posthog_flutter_web.dart @@ -7,6 +7,7 @@ import 'package:flutter/services.dart'; import 'package:flutter_web_plugins/flutter_web_plugins.dart'; import 'package:posthog_flutter/src/error_tracking/dart_exception_processor.dart'; import 'package:posthog_flutter/src/util/logging.dart'; +import 'package:posthog_flutter/src/utils/channel_serialization.dart'; import 'package:posthog_flutter/src/utils/property_normalizer.dart'; import 'src/feature_flag_result.dart'; @@ -431,7 +432,7 @@ class PosthogFlutterWeb extends PosthogFlutterPlatformInterface { ); // Web SDK returns: { key, enabled, variant, payload } - return PostHogFeatureFlagResult.fromMap(result, key); + return featureFlagResultFromMap(result, key); } @override diff --git a/posthog_flutter/lib/src/feature_flag_result.dart b/posthog_flutter/lib/src/feature_flag_result.dart index 9a85fef5..14298af1 100644 --- a/posthog_flutter/lib/src/feature_flag_result.dart +++ b/posthog_flutter/lib/src/feature_flag_result.dart @@ -53,23 +53,4 @@ class PostHogFeatureFlagResult { @override int get hashCode => Object.hash(key, enabled, variant); - - /// Creates a [PostHogFeatureFlagResult] from a native SDK response map. - /// - /// The [result] should be a map containing `key`, `enabled`, `variant`, and - /// `payload` entries. Falls back to [fallbackKey] if the map does not include - /// a key. - /// - /// Returns `null` if [result] is `null` or is not a [Map]. - static PostHogFeatureFlagResult? fromMap(Object? result, String fallbackKey) { - if (result == null) return null; - if (result is! Map) return null; - - return PostHogFeatureFlagResult( - key: result['key'] as String? ?? fallbackKey, - enabled: result['enabled'] as bool? ?? false, - variant: result['variant'] as String?, - payload: result['payload'], - ); - } } diff --git a/posthog_flutter/lib/src/posthog_config.dart b/posthog_flutter/lib/src/posthog_config.dart index 78b2c2c8..c501e432 100644 --- a/posthog_flutter/lib/src/posthog_config.dart +++ b/posthog_flutter/lib/src/posthog_config.dart @@ -7,7 +7,6 @@ import 'posthog.dart'; import 'posthog_event.dart'; import 'posthog_flutter_platform_interface.dart'; import 'replay/mask/posthog_text_mask.dart'; -import 'util/logging.dart'; /// Callback to intercept and modify events before they are sent to PostHog. /// @@ -394,42 +393,6 @@ class PostHogConfig { final trimmedHost = host.trim(); return trimmedHost.isEmpty ? _defaultHost : trimmedHost; } - - /// Converts this configuration to a platform-channel map. - /// - /// Returns the values consumed by the Android, Apple, and web implementations. - Map toMap() { - return { - 'projectToken': projectToken, - 'host': host, - 'flushAt': flushAt, - 'maxQueueSize': maxQueueSize, - 'maxBatchSize': maxBatchSize, - 'flushInterval': flushInterval.inSeconds, - 'sendFeatureFlagEvents': sendFeatureFlagEvent, - 'preloadFeatureFlags': preloadFeatureFlags, - 'captureApplicationLifecycleEvents': captureApplicationLifecycleEvents, - 'rageClickConfig': rageClickConfig.toMap(), - 'debug': debug, - 'optOut': optOut, - 'surveys': surveys, - 'personProfiles': personProfiles.name, - 'compression': compression.name, - 'sessionReplay': sessionReplay, - 'dataMode': dataMode.name, - 'sessionReplayConfig': sessionReplayConfig.toMap(), - 'errorTrackingConfig': errorTrackingConfig.toMap(), - 'logs': logsConfig.toMap(), - 'capturePushNotificationSubscriptions': - capturePushNotificationSubscriptions, - 'capturePushNotificationOpened': capturePushNotificationOpened, - // A closure can't cross the channel. This tells native whether to install - // a bridging provider at all — installing one the host didn't ask for - // would change how the native SDK handles a 401 on the subscription call. - 'pushIdentityProviderEnabled': pushIdentityProvider != null, - if (bootstrap != null) 'bootstrap': bootstrap!.toMap(), - }; - } } /// Pre-seeded identity and feature-flag state applied on the very first SDK @@ -486,34 +449,6 @@ class PostHogBootstrapConfig { /// JSON payloads paired with [featureFlags], keyed by flag key. Each value is /// the already-decoded payload (map, list, string, number, `null`, ...). final Map? featureFlagPayloads; - - /// Converts this configuration to a platform-channel map. - /// - /// Only the dimensions that were set are included; [isIdentifiedId] is always - /// sent so the native SDK doesn't have to infer it. - Map toMap() { - final flags = featureFlags; - if (flags != null) { - for (final entry in flags.entries) { - // Only bool/String are served (see [featureFlags]); the native SDKs drop - // anything else silently, so warn instead of leaving no trace. - if (entry.value is! bool && entry.value is! String) { - printIfDebug( - '[PostHog] bootstrap featureFlags["${entry.key}"] is ' - '${entry.value.runtimeType}; only bool and String values are served, ' - 'so this entry will be ignored.', - ); - } - } - } - return { - if (distinctId != null) 'distinctId': distinctId, - 'isIdentifiedId': isIdentifiedId, - if (featureFlags != null) 'featureFlags': featureFlags, - if (featureFlagPayloads != null) - 'featureFlagPayloads': featureFlagPayloads, - }; - } } /// Configuration for the logs subsystem. @@ -615,36 +550,6 @@ class PostHogLogsConfig { /// record. Keep anything sensitive out of those fields; put it in [body] or /// [PostHogLogRecord.attributes], which a callback can scrub or drop. List beforeSend = []; - - /// Converts the identity and tuning options to a platform-channel map. - /// - /// Only fields the user set are included, so unset fields keep the native - /// default. [beforeSend] is intentionally omitted: it runs in Dart and never - /// crosses the platform channel. - Map toMap() { - return { - if (serviceName != null) 'serviceName': serviceName, - if (serviceVersion != null) 'serviceVersion': serviceVersion, - if (environment != null) 'environment': environment, - if (resourceAttributes.isNotEmpty) - 'resourceAttributes': resourceAttributes, - if (flushInterval != null) - 'flushIntervalSeconds': _wholeSeconds(flushInterval!), - if (flushAt != null) 'flushAt': flushAt, - if (maxBatchSize != null) 'maxBatchSize': maxBatchSize, - if (maxBufferSize != null) 'maxBufferSize': maxBufferSize, - if (rateCapMaxLogs != null) 'rateCapMaxLogs': rateCapMaxLogs, - if (rateCapWindow != null) - 'rateCapWindowSeconds': _wholeSeconds(rateCapWindow!), - }; - } - - /// The native flush interval and rate-cap window are whole seconds. A - /// sub-second [Duration] truncates to `0`, which the native SDK treats as - /// "disabled" (rate cap) or continuous flushing — surprising for a caller who - /// set, say, 500ms. Floor at 1s, the smallest value the native API can honor. - static int _wholeSeconds(Duration duration) => - duration.inSeconds < 1 ? 1 : duration.inSeconds; } /// Configuration for rage-click autocapture on iOS and Mac Catalyst. @@ -674,17 +579,6 @@ class PostHogRageClickConfig { /// /// Defaults to `3`. var minimumTapCount = 3; - - /// Converts this rage-click configuration to a platform-channel map. - Map toMap() { - return { - 'enabled': enabled, - 'thresholdPoints': thresholdPoints, - 'timeoutInterval': - timeoutInterval.inMicroseconds / Duration.microsecondsPerSecond, - 'minimumTapCount': minimumTapCount, - }; - } } /// Pixel format for Android native-screen captures in session replay. @@ -966,26 +860,6 @@ class PostHogSessionReplayConfig { /// /// Default: false. var verifyScreenshotMaskAlignment = false; - - /// Converts this session replay configuration to a platform-channel map. - /// - /// Returns values consumed by the Android and Apple session replay - /// implementations. - Map toMap() { - return { - 'captureTouches': captureTouches, - 'maskAllImages': maskAllImages, - 'maskAllTexts': maskAllTexts, - 'throttleDelayMs': throttleDelay.inMilliseconds, - 'maskAllPlatformViews': maskAllPlatformViews, - 'captureNativeScreens': captureNativeScreens, - 'verifyScreenshotMaskAlignment': verifyScreenshotMaskAlignment, - 'screenshotScale': screenshotScale, - 'screenshotCompressionQuality': screenshotCompressionQuality, - 'screenshotColorMode': screenshotColorMode.name, - if (sampleRate != null) 'sampleRate': sampleRate, - }; - } } /// Configuration for PostHog error tracking and exception capture. @@ -1159,25 +1033,6 @@ class PostHogErrorTrackingConfig { /// /// Record steps with `Posthog().addExceptionStep()`. final exceptionSteps = PostHogExceptionStepsConfig(); - - /// Converts this error tracking configuration to a platform-channel map. - /// - /// Returns values consumed by the Android, Apple, and Dart exception capture - /// implementations. - Map toMap() { - return { - 'inAppIncludes': inAppIncludes, - 'inAppExcludes': inAppExcludes, - 'inAppByDefault': inAppByDefault, - 'captureFlutterErrors': captureFlutterErrors, - 'captureSilentFlutterErrors': captureSilentFlutterErrors, - 'capturePlatformDispatcherErrors': capturePlatformDispatcherErrors, - 'captureNativeExceptions': captureNativeExceptions, - 'captureNativeCrashes': captureNativeCrashes, - 'captureIsolateErrors': captureIsolateErrors, - 'exceptionSteps': exceptionSteps.toMap(), - }; - } } /// Configuration for exception steps. @@ -1211,12 +1066,4 @@ class PostHogExceptionStepsConfig { /// until the total fits. A single step larger than the budget is rejected /// outright. Defaults to `32768` (32 KiB). var maxBytes = 32768; - - /// Converts this configuration to a platform-channel map. - Map toMap() { - return { - 'enabled': enabled, - 'maxBytes': maxBytes, - }; - } } diff --git a/posthog_flutter/lib/src/posthog_flutter_io.dart b/posthog_flutter/lib/src/posthog_flutter_io.dart index 2bf87a96..bf923708 100644 --- a/posthog_flutter/lib/src/posthog_flutter_io.dart +++ b/posthog_flutter/lib/src/posthog_flutter_io.dart @@ -12,6 +12,7 @@ import 'surveys/models/survey_callbacks.dart'; import 'error_tracking/dart_exception_processor.dart'; import 'utils/before_send.dart'; import 'utils/capture_utils.dart'; +import 'utils/channel_serialization.dart'; import 'utils/flutter_version.dart'; import 'utils/property_normalizer.dart'; @@ -699,7 +700,7 @@ class PosthogFlutterIO extends PosthogFlutterPlatformInterface { }); // Native returns: { key, enabled, variant, payload } - return PostHogFeatureFlagResult.fromMap(result, key); + return featureFlagResultFromMap(result, key); } on PlatformException catch (exception) { printIfDebug('Exception on getFeatureFlagResult: $exception'); return null; diff --git a/posthog_flutter/lib/src/utils/channel_serialization.dart b/posthog_flutter/lib/src/utils/channel_serialization.dart new file mode 100644 index 00000000..25e770c4 --- /dev/null +++ b/posthog_flutter/lib/src/utils/channel_serialization.dart @@ -0,0 +1,171 @@ +import '../feature_flag_result.dart'; +import '../posthog_config.dart'; +import '../util/logging.dart'; + +extension PostHogConfigSerialization on PostHogConfig { + Map toMap() { + return { + 'projectToken': projectToken, + 'host': host, + 'flushAt': flushAt, + 'maxQueueSize': maxQueueSize, + 'maxBatchSize': maxBatchSize, + 'flushInterval': flushInterval.inSeconds, + 'sendFeatureFlagEvents': sendFeatureFlagEvent, + 'preloadFeatureFlags': preloadFeatureFlags, + 'captureApplicationLifecycleEvents': captureApplicationLifecycleEvents, + 'rageClickConfig': rageClickConfig.toMap(), + 'debug': debug, + 'optOut': optOut, + 'surveys': surveys, + 'personProfiles': personProfiles.name, + 'compression': compression.name, + 'sessionReplay': sessionReplay, + 'dataMode': dataMode.name, + 'sessionReplayConfig': sessionReplayConfig.toMap(), + 'errorTrackingConfig': errorTrackingConfig.toMap(), + 'logs': logsConfig.toMap(), + 'capturePushNotificationSubscriptions': + capturePushNotificationSubscriptions, + 'capturePushNotificationOpened': capturePushNotificationOpened, + // A closure can't cross the channel. This tells native whether to install + // a bridging provider at all — installing one the host didn't ask for + // would change how the native SDK handles a 401 on the subscription call. + 'pushIdentityProviderEnabled': pushIdentityProvider != null, + if (bootstrap != null) 'bootstrap': bootstrap!.toMap(), + }; + } +} + +extension PostHogBootstrapConfigSerialization on PostHogBootstrapConfig { + /// Only the dimensions that were set are included; [isIdentifiedId] is always + /// sent so the native SDK doesn't have to infer it. + Map toMap() { + final flags = featureFlags; + if (flags != null) { + for (final entry in flags.entries) { + // Only bool/String are served (see [featureFlags]); the native SDKs drop + // anything else silently, so warn instead of leaving no trace. + if (entry.value is! bool && entry.value is! String) { + printIfDebug( + '[PostHog] bootstrap featureFlags["${entry.key}"] is ' + '${entry.value.runtimeType}; only bool and String values are served, ' + 'so this entry will be ignored.', + ); + } + } + } + return { + if (distinctId != null) 'distinctId': distinctId, + 'isIdentifiedId': isIdentifiedId, + if (featureFlags != null) 'featureFlags': featureFlags, + if (featureFlagPayloads != null) + 'featureFlagPayloads': featureFlagPayloads, + }; + } +} + +extension PostHogLogsConfigSerialization on PostHogLogsConfig { + /// Only fields the user set are included, so unset fields keep the native + /// default. [beforeSend] is intentionally omitted: it runs in Dart and never + /// crosses the platform channel. + Map toMap() { + return { + if (serviceName != null) 'serviceName': serviceName, + if (serviceVersion != null) 'serviceVersion': serviceVersion, + if (environment != null) 'environment': environment, + if (resourceAttributes.isNotEmpty) + 'resourceAttributes': resourceAttributes, + if (flushInterval != null) + 'flushIntervalSeconds': _wholeSeconds(flushInterval!), + if (flushAt != null) 'flushAt': flushAt, + if (maxBatchSize != null) 'maxBatchSize': maxBatchSize, + if (maxBufferSize != null) 'maxBufferSize': maxBufferSize, + if (rateCapMaxLogs != null) 'rateCapMaxLogs': rateCapMaxLogs, + if (rateCapWindow != null) + 'rateCapWindowSeconds': _wholeSeconds(rateCapWindow!), + }; + } + + /// The native flush interval and rate-cap window are whole seconds. A + /// sub-second [Duration] truncates to `0`, which the native SDK treats as + /// "disabled" (rate cap) or continuous flushing — surprising for a caller who + /// set, say, 500ms. Floor at 1s, the smallest value the native API can honor. + static int _wholeSeconds(Duration duration) => + duration.inSeconds < 1 ? 1 : duration.inSeconds; +} + +extension PostHogRageClickConfigSerialization on PostHogRageClickConfig { + Map toMap() { + return { + 'enabled': enabled, + 'thresholdPoints': thresholdPoints, + 'timeoutInterval': + timeoutInterval.inMicroseconds / Duration.microsecondsPerSecond, + 'minimumTapCount': minimumTapCount, + }; + } +} + +extension PostHogSessionReplayConfigSerialization + on PostHogSessionReplayConfig { + Map toMap() { + return { + 'captureTouches': captureTouches, + 'maskAllImages': maskAllImages, + 'maskAllTexts': maskAllTexts, + 'throttleDelayMs': throttleDelay.inMilliseconds, + 'maskAllPlatformViews': maskAllPlatformViews, + 'captureNativeScreens': captureNativeScreens, + 'verifyScreenshotMaskAlignment': verifyScreenshotMaskAlignment, + 'screenshotScale': screenshotScale, + 'screenshotCompressionQuality': screenshotCompressionQuality, + 'screenshotColorMode': screenshotColorMode.name, + if (sampleRate != null) 'sampleRate': sampleRate, + }; + } +} + +extension PostHogErrorTrackingConfigSerialization + on PostHogErrorTrackingConfig { + Map toMap() { + return { + 'inAppIncludes': inAppIncludes, + 'inAppExcludes': inAppExcludes, + 'inAppByDefault': inAppByDefault, + 'captureFlutterErrors': captureFlutterErrors, + 'captureSilentFlutterErrors': captureSilentFlutterErrors, + 'capturePlatformDispatcherErrors': capturePlatformDispatcherErrors, + 'captureNativeExceptions': captureNativeExceptions, + 'captureNativeCrashes': captureNativeCrashes, + 'captureIsolateErrors': captureIsolateErrors, + 'exceptionSteps': exceptionSteps.toMap(), + }; + } +} + +extension PostHogExceptionStepsConfigSerialization + on PostHogExceptionStepsConfig { + Map toMap() { + return { + 'enabled': enabled, + 'maxBytes': maxBytes, + }; + } +} + +/// Returns `null` if [result] is not a [Map]. Falls back to [fallbackKey] when +/// the map has no `key`. +PostHogFeatureFlagResult? featureFlagResultFromMap( + Object? result, + String fallbackKey, +) { + if (result is! Map) return null; + + return PostHogFeatureFlagResult( + key: result['key'] as String? ?? fallbackKey, + enabled: result['enabled'] as bool? ?? false, + variant: result['variant'] as String?, + payload: result['payload'], + ); +} diff --git a/posthog_flutter/test/posthog_logs_test.dart b/posthog_flutter/test/posthog_logs_test.dart index 8d0d46f3..624822a8 100644 --- a/posthog_flutter/test/posthog_logs_test.dart +++ b/posthog_flutter/test/posthog_logs_test.dart @@ -1,6 +1,7 @@ import 'package:flutter_test/flutter_test.dart'; import 'package:posthog_flutter/posthog_flutter.dart'; import 'package:posthog_flutter/src/posthog_flutter_platform_interface.dart'; +import 'package:posthog_flutter/src/utils/channel_serialization.dart'; import 'posthog_flutter_platform_interface_fake.dart'; diff --git a/posthog_flutter/test/posthog_test.dart b/posthog_flutter/test/posthog_test.dart index 59874c98..2c229270 100644 --- a/posthog_flutter/test/posthog_test.dart +++ b/posthog_flutter/test/posthog_test.dart @@ -7,6 +7,7 @@ import 'package:posthog_flutter/src/posthog_flutter_platform_interface.dart'; import 'package:posthog_flutter/src/posthog_internal_events.dart'; import 'package:posthog_flutter/src/replay/mask/posthog_mask_controller.dart'; import 'package:posthog_flutter/src/replay/screenshot/screenshot_capturer.dart'; +import 'package:posthog_flutter/src/utils/channel_serialization.dart'; import 'posthog_flutter_platform_interface_fake.dart'; @@ -513,12 +514,12 @@ void main() { }); test('fromMap returns null for null input', () { - final result = PostHogFeatureFlagResult.fromMap(null, 'fallback'); + final result = featureFlagResultFromMap(null, 'fallback'); expect(result, isNull); }); test('fromMap returns null for non-Map input', () { - final result = PostHogFeatureFlagResult.fromMap('not a map', 'fallback'); + final result = featureFlagResultFromMap('not a map', 'fallback'); expect(result, isNull); }); @@ -530,7 +531,7 @@ void main() { 'payload': {'data': 123}, }; - final result = PostHogFeatureFlagResult.fromMap(map, 'fallback'); + final result = featureFlagResultFromMap(map, 'fallback'); expect(result, isNotNull); expect(result!.key, equals('my-flag')); @@ -542,7 +543,7 @@ void main() { test('fromMap uses fallback key when map key is null', () { final map = {'enabled': true, 'variant': null, 'payload': null}; - final result = PostHogFeatureFlagResult.fromMap(map, 'fallback-key'); + final result = featureFlagResultFromMap(map, 'fallback-key'); expect(result, isNotNull); expect(result!.key, equals('fallback-key')); @@ -551,7 +552,7 @@ void main() { test('fromMap defaults enabled to false when not in map', () { final map = {'key': 'my-flag'}; - final result = PostHogFeatureFlagResult.fromMap(map, 'fallback'); + final result = featureFlagResultFromMap(map, 'fallback'); expect(result, isNotNull); expect(result!.enabled, isFalse); diff --git a/posthog_flutter/test/replay_capture_touches_test.dart b/posthog_flutter/test/replay_capture_touches_test.dart index 485c5cb2..1a4f9d1d 100644 --- a/posthog_flutter/test/replay_capture_touches_test.dart +++ b/posthog_flutter/test/replay_capture_touches_test.dart @@ -4,6 +4,7 @@ import 'package:posthog_flutter/posthog_flutter.dart'; import 'package:posthog_flutter/src/posthog_flutter_io.dart'; import 'package:posthog_flutter/src/posthog_flutter_platform_interface.dart'; import 'package:posthog_flutter/src/posthog_internal_events.dart'; +import 'package:posthog_flutter/src/utils/channel_serialization.dart'; void main() { TestWidgetsFlutterBinding.ensureInitialized(); diff --git a/posthog_flutter/test/replay_screenshot_config_test.dart b/posthog_flutter/test/replay_screenshot_config_test.dart index edc745a2..d562fd4f 100644 --- a/posthog_flutter/test/replay_screenshot_config_test.dart +++ b/posthog_flutter/test/replay_screenshot_config_test.dart @@ -1,5 +1,6 @@ import 'package:flutter_test/flutter_test.dart'; import 'package:posthog_flutter/posthog_flutter.dart'; +import 'package:posthog_flutter/src/utils/channel_serialization.dart'; void main() { test('screenshot controls preserve native defaults', () { From a700edbe55e36e65c18420ed689e6561cc5ee4e1 Mon Sep 17 00:00:00 2001 From: Anna Garcia Date: Wed, 7 Oct 2026 16:04:08 -0400 Subject: [PATCH 7/7] chore!: require iOS 15 and macOS 11 Raises the deployment targets to the posthog-ios 4.0 minimums ahead of the SDK bump, so the bump itself only changes the dependency range. Drops the availability checks that are now always true and moves the CodeQL Swift job to Xcode 26. Co-Authored-By: Claude Opus 5.5 (1M context) --- .changeset/v6-remove-deprecated-apis.md | 1 + .github/workflows/codeql.yml | 4 ++-- example/ios/Podfile | 2 +- example/ios/Podfile.lock | 2 +- example/ios/Runner.xcodeproj/project.pbxproj | 18 +++++++++--------- example/macos/Podfile | 2 +- example/macos/Podfile.lock | 2 +- example/macos/Runner.xcodeproj/project.pbxproj | 6 +++--- posthog_flutter/darwin/posthog_flutter.podspec | 6 ++---- .../darwin/posthog_flutter/Package.swift | 4 ++-- .../posthog_flutter/PosthogFlutterPlugin.swift | 16 ++++++---------- 11 files changed, 29 insertions(+), 34 deletions(-) diff --git a/.changeset/v6-remove-deprecated-apis.md b/.changeset/v6-remove-deprecated-apis.md index 52ef0668..566af215 100644 --- a/.changeset/v6-remove-deprecated-apis.md +++ b/.changeset/v6-remove-deprecated-apis.md @@ -2,6 +2,7 @@ "posthog_flutter": major --- +- **Breaking:** bump minimum iOS deployment target from 13.0 to 15.0 and macOS from 10.15 to 11.0 - **Breaking:** remove `PostHogConfig.apiKey` and the `com.posthog.posthog.API_KEY` manifest/Info.plist key — use `projectToken` and `com.posthog.posthog.PROJECT_TOKEN` - **Breaking:** remove `Posthog().getFeatureFlagPayload()` — use `getFeatureFlagResult(key, sendFeatureFlagEvent: false)` and read `payload` - **Breaking:** remove the `PostHogSessionReplayConfig.debouncerDelay` setter — use `PostHogSessionReplayConfig.throttleDelay` diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index f88a2503..84257df9 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -24,7 +24,7 @@ jobs: runner: ubuntu-latest - language: swift build-mode: manual - runner: macos-15-xlarge + runner: macos-26 - language: actions build-mode: none runner: ubuntu-latest @@ -45,7 +45,7 @@ jobs: if: matrix.language == 'swift' uses: maxim-lobanov/setup-xcode@ed7a3b1fda3918c0306d1b724322adc0b8cc0a90 # v1.7.0 with: - xcode-version: '16.4' + xcode-version: '26.4' - name: Install dependencies (Swift) if: matrix.language == 'swift' diff --git a/example/ios/Podfile b/example/ios/Podfile index 266a1cd0..e20ea2b7 100644 --- a/example/ios/Podfile +++ b/example/ios/Podfile @@ -1,5 +1,5 @@ # Uncomment this line to define a global platform for your project -platform :ios, '14.0' +platform :ios, '15.0' # CocoaPods analytics sends network stats synchronously affecting flutter build latency. ENV['COCOAPODS_DISABLE_STATS'] = 'true' diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock index 6356c2c8..70f8356f 100644 --- a/example/ios/Podfile.lock +++ b/example/ios/Podfile.lock @@ -33,6 +33,6 @@ SPEC CHECKSUMS: google_maps_flutter_ios: 17552876e72723da1d41accc22f03b5f7afbde69 GoogleMaps: 8939898920281c649150e0af74aa291c60f2e77d -PODFILE CHECKSUM: 3c864ae2f1db9f17d3418f22aa4b78eac050c10b +PODFILE CHECKSUM: 583e7c5826ead1663c2849ec27bee3d398ceebac COCOAPODS: 1.16.2 diff --git a/example/ios/Runner.xcodeproj/project.pbxproj b/example/ios/Runner.xcodeproj/project.pbxproj index b6975b16..535d541f 100644 --- a/example/ios/Runner.xcodeproj/project.pbxproj +++ b/example/ios/Runner.xcodeproj/project.pbxproj @@ -478,7 +478,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 14.0; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SUPPORTED_PLATFORMS = iphoneos; @@ -497,7 +497,7 @@ DEVELOPMENT_TEAM = PNC2XCH2XP; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 14.0; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -518,7 +518,7 @@ CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; GENERATE_INFOPLIST_FILE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 14.0; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; MARKETING_VERSION = 1.0; PRODUCT_BUNDLE_IDENTIFIER = com.example.posthogFlutterExample.RunnerTests; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -537,7 +537,7 @@ CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; GENERATE_INFOPLIST_FILE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 14.0; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; MARKETING_VERSION = 1.0; PRODUCT_BUNDLE_IDENTIFIER = com.example.posthogFlutterExample.RunnerTests; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -554,7 +554,7 @@ CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; GENERATE_INFOPLIST_FILE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 14.0; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; MARKETING_VERSION = 1.0; PRODUCT_BUNDLE_IDENTIFIER = com.example.posthogFlutterExample.RunnerTests; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -610,7 +610,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 14.0; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; @@ -659,7 +659,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 14.0; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SUPPORTED_PLATFORMS = iphoneos; @@ -680,7 +680,7 @@ DEVELOPMENT_TEAM = PNC2XCH2XP; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 14.0; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -704,7 +704,7 @@ DEVELOPMENT_TEAM = PNC2XCH2XP; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 14.0; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", diff --git a/example/macos/Podfile b/example/macos/Podfile index b52666a1..dbccf89c 100644 --- a/example/macos/Podfile +++ b/example/macos/Podfile @@ -1,4 +1,4 @@ -platform :osx, '10.15' +platform :osx, '11.0' # CocoaPods analytics sends network stats synchronously affecting flutter build latency. ENV['COCOAPODS_DISABLE_STATS'] = 'true' diff --git a/example/macos/Podfile.lock b/example/macos/Podfile.lock index 9d359e12..36151c7c 100644 --- a/example/macos/Podfile.lock +++ b/example/macos/Podfile.lock @@ -11,6 +11,6 @@ EXTERNAL SOURCES: SPEC CHECKSUMS: FlutterMacOS: d0db08ddef1a9af05a5ec4b724367152bb0500b1 -PODFILE CHECKSUM: 9ebaf0ce3d369aaa26a9ea0e159195ed94724cf3 +PODFILE CHECKSUM: c2e95c8c0fe03c5c57e438583cae4cc732296009 COCOAPODS: 1.16.2 diff --git a/example/macos/Runner.xcodeproj/project.pbxproj b/example/macos/Runner.xcodeproj/project.pbxproj index f6c36aa8..c0dda7a1 100644 --- a/example/macos/Runner.xcodeproj/project.pbxproj +++ b/example/macos/Runner.xcodeproj/project.pbxproj @@ -549,7 +549,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.15; + MACOSX_DEPLOYMENT_TARGET = 11.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = macosx; SWIFT_COMPILATION_MODE = wholemodule; @@ -628,7 +628,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.15; + MACOSX_DEPLOYMENT_TARGET = 11.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = macosx; @@ -675,7 +675,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.15; + MACOSX_DEPLOYMENT_TARGET = 11.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = macosx; SWIFT_COMPILATION_MODE = wholemodule; diff --git a/posthog_flutter/darwin/posthog_flutter.podspec b/posthog_flutter/darwin/posthog_flutter.podspec index c39b30b2..98e3a7cf 100644 --- a/posthog_flutter/darwin/posthog_flutter.podspec +++ b/posthog_flutter/darwin/posthog_flutter.podspec @@ -21,12 +21,10 @@ Postog flutter plugin s.ios.dependency 'Flutter' s.osx.dependency 'FlutterMacOS' - # ~> Version 3.80.0 up to, but not including, 4.0.0 s.dependency 'PostHog', '>= 3.84.0', '< 4.0.0' - s.ios.deployment_target = '13.0' - # PH iOS SDK 3.0.0 requires >= 10.15 - s.osx.deployment_target = '10.15' + s.ios.deployment_target = '15.0' + s.osx.deployment_target = '11.0' # Flutter.framework does not contain a i386 slice. s.ios.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES', 'EXCLUDED_ARCHS[sdk=iphonesimulator*]' => 'i386' } diff --git a/posthog_flutter/darwin/posthog_flutter/Package.swift b/posthog_flutter/darwin/posthog_flutter/Package.swift index dd9a201d..1cf4470c 100644 --- a/posthog_flutter/darwin/posthog_flutter/Package.swift +++ b/posthog_flutter/darwin/posthog_flutter/Package.swift @@ -6,8 +6,8 @@ import PackageDescription let package = Package( name: "posthog_flutter", platforms: [ - .iOS("13.0"), - .macOS("10.15"), + .iOS("15.0"), + .macOS("11.0"), ], products: [ .library(name: "posthog-flutter", targets: ["posthog_flutter"]), 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 6054770d..a69380be 100644 --- a/posthog_flutter/darwin/posthog_flutter/Sources/posthog_flutter/PosthogFlutterPlugin.swift +++ b/posthog_flutter/darwin/posthog_flutter/Sources/posthog_flutter/PosthogFlutterPlugin.swift @@ -104,9 +104,7 @@ public class PosthogFlutterPlugin: NSObject, FlutterPlugin { /// a later `FlutterEngine` registers — that setup() has already run, so use the plist key there. private static func prewarmPushNotificationOpenCapture() { guard plistCapturePushNotificationOpened else { return } - if #available(iOS 14.0, macOS 11.0, *) { - PostHogSDK.prewarmPushNotificationOpenCapture() - } + PostHogSDK.prewarmPushNotificationOpenCapture() } private static var plistCapturePushNotificationOpened: Bool { @@ -280,13 +278,11 @@ public class PosthogFlutterPlugin: NSObject, FlutterPlugin { } // configure surveys - if #available(iOS 15.0, *) { - let surveys: Bool = posthogConfig["surveys"] as? Bool ?? false - config.surveys = surveys - if surveys { - // if surveys are enabled, assign this instance as the survey delegate (we'll take over rendering) - config.surveysConfig.surveysDelegate = instance - } + let surveys: Bool = posthogConfig["surveys"] as? Bool ?? false + config.surveys = surveys + if surveys { + // if surveys are enabled, assign this instance as the survey delegate (we'll take over rendering) + config.surveysConfig.surveysDelegate = instance } #endif