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 @@ -235,6 +235,7 @@ class MparticleFlutterSdkPlugin: FlutterPlugin, MethodCallHandler, ActivityAware
result.success(true)
}
"roktSelectPlacements" -> this.roktSelectPlacements(call, result)
"roktPurchaseFinalized" -> this.roktPurchaseFinalized(call, result)
else -> {
result.notImplemented()
}
Expand Down Expand Up @@ -785,6 +786,26 @@ class MparticleFlutterSdkPlugin: FlutterPlugin, MethodCallHandler, ActivityAware
return builder.build()
}

private fun roktPurchaseFinalized(call: MethodCall, result: Result) {
val placementId = call.argument<String>("placementId")
val catalogItemId = call.argument<String>("catalogItemId")
val success = call.argument<Boolean>("success") ?: true
if (placementId != null && catalogItemId != null) {
MParticle.getInstance()?.Rokt()?.purchaseFinalized(
placementId = placementId,
catalogItemId = catalogItemId,
status = success,
)
result.success("Success")
} else {
result.error(
"INVALID_PARAMS",
"placementId and catalogItemId are required",
null,
)
}
}

private fun String.toColorMode(): RoktConfig.ColorMode =
when (this) {
"dark" -> RoktConfig.ColorMode.DARK
Expand Down
16 changes: 14 additions & 2 deletions ios/Classes/SwiftMparticleFlutterSdkPlugin.swift
Original file line number Diff line number Diff line change
Expand Up @@ -529,7 +529,7 @@ public class SwiftMparticleFlutterSdkPlugin: NSObject, FlutterPlugin {
}
}
}

var roktConfig: MPRoktConfig?
if let configMap = callArguments["config"] as? [String: Any] {
roktConfig = buildRoktConfig(configMap: configMap)
Expand All @@ -540,12 +540,24 @@ public class SwiftMparticleFlutterSdkPlugin: NSObject, FlutterPlugin {
}

roktEventHandler.subscribeToEvents(identifier: placementId)

MParticle.sharedInstance().rokt.selectPlacements(placementId, attributes: attributes, embeddedViews: placeholders, config: roktConfig, callbacks: callback)
result(true)
} else {
print("Incorrect argument for \(call.method) iOS method")
result(FlutterError(code: "INVALID_ARGUMENTS", message: "Missing placementId", details: nil))
}
case "roktPurchaseFinalized":
if let callArguments = call.arguments as? [String: Any],
let placementId = callArguments["placementId"] as? String,
let catalogItemId = callArguments["catalogItemId"] as? String,
let success = callArguments["success"] as? Bool {
MParticle.sharedInstance().rokt.purchaseFinalized(placementId, catalogItemId: catalogItemId, success: success)
result(true)
} else {
print("Incorrect argument for \(call.method) iOS method")
result(FlutterError(code: "INVALID_ARGUMENTS", message: "Missing placementId or catalogItemId or success", details: nil))
}
default:
print("mParticle flutter SDK for iOS does not support \(call.method)")
}
Expand All @@ -569,7 +581,7 @@ public class SwiftMparticleFlutterSdkPlugin: NSObject, FlutterPlugin {
private func buildRoktConfig(configMap: [String: Any]) -> MPRoktConfig? {
let config = MPRoktConfig()
var isConfigEmpty = true

if let colorModeString = configMap["colorMode"] as? String {
if #available(iOS 12.0, *) {
isConfigEmpty = false
Expand Down
27 changes: 27 additions & 0 deletions lib/mparticle_flutter_sdk.dart
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,12 @@ class MparticleFlutterSdk {
_placeholders[id] = name;
}

/// Clears all placeholders. Used for testing.
@visibleForTesting
void clearPlaceholders() {
_placeholders.clear();
}

/// Logs a product commerce event with an [productActionType], a promotion commerce event with a [eventType], and an impression commerce event if neither of the prior are implemented.
Future<void> logCommerceEvent(CommerceEvent commerceEvent) async {
var commerceEventMessage = {
Expand Down Expand Up @@ -325,6 +331,27 @@ class Rokt {
return await _channel.invokeMethod('roktSelectPlacements', params);
}

/// Notifies Rokt that a purchase has been finalized
///
/// Use this method to inform Rokt that a purchase has been completed or failed
/// - Parameters:
/// - placementId: The placement ID associated with the purchase
/// - catalogItemId: The catalog item ID that was purchased
/// - success: Whether the purchase was successful
///
/// Note: This method requires iOS 15+.
Future<void> purchaseFinalized({
required String placementId,
required String catalogItemId,
required bool success,
}) async {
return await _channel.invokeMethod('roktPurchaseFinalized', {
'placementId': placementId,
'catalogItemId': catalogItemId,
'success': success,
});
}

Map<String, dynamic>? _roktConfigToMap({required RoktConfig? config}) {
if (config == null) {
return null;
Expand Down
61 changes: 61 additions & 0 deletions test/mparticle_flutter_sdk_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ void main() {
TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger
.setMockMethodCallHandler(channel, null);
methodCall = null;
mp.clearPlaceholders();
});

group('mParticle Dart API Layer', () {
Expand Down Expand Up @@ -295,4 +296,64 @@ void main() {
);
});
});

group('Rokt API', () {
test('rokt select placements', () async {
final roktConfig = RoktConfig(
colorMode: ColorMode.dark,
cacheConfig: CacheConfig(
cacheDurationInSeconds: 100,
cacheAttributes: {'key1': 'value1'}));
await mp.rokt.selectPlacements(
placementId: 'placement1',
attributes: {'attr1': 'val1'},
roktConfig: roktConfig,
fontFilePathMap: {'font1': 'path1'});

expect(
methodCall,
isMethodCall('roktSelectPlacements', arguments: {
'placementId': 'placement1',
'attributes': {'attr1': 'val1'},
'config': {
'colorMode': 'dark',
'cacheConfig': {
'cacheDurationInSeconds': 100,
'cacheAttributes': {'key1': 'value1'}
}
},
'fontFilePathMap': {'font1': 'path1'},
}));
});

test('rokt select placements with placeholders', () async {
mp.attachPlaceholder(id: 1, name: "placeholder1");
await mp.rokt.selectPlacements(
placementId: 'placement1',
);

expect(
methodCall,
isMethodCall('roktSelectPlacements', arguments: {
'placementId': 'placement1',
'attributes': null,
'config': null,
'fontFilePathMap': null,
'placeholders': {1: 'placeholder1'},
}));
});

test('rokt purchase finalized', () async {
await mp.rokt.purchaseFinalized(
placementId: 'placement1', catalogItemId: 'catalog1', success: true);

expect(
methodCall,
isMethodCall('roktPurchaseFinalized', arguments: {
'placementId': 'placement1',
'catalogItemId': 'catalog1',
'success': true,
}));
});
});
}