Skip to content

Commit 370428c

Browse files
committed
feat(rokt): add selectShoppableAds interface and iOS bridge
Expose selectShoppableAds in the Flutter API with iOS native implementation, Android no-op parity, and platform tests while keeping pod dependencies minimal via transitive resolution. Made-with: Cursor
1 parent d28c321 commit 370428c

6 files changed

Lines changed: 85 additions & 3 deletions

File tree

android/src/main/kotlin/com/mparticle/mparticle_flutter_sdk/MparticleFlutterSdkPlugin.kt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,7 @@ class MparticleFlutterSdkPlugin: FlutterPlugin, MethodCallHandler, ActivityAware
235235
result.success(true)
236236
}
237237
"roktSelectPlacements" -> this.roktSelectPlacements(call, result)
238+
"roktSelectShoppableAds" -> this.roktSelectShoppableAds(call, result)
238239
"roktPurchaseFinalized" -> this.roktPurchaseFinalized(call, result)
239240
else -> {
240241
result.notImplemented()
@@ -806,6 +807,11 @@ class MparticleFlutterSdkPlugin: FlutterPlugin, MethodCallHandler, ActivityAware
806807
}
807808
}
808809

810+
private fun roktSelectShoppableAds(call: MethodCall, result: Result) {
811+
// Parity with RN bridge: Android API is exposed but not implemented yet.
812+
result.success(true)
813+
}
814+
809815
private fun String.toColorMode(): RoktConfig.ColorMode =
810816
when (this) {
811817
"dark" -> RoktConfig.ColorMode.DARK

ios/Classes/SwiftMparticleFlutterSdkPlugin.swift

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -561,6 +561,28 @@ public class SwiftMparticleFlutterSdkPlugin: NSObject, FlutterPlugin {
561561
print("Incorrect argument for \(call.method) iOS method")
562562
result(FlutterError(code: "INVALID_ARGUMENTS", message: "Missing placementId or catalogItemId or success", details: nil))
563563
}
564+
case "roktSelectShoppableAds":
565+
if let callArguments = call.arguments as? [String: Any],
566+
let placementId = callArguments["placementId"] as? String {
567+
let attributes = callArguments["attributes"] as? [String: String] ?? [:]
568+
var roktConfig: RoktConfig?
569+
if let configMap = callArguments["config"] as? [String: Any] {
570+
roktConfig = buildRoktConfig(configMap: configMap)
571+
}
572+
573+
roktEventHandler.subscribeToEvents(identifier: placementId)
574+
MParticle.sharedInstance().rokt.selectShoppableAds(
575+
placementId,
576+
attributes: attributes,
577+
config: roktConfig
578+
) { _ in
579+
// Event propagation is handled by subscribeToEvents(identifier:)
580+
}
581+
result(true)
582+
} else {
583+
print("Incorrect argument for \(call.method) iOS method")
584+
result(FlutterError(code: "INVALID_ARGUMENTS", message: "Missing placementId", details: nil))
585+
}
564586
default:
565587
print("mParticle flutter SDK for iOS does not support \(call.method)")
566588
}

ios/mparticle_flutter_sdk.podspec

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,8 @@ mParticle Flutter Wrapper
1515
s.source = { :path => '.' }
1616
s.source_files = 'Classes/**/*'
1717
s.dependency 'Flutter'
18-
# SDK 9.0 split requires both umbrella and ObjC pods.
18+
# SDK 9.0 umbrella pod pulls required transitive dependencies.
1919
s.dependency 'mParticle-Apple-SDK', '~> 9.0'
20-
s.dependency 'mParticle-Apple-SDK-ObjC', '~> 9.0'
21-
s.dependency 'RoktContracts', '~> 0.1'
2220
s.platform = :ios, '15.6'
2321

2422
# Flutter.framework does not contain a i386 slice.

lib/mparticle_flutter_sdk.dart

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -331,6 +331,22 @@ class Rokt {
331331
return await _channel.invokeMethod('roktSelectPlacements', params);
332332
}
333333

334+
/// Selects shoppable ads with a [identifier], optional [attributes], and optional [roktConfig].
335+
///
336+
/// This method currently has native implementation on iOS.
337+
/// Android keeps a no-op bridge for cross-platform API compatibility.
338+
Future<void> selectShoppableAds({
339+
required String identifier,
340+
Map<String, dynamic>? attributes,
341+
RoktConfig? roktConfig,
342+
}) async {
343+
return await _channel.invokeMethod('roktSelectShoppableAds', {
344+
'placementId': identifier,
345+
'attributes': attributes,
346+
'config': _roktConfigToMap(config: roktConfig),
347+
});
348+
}
349+
334350
/// Notifies Rokt that a purchase has been finalized
335351
///
336352
/// Use this method to inform Rokt that a purchase has been completed or failed

lib/mparticle_flutter_sdk_web.dart

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -536,6 +536,18 @@ class MparticleFlutterSdkWeb {
536536
})
537537
]);
538538
break;
539+
case 'roktSelectShoppableAds':
540+
final mpRokt = JsObject.fromBrowserObject(context['mParticle']['Rokt']);
541+
final placementId = call.arguments['placementId'];
542+
final attributes = call.arguments['attributes'] ?? {};
543+
544+
mpRokt.callMethod('selectShoppableAds', [
545+
JsObject.jsify({
546+
'identifier': placementId,
547+
'attributes': attributes
548+
})
549+
]);
550+
break;
539551
default:
540552
throw PlatformException(
541553
code: 'Unimplemented',

test/mparticle_flutter_sdk_test.dart

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -502,5 +502,33 @@ void main() {
502502
'success': true,
503503
}));
504504
});
505+
506+
test('rokt select shoppable ads', () async {
507+
final roktConfig = RoktConfig(
508+
colorMode: ColorMode.dark,
509+
cacheConfig: CacheConfig(
510+
cacheDurationInSeconds: 100,
511+
cacheAttributes: {'key1': 'value1'}));
512+
513+
await mp.rokt.selectShoppableAds(
514+
identifier: 'placement1',
515+
attributes: {'attr1': 'val1'},
516+
roktConfig: roktConfig,
517+
);
518+
519+
expect(
520+
methodCall,
521+
isMethodCall('roktSelectShoppableAds', arguments: {
522+
'placementId': 'placement1',
523+
'attributes': {'attr1': 'val1'},
524+
'config': {
525+
'colorMode': 'dark',
526+
'cacheConfig': {
527+
'cacheDurationInSeconds': 100,
528+
'cacheAttributes': {'key1': 'value1'}
529+
}
530+
},
531+
}));
532+
});
505533
});
506534
}

0 commit comments

Comments
 (0)