Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 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