diff --git a/packages/mixpanel_flutter/android/src/main/java/com/mixpanel/mixpanel_flutter/MixpanelFlutterPlugin.java b/packages/mixpanel_flutter/android/src/main/java/com/mixpanel/mixpanel_flutter/MixpanelFlutterPlugin.java index b0993a0..6fca356 100644 --- a/packages/mixpanel_flutter/android/src/main/java/com/mixpanel/mixpanel_flutter/MixpanelFlutterPlugin.java +++ b/packages/mixpanel_flutter/android/src/main/java/com/mixpanel/mixpanel_flutter/MixpanelFlutterPlugin.java @@ -264,6 +264,7 @@ private void handleInitialize(MethodCall call, Result result) { Boolean featureFlagsEnabled = null; JSONObject featureFlagsContext = null; VariantLookupPolicy variantLookupPolicy = null; + Boolean prefetchFlags = null; if (featureFlagsMap != null) { Object enabledValue = featureFlagsMap.get("enabled"); if (enabledValue instanceof Boolean) { @@ -285,6 +286,10 @@ private void handleInitialize(MethodCall call, Result result) { Map policyMap = (Map) policyValue; variantLookupPolicy = parseVariantLookupPolicy(policyMap); } + Object prefetchValue = featureFlagsMap.get("prefetchFlags"); + if (prefetchValue instanceof Boolean) { + prefetchFlags = (Boolean) prefetchValue; + } } // Build MixpanelOptions with feature flags configuration @@ -304,6 +309,9 @@ private void handleInitialize(MethodCall call, Result result) { if (variantLookupPolicy != null) { ffBuilder.variantLookupPolicy(variantLookupPolicy); } + if (prefetchFlags != null) { + ffBuilder.prefetchFlags(prefetchFlags); + } optionsBuilder.featureFlagOptions(ffBuilder.build()); } diff --git a/packages/mixpanel_flutter/lib/mixpanel_flutter.dart b/packages/mixpanel_flutter/lib/mixpanel_flutter.dart index 1677f23..38b9777 100644 --- a/packages/mixpanel_flutter/lib/mixpanel_flutter.dart +++ b/packages/mixpanel_flutter/lib/mixpanel_flutter.dart @@ -317,10 +317,22 @@ class FeatureFlagsConfig { /// native SDK defaults and pre-persistence behavior. final VariantLookupPolicy variantLookupPolicy; + /// Whether to eagerly fetch flags during initialization. + /// When `true` (default), the SDK automatically calls `loadFlags()` during + /// initialization so flags are ready (or close to ready) when accessed. + /// When `false`, flags are fetched lazily on first access or manually via + /// `loadFlags()` or `identify()`. + /// + /// Setting this to `false` is useful when you want to defer the initial + /// fetch until after calling `identify()` to ensure flags evaluate against + /// the correct user identity. + final bool prefetchFlags; + const FeatureFlagsConfig({ this.enabled = true, this.context = const {}, this.variantLookupPolicy = const VariantLookupPolicy.networkOnly(), + this.prefetchFlags = true, }); /// Converts this config to a Map for serialization. @@ -329,6 +341,7 @@ class FeatureFlagsConfig { 'enabled': enabled, 'context': context, 'variantLookupPolicy': variantLookupPolicy.toMap(), + 'prefetchFlags': prefetchFlags, }; } } diff --git a/packages/mixpanel_flutter/lib/mixpanel_flutter_web.dart b/packages/mixpanel_flutter/lib/mixpanel_flutter_web.dart index c530a3b..f747f62 100644 --- a/packages/mixpanel_flutter/lib/mixpanel_flutter_web.dart +++ b/packages/mixpanel_flutter/lib/mixpanel_flutter_web.dart @@ -238,6 +238,9 @@ class MixpanelFlutterPlugin { if (persistence != null) { flagsConfig['persistence'] = persistence; } + // Add prefetchFlags if provided, default to true + bool prefetchFlags = featureFlags['prefetchFlags'] ?? true; + flagsConfig['prefetchFlags'] = prefetchFlags; initConfig['flags'] = flagsConfig.isEmpty ? true : flagsConfig; } } diff --git a/packages/mixpanel_flutter/swift/Classes/SwiftMixpanelFlutterPlugin.swift b/packages/mixpanel_flutter/swift/Classes/SwiftMixpanelFlutterPlugin.swift index c2f6a8c..b6cb601 100644 --- a/packages/mixpanel_flutter/swift/Classes/SwiftMixpanelFlutterPlugin.swift +++ b/packages/mixpanel_flutter/swift/Classes/SwiftMixpanelFlutterPlugin.swift @@ -264,9 +264,11 @@ public class SwiftMixpanelFlutterPlugin: NSObject, FlutterPlugin { let enabled = featureFlags["enabled"] as? Bool, enabled { let context = featureFlags["context"] as? [String: Any] ?? [:] let policy = parseVariantLookupPolicy(featureFlags["variantLookupPolicy"] as? [String: Any]) + let prefetchFlags = featureFlags["prefetchFlags"] as? Bool ?? true featureFlagOptions = FeatureFlagOptions( enabled: true, context: context, + prefetchFlags: prefetchFlags, variantLookupPolicy: policy ) } diff --git a/packages/mixpanel_flutter/test/mixpanel_flutter_test.dart b/packages/mixpanel_flutter/test/mixpanel_flutter_test.dart index 5d72a9d..587d077 100644 --- a/packages/mixpanel_flutter/test/mixpanel_flutter_test.dart +++ b/packages/mixpanel_flutter/test/mixpanel_flutter_test.dart @@ -1260,6 +1260,7 @@ void main() { 'enabled': true, 'context': {'user_tier': 'premium'}, 'variantLookupPolicy': {'policy': 'networkOnly'}, + 'prefetchFlags': true, }, }, ), @@ -1291,6 +1292,7 @@ void main() { 'enabled': true, 'context': {}, 'variantLookupPolicy': {'policy': 'networkOnly'}, + 'prefetchFlags': true, }, }, ), @@ -1325,6 +1327,7 @@ void main() { 'enabled': false, 'context': {'user_tier': 'premium'}, 'variantLookupPolicy': {'policy': 'networkOnly'}, + 'prefetchFlags': true, }, }, ), @@ -1373,6 +1376,7 @@ void main() { expect(map['enabled'], true); expect(map['context'], {'key': 'value'}); expect(map['variantLookupPolicy'], {'policy': 'networkOnly'}); + expect(map['prefetchFlags'], true); }); test('FeatureFlagsConfig default values', () { @@ -1380,11 +1384,48 @@ void main() { expect(config.enabled, true); expect(config.context, {}); expect(config.variantLookupPolicy, isA()); + expect(config.prefetchFlags, true); final map = config.toMap(); expect(map['enabled'], true); expect(map['context'], {}); expect(map['variantLookupPolicy'], {'policy': 'networkOnly'}); + expect(map['prefetchFlags'], true); + }); + + test('FeatureFlagsConfig with prefetchFlags false', () async { + _mixpanel = await Mixpanel.init( + "test token", + optOutTrackingDefault: false, + trackAutomaticEvents: true, + featureFlags: FeatureFlagsConfig( + enabled: true, + prefetchFlags: false, + ), + ); + expect( + methodCall, + isMethodCall( + 'initialize', + arguments: { + 'token': "test token", + 'optOutTrackingDefault': false, + 'trackAutomaticEvents': true, + 'mixpanelProperties': { + '\$lib_version': sdkVersion, + 'mp_lib': 'flutter', + }, + 'superProperties': null, + 'config': null, + 'featureFlags': { + 'enabled': true, + 'context': {}, + 'variantLookupPolicy': {'policy': 'networkOnly'}, + 'prefetchFlags': false, + }, + }, + ), + ); }); test(