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

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions MIGRATING.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,6 @@ await MparticleFlutterSdk.getInstance().then((mp) => mp?.rokt.selectShoppableAds
- **Android**: the method is exposed for API parity but is a no-op (logs a warning).
- **Web**: not implemented — calls will throw `MissingPluginException`.

Events for a shoppable ads placement are delivered on the existing `MPRoktEvents` `EventChannel` once `selectShoppableAds` has been called.
Rokt event delivery now uses explicit subscription by identifier through `Rokt.events(...)`. Call `events(identifier, ...)` before `selectPlacements(...)` or `selectShoppableAds(...)` for that identifier.

The Rokt Apple Pay payment extension (for example `RoktStripePaymentExtension`) is **not** proxied through Dart. Integrators must register it directly from native Swift/Objective-C in the host app (for example `ios/Runner/AppDelegate.swift`), after `MParticle.sharedInstance().start(with:)`. See the [Apple SDK Rokt integration section](https://github.com/mParticle/mparticle-apple-sdk/blob/main/README.md#rokt-integration) for the exact snippet.
The Rokt payment extension (for example `RoktPaymentExtension`) is **not** proxied through Dart. Integrators must add the pod and register it directly from native Swift/Objective-C in the host app (for example `ios/Runner/AppDelegate.swift`), after `MParticle.sharedInstance().start(with:)`.
54 changes: 53 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ To install mParticle on an iOS platform:
2. Install the SDK using CocoaPods:

```bash
$ # Update your Podfile to depend on 'mParticle-Apple-SDK' version 8.5.0 or later
$ # Update your Podfile to depend on 'mParticle-Apple-SDK' version 9.1.0 or later
$ pod install
```

Expand Down Expand Up @@ -256,6 +256,58 @@ You must first call `getInstance` on `MparticleFlutterSdk` before each method is
MparticleFlutterSdk? mpInstance = await MparticleFlutterSdk.getInstance();
```

### Rokt

`Rokt` is exposed under `mpInstance?.rokt` and supports:

- `events(String identifier, void Function(dynamic event) onEvent)`
- `selectPlacements(...)`
- `selectShoppableAds(...)` (iOS implementation; Android no-op for parity; web unsupported)
- `purchaseFinalized(...)` (iOS)

Subscribe to events for a placement identifier before selecting placements:

```dart
mpInstance?.rokt.events('MSDKEmbeddedLayout', (event) {
print('Rokt event: $event');
});

await mpInstance?.rokt.selectPlacements(
identifier: 'MSDKEmbeddedLayout',
attributes: {'email': 'user@example.com'},
);
```

For iOS shoppable ads:

```dart
mpInstance?.rokt.events('StgRoktShoppableAds', (event) {
print('Rokt shoppable event: $event');
});

await mpInstance?.rokt.selectShoppableAds(
identifier: 'StgRoktShoppableAds',
attributes: {'email': 'user@example.com'},
);
```

To enable iOS payment flows for shoppable ads, add the payment extension pod in your app `ios/Podfile` and register it natively after `MParticle.sharedInstance().start(with:)`:

```ruby
pod 'RoktPaymentExtension'
```

```swift
import RoktPaymentExtension

if let paymentExtension = RoktPaymentExtension(
applePayMerchantId: "merchant.com.example.app",
urlScheme: nil
) {
MParticle.sharedInstance().rokt.registerPaymentExtension(paymentExtension)
}
```

### Custom Events

To log events, import mParticle `EventTypes` and `MPEvent` to write proper event logging calls:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,7 @@ class MparticleFlutterSdkPlugin: FlutterPlugin, MethodCallHandler, ActivityAware
setSdkVersion()
result.success(true)
}
"roktSubscribeToEvents" -> this.roktSubscribeToEvents(call, result)
"roktSelectPlacements" -> this.roktSelectPlacements(call, result)
"roktSelectShoppableAds" -> this.roktSelectShoppableAds(call, result)
"roktPurchaseFinalized" -> this.roktPurchaseFinalized(call, result)
Expand Down Expand Up @@ -756,16 +757,6 @@ class MparticleFlutterSdkPlugin: FlutterPlugin, MethodCallHandler, ActivityAware
}

MParticle.getInstance()?.let { instance ->
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
activity?.let {
roktEventHandler?.subscribeToEvents(
events = instance.Rokt().events(placementId),
activity = it,
identifier = placementId,
)
}
}

instance.Rokt().selectPlacements(placementId, stringAttributes, null, placeHolders.takeIf { it.isNotEmpty() }, customFonts, config)
result.success(true)
} ?: result.error(TAG, "No mParticle instance exists", null)
Expand All @@ -774,6 +765,27 @@ class MparticleFlutterSdkPlugin: FlutterPlugin, MethodCallHandler, ActivityAware
}
}

private fun roktSubscribeToEvents(call: MethodCall, result: Result) {
val identifier = call.argument<String>("identifier")
if (identifier.isNullOrBlank()) {
result.error(TAG, "Missing identifier", null)
return
}

MParticle.getInstance()?.let { instance ->
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
activity?.let { currentActivity ->
roktEventHandler?.subscribeToEvents(
events = instance.Rokt().events(identifier),
activity = currentActivity,
identifier = identifier,
)
}
}
result.success(true)
} ?: result.error(TAG, "No mParticle instance exists", null)
}

private fun buildRoktConfig(configMap: Map<String, Any>): RoktConfig {
val builder = RoktConfig.Builder()
(configMap["colorMode"] as? String)?.let {
Expand Down
2 changes: 1 addition & 1 deletion example/ios/Podfile
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ target 'Runner' do
use_frameworks!
use_modular_headers!

pod 'mParticle-Apple-SDK'
pod 'mParticle-Rokt'
pod 'RoktPaymentExtension'

flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
customLLDBInitFile = "$(SRCROOT)/Flutter/ephemeral/flutter_lldbinit"
shouldUseLaunchSchemeArgsEnv = "YES">
<MacroExpansion>
<BuildableReference
Expand All @@ -43,11 +44,13 @@
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
customLLDBInitFile = "$(SRCROOT)/Flutter/ephemeral/flutter_lldbinit"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
enableGPUValidationMode = "1"
allowLocationSimulation = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
Expand Down
3 changes: 3 additions & 0 deletions example/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,9 @@ class _MyAppState extends State<MyApp> {
// Platform messages are asynchronous, so we initialize in an async method.
Future<void> initMparticle() async {
mpInstance = await MparticleFlutterSdk.getInstance();
mpInstance?.rokt.events('StgRoktShoppableAds', (event) {
print("Rokt event: $event");
});
if (mpInstance != null) {
setState(() {
_isInitialized = true;
Expand Down
48 changes: 48 additions & 0 deletions example/lib/rokt_layouts_screen.dart
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,30 @@ class _RoktLayoutsScreenState extends State<RoktLayoutsScreen> {
return {};
}

Map<String, String> _getShoppableAdsAttributes() {
return {
'country': 'US',
'shippingstate': 'NY',
'shippingzipcode': '10001',
'firstname': 'Jenny',
'stripeApplePayAvailable': 'true',
'last4digits': '4444',
'shippingaddress1': '123 Main St',
'colormode': 'LIGHT',
'billingzipcode': '07762',
'paymenttype': 'ApplePay',
'shippingcountry': 'US',
'sandbox': 'true',
'shippingaddress2': 'Apt 4B',
'confirmationref': 'ORD-12345',
'shippingcity': 'New York',
'newToApplePay': 'false',
'applePayCapabilities': 'true',
'lastname': 'Smith',
'email': 'jenny.smith@example.com',
};
}

String _getPlatform() {
if (kIsWeb) {
return 'Web';
Expand Down Expand Up @@ -151,6 +175,30 @@ class _RoktLayoutsScreenState extends State<RoktLayoutsScreen> {
print('Error calling Rokt selectPlacements: $e');
}
}),
const SizedBox(height: 20),
buildButton('Select Shoppable Ads (iOS)', () async {
if (!Platform.isIOS) {
print('${_getPlatform()} SelectShoppableAds is a no-op');
return;
}

var identityRequest = MparticleFlutterSdk.identityRequest;
identityRequest.setIdentity(
identityType: IdentityType.CustomerId,
value: _getIdentityValue());

try {
await widget.mpInstance?.identity
.identify(identityRequest: identityRequest);

widget.mpInstance?.rokt.selectShoppableAds(
identifier: 'StgRoktShoppableAds',
attributes: _getShoppableAdsAttributes());
print('${_getPlatform()} Rokt selectShoppableAds called');
} catch (e) {
print('Error calling Rokt selectShoppableAds: $e');
}
}),
Center(
child: Text("Location1", style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold)),
),
Expand Down
Loading
Loading