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 82afcf8e..f14436d4 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 @@ -239,6 +239,7 @@ private void handleInitialize(MethodCall call, Result result) { Boolean optOutTrackingDefault = call.argument("optOutTrackingDefault"); Boolean trackAutomaticEvents = call.argument("trackAutomaticEvents"); + String serverURL = call.argument("serverURL"); // Parse feature flags config if provided Map featureFlagsMap = call.>argument("featureFlags"); @@ -273,6 +274,10 @@ private void handleInitialize(MethodCall call, Result result) { .optOutTrackingDefault(optOutTrackingDefault == null ? false : optOutTrackingDefault) .superProperties(superAndMixpanelProperties); + if (serverURL != null && !serverURL.isEmpty()) { + optionsBuilder.serverURL(serverURL); + } + if (featureFlagsEnabled != null && featureFlagsEnabled) { FeatureFlagOptions.Builder ffBuilder = new FeatureFlagOptions.Builder().enabled(true); if (featureFlagsContext != null) { diff --git a/packages/mixpanel_flutter/lib/mixpanel_flutter.dart b/packages/mixpanel_flutter/lib/mixpanel_flutter.dart index 1f51e73e..1a38f8a4 100644 --- a/packages/mixpanel_flutter/lib/mixpanel_flutter.dart +++ b/packages/mixpanel_flutter/lib/mixpanel_flutter.dart @@ -364,13 +364,17 @@ class Mixpanel { /// * [superProperties] Optional super properties to register /// * [config] Optional A dictionary of config options to override (WEB ONLY) /// * [featureFlags] Optional Feature flags configuration + /// * [serverURL] Optional base URL used for Mixpanel API requests. Useful if you + /// need to proxy Mixpanel requests, or to route data to Mixpanel's EU servers + /// (`https://api-eu.mixpanel.com`). Defaults to `https://api.mixpanel.com`. /// static Future init(String token, {bool optOutTrackingDefault = false, required bool trackAutomaticEvents, Map? superProperties, Map? config, - FeatureFlagsConfig? featureFlags}) async { + FeatureFlagsConfig? featureFlags, + String? serverURL}) async { var allProperties = {'token': token}; allProperties['optOutTrackingDefault'] = optOutTrackingDefault; allProperties['trackAutomaticEvents'] = trackAutomaticEvents; @@ -380,6 +384,9 @@ class Mixpanel { if (featureFlags != null) { allProperties['featureFlags'] = featureFlags.toMap(); } + if (serverURL != null && _MixpanelHelper.isValidString(serverURL)) { + allProperties['serverURL'] = serverURL; + } await _channel.invokeMethod('initialize', allProperties); return Mixpanel(token); } diff --git a/packages/mixpanel_flutter/lib/mixpanel_flutter_web.dart b/packages/mixpanel_flutter/lib/mixpanel_flutter_web.dart index 24c62457..c530a3b3 100644 --- a/packages/mixpanel_flutter/lib/mixpanel_flutter_web.dart +++ b/packages/mixpanel_flutter/lib/mixpanel_flutter_web.dart @@ -218,6 +218,11 @@ class MixpanelFlutterPlugin { dynamic config = args['config']; Map initConfig = Map.from(config ?? {}); + final serverURL = args['serverURL']; + if (serverURL is String && serverURL.isNotEmpty) { + initConfig['api_host'] = serverURL; + } + // Handle feature flags configuration dynamic featureFlags = args['featureFlags']; if (featureFlags != null && featureFlags is Map) { diff --git a/packages/mixpanel_flutter/swift/Classes/SwiftMixpanelFlutterPlugin.swift b/packages/mixpanel_flutter/swift/Classes/SwiftMixpanelFlutterPlugin.swift index 76859c3c..2db58d4c 100644 --- a/packages/mixpanel_flutter/swift/Classes/SwiftMixpanelFlutterPlugin.swift +++ b/packages/mixpanel_flutter/swift/Classes/SwiftMixpanelFlutterPlugin.swift @@ -192,6 +192,7 @@ public class SwiftMixpanelFlutterPlugin: NSObject, FlutterPlugin { let superProperties = arguments["superProperties"] as? [String: Any] self.token = token let trackAutomaticEvents = arguments["trackAutomaticEvents"] as! Bool + let serverURL = (arguments["serverURL"] as? String).flatMap { $0.isEmpty ? nil : $0 } // Check for feature flags configuration var featureFlagOptions: FeatureFlagOptions? = nil @@ -213,6 +214,7 @@ public class SwiftMixpanelFlutterPlugin: NSObject, FlutterPlugin { trackAutomaticEvents: trackAutomaticEvents, optOutTrackingByDefault: optOutTrackingDefault ?? false, superProperties: MixpanelTypeHandler.mixpanelProperties(properties: superProperties, mixpanelProperties: mixpanelProperties), + serverURL: serverURL, featureFlagOptions: featureFlagOptions ) instance = Mixpanel.initialize(options: options) diff --git a/packages/mixpanel_flutter/test/mixpanel_flutter_test.dart b/packages/mixpanel_flutter/test/mixpanel_flutter_test.dart index 7b202ed5..5d72a9dd 100644 --- a/packages/mixpanel_flutter/test/mixpanel_flutter_test.dart +++ b/packages/mixpanel_flutter/test/mixpanel_flutter_test.dart @@ -97,6 +97,85 @@ void main() { }); + test('check initialize with serverURL forwards to native', () async { + _mixpanel = await Mixpanel.init( + "test token", + optOutTrackingDefault: false, + trackAutomaticEvents: true, + serverURL: 'https://api-eu.mixpanel.com', + ); + expect( + methodCall, + isMethodCall( + 'initialize', + arguments: { + 'token': "test token", + 'optOutTrackingDefault': false, + 'trackAutomaticEvents': true, + 'mixpanelProperties': { + '\$lib_version': sdkVersion, + 'mp_lib': 'flutter', + }, + 'superProperties': null, + 'config': null, + 'serverURL': 'https://api-eu.mixpanel.com', + }, + ), + ); + }); + + test('check initialize omits serverURL when blank', () async { + _mixpanel = await Mixpanel.init( + "test token", + optOutTrackingDefault: false, + trackAutomaticEvents: true, + serverURL: '', + ); + expect( + methodCall, + isMethodCall( + 'initialize', + arguments: { + 'token': "test token", + 'optOutTrackingDefault': false, + 'trackAutomaticEvents': true, + 'mixpanelProperties': { + '\$lib_version': sdkVersion, + 'mp_lib': 'flutter', + }, + 'superProperties': null, + 'config': null, + }, + ), + ); + }); + + test('check initialize omits serverURL when null', () async { + _mixpanel = await Mixpanel.init( + "test token", + optOutTrackingDefault: false, + trackAutomaticEvents: true, + serverURL: null, + ); + expect( + methodCall, + isMethodCall( + 'initialize', + arguments: { + 'token': "test token", + 'optOutTrackingDefault': false, + 'trackAutomaticEvents': true, + 'mixpanelProperties': { + '\$lib_version': sdkVersion, + 'mp_lib': 'flutter', + }, + 'superProperties': null, + 'config': null, + }, + ), + ); + }); + test('check setServerURL', () async { _mixpanel.setServerURL("https://api-eu.mixpanel.com"); expect(