Skip to content
Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -285,6 +286,10 @@ private void handleInitialize(MethodCall call, Result result) {
Map<String, Object> policyMap = (Map<String, Object>) policyValue;
variantLookupPolicy = parseVariantLookupPolicy(policyMap);
}
Object prefetchValue = featureFlagsMap.get("prefetchFlags");
if (prefetchValue instanceof Boolean) {
prefetchFlags = (Boolean) prefetchValue;
}
}

// Build MixpanelOptions with feature flags configuration
Expand All @@ -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());
}

Expand Down
13 changes: 13 additions & 0 deletions packages/mixpanel_flutter/lib/mixpanel_flutter.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -329,6 +341,7 @@ class FeatureFlagsConfig {
'enabled': enabled,
'context': context,
'variantLookupPolicy': variantLookupPolicy.toMap(),
'prefetchFlags': prefetchFlags,
};
}
}
Expand Down
3 changes: 3 additions & 0 deletions packages/mixpanel_flutter/lib/mixpanel_flutter_web.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
)
}
Expand Down
41 changes: 41 additions & 0 deletions packages/mixpanel_flutter/test/mixpanel_flutter_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -1260,6 +1260,7 @@ void main() {
'enabled': true,
'context': {'user_tier': 'premium'},
'variantLookupPolicy': {'policy': 'networkOnly'},
'prefetchFlags': true,
},
},
),
Expand Down Expand Up @@ -1291,6 +1292,7 @@ void main() {
'enabled': true,
'context': <String, dynamic>{},
'variantLookupPolicy': {'policy': 'networkOnly'},
'prefetchFlags': true,
},
},
),
Expand Down Expand Up @@ -1325,6 +1327,7 @@ void main() {
'enabled': false,
'context': {'user_tier': 'premium'},
'variantLookupPolicy': {'policy': 'networkOnly'},
'prefetchFlags': true,
},
},
),
Expand Down Expand Up @@ -1373,18 +1376,56 @@ void main() {
expect(map['enabled'], true);
expect(map['context'], {'key': 'value'});
expect(map['variantLookupPolicy'], {'policy': 'networkOnly'});
expect(map['prefetchFlags'], true);
});

test('FeatureFlagsConfig default values', () {
final config = FeatureFlagsConfig();
expect(config.enabled, true);
expect(config.context, <String, dynamic>{});
expect(config.variantLookupPolicy, isA<NetworkOnlyPolicy>());
expect(config.prefetchFlags, true);

final map = config.toMap();
expect(map['enabled'], true);
expect(map['context'], <String, dynamic>{});
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: <String, dynamic>{
'token': "test token",
'optOutTrackingDefault': false,
'trackAutomaticEvents': true,
'mixpanelProperties': {
'\$lib_version': sdkVersion,
'mp_lib': 'flutter',
},
'superProperties': null,
'config': null,
'featureFlags': {
'enabled': true,
'context': <String, dynamic>{},
'variantLookupPolicy': {'policy': 'networkOnly'},
'prefetchFlags': false,
},
},
),
);
});

test(
Expand Down
Loading