Skip to content

Commit a4388cb

Browse files
chore: Add MPRoktLayout Implementation to Example App (#598)
* chore: Add MPRoktLayout Implementation to Example App
1 parent 37c277c commit a4388cb

File tree

2 files changed

+255
-7
lines changed

2 files changed

+255
-7
lines changed

SwiftExample/mParticleSwiftExample.xcodeproj/project.pbxproj

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
/* Begin PBXBuildFile section */
1010
7E4B5EB92F338B9100B61C64 /* mParticle-Apple-SDK in Frameworks */ = {isa = PBXBuildFile; productRef = 7E4B5EB82F338B9100B61C64 /* mParticle-Apple-SDK */; };
11-
7E4B5EBC2F338BA500B61C64 /* mParticle-Rokt in Frameworks */ = {isa = PBXBuildFile; productRef = 7E4B5EBB2F338BA500B61C64 /* mParticle-Rokt */; };
11+
7ED594AE2F46240D00AB6433 /* mParticle-Rokt in Frameworks */ = {isa = PBXBuildFile; productRef = 7ED594AD2F46240D00AB6433 /* mParticle-Rokt */; };
1212
A10000010000000000000001 /* mParticleSwiftExampleApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = A10000020000000000000001 /* mParticleSwiftExampleApp.swift */; };
1313
A10000010000000000000002 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A10000020000000000000002 /* ContentView.swift */; };
1414
A10000010000000000000003 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = A10000020000000000000003 /* Assets.xcassets */; };
@@ -31,7 +31,7 @@
3131
files = (
3232
7E4B5EB92F338B9100B61C64 /* mParticle-Apple-SDK in Frameworks */,
3333
A10000010000000000000004 /* mParticle-Apple-SDK in Frameworks */,
34-
7E4B5EBC2F338BA500B61C64 /* mParticle-Rokt in Frameworks */,
34+
7ED594AE2F46240D00AB6433 /* mParticle-Rokt in Frameworks */,
3535
);
3636
runOnlyForDeploymentPostprocessing = 0;
3737
};
@@ -85,7 +85,7 @@
8585
packageProductDependencies = (
8686
A10000030000000000000001 /* mParticle-Apple-SDK */,
8787
7E4B5EB82F338B9100B61C64 /* mParticle-Apple-SDK */,
88-
7E4B5EBB2F338BA500B61C64 /* mParticle-Rokt */,
88+
7ED594AD2F46240D00AB6433 /* mParticle-Rokt */,
8989
);
9090
productName = mParticleSwiftExample;
9191
productReference = A10000020000000000000006 /* mParticleSwiftExample.app */;
@@ -117,7 +117,7 @@
117117
mainGroup = A10000050000000000000001;
118118
packageReferences = (
119119
7E4B5EB72F338B9100B61C64 /* XCRemoteSwiftPackageReference "mparticle-apple-sdk" */,
120-
7E4B5EBA2F338BA500B61C64 /* XCRemoteSwiftPackageReference "mparticle-apple-integration-rokt" */,
120+
7ED594AC2F46240D00AB6433 /* XCRemoteSwiftPackageReference "mparticle-apple-integration-rokt" */,
121121
);
122122
productRefGroup = A10000050000000000000003 /* Products */;
123123
projectDirPath = "";
@@ -367,7 +367,7 @@
367367
minimumVersion = 8.4.0;
368368
};
369369
};
370-
7E4B5EBA2F338BA500B61C64 /* XCRemoteSwiftPackageReference "mparticle-apple-integration-rokt" */ = {
370+
7ED594AC2F46240D00AB6433 /* XCRemoteSwiftPackageReference "mparticle-apple-integration-rokt" */ = {
371371
isa = XCRemoteSwiftPackageReference;
372372
repositoryURL = "https://github.com/mparticle-integrations/mparticle-apple-integration-rokt.git";
373373
requirement = {
@@ -383,9 +383,9 @@
383383
package = 7E4B5EB72F338B9100B61C64 /* XCRemoteSwiftPackageReference "mparticle-apple-sdk" */;
384384
productName = "mParticle-Apple-SDK";
385385
};
386-
7E4B5EBB2F338BA500B61C64 /* mParticle-Rokt */ = {
386+
7ED594AD2F46240D00AB6433 /* mParticle-Rokt */ = {
387387
isa = XCSwiftPackageProductDependency;
388-
package = 7E4B5EBA2F338BA500B61C64 /* XCRemoteSwiftPackageReference "mparticle-apple-integration-rokt" */;
388+
package = 7ED594AC2F46240D00AB6433 /* XCRemoteSwiftPackageReference "mparticle-apple-integration-rokt" */;
389389
productName = "mParticle-Rokt";
390390
};
391391
A10000030000000000000001 /* mParticle-Apple-SDK */ = {

SwiftExample/mParticleSwiftExample/ContentView.swift

Lines changed: 248 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
// swiftlint:disable file_length
22
import SwiftUI
33
import mParticle_Apple_SDK
4+
import mParticle_Rokt_Swift
5+
import Rokt_Widget
46
import AdSupport
57
import AppTrackingTransparency
68

@@ -95,6 +97,13 @@ struct ContentView: View {
9597
title: "Display Rokt Overlay (auto close)",
9698
action: selectOverlayPlacementAutoClose
9799
)
100+
ActionButton(
101+
title: "Display Rokt with Event Subscription",
102+
action: selectPlacementWithEventSubscription
103+
)
104+
NavigationLink("MPRoktLayout SwiftUI Example") {
105+
RoktLayoutExampleView()
106+
}
98107
}
99108
}
100109
.listStyle(InsetGroupedListStyle())
@@ -202,6 +211,175 @@ struct RoktEmbeddedViewWrapper: UIViewRepresentable {
202211
}
203212
}
204213

214+
// MARK: - MPRoktLayout SwiftUI Example
215+
216+
struct RoktLayoutExampleView: View {
217+
@State private var sdkTriggered = false
218+
@State private var eventLog: [String] = []
219+
220+
let attributes: [String: String] = [
221+
"email": "j.smith@example.com",
222+
"firstname": "Jenny",
223+
"lastname": "Smith",
224+
"billingzipcode": "07762",
225+
"confirmationref": "54321",
226+
"sandbox": "true",
227+
"mobile": "(555)867-5309"
228+
]
229+
230+
var body: some View {
231+
ScrollView {
232+
VStack(alignment: .leading, spacing: 16) {
233+
Text("MPRoktLayout Example")
234+
.font(.title2)
235+
.fontWeight(.bold)
236+
.padding(.horizontal)
237+
238+
Text("This demonstrates the SwiftUI-native MPRoktLayout component for embedding Rokt placements declaratively.")
239+
.font(.subheadline)
240+
.foregroundColor(.secondary)
241+
.padding(.horizontal)
242+
243+
// Trigger button
244+
Button {
245+
sdkTriggered = true
246+
eventLog.append("[\(formattedTime())] Triggered placement")
247+
} label: {
248+
Text(sdkTriggered ? "Placement Triggered" : "Trigger Rokt Placement")
249+
.frame(maxWidth: .infinity)
250+
.padding()
251+
.background(sdkTriggered ? Color.gray : Color.blue)
252+
.foregroundColor(.white)
253+
.cornerRadius(10)
254+
}
255+
.disabled(sdkTriggered)
256+
.padding(.horizontal)
257+
258+
// Reset button
259+
if sdkTriggered {
260+
Button {
261+
sdkTriggered = false
262+
eventLog.append("[\(formattedTime())] Reset placement")
263+
} label: {
264+
Text("Reset")
265+
.frame(maxWidth: .infinity)
266+
.padding()
267+
.background(Color.orange)
268+
.foregroundColor(.white)
269+
.cornerRadius(10)
270+
}
271+
.padding(.horizontal)
272+
}
273+
274+
// Rokt Layout - Embedded Placement
275+
if sdkTriggered {
276+
VStack(alignment: .leading, spacing: 8) {
277+
Text("Embedded Placement")
278+
.font(.headline)
279+
.padding(.horizontal)
280+
281+
MPRoktLayout(
282+
sdkTriggered: $sdkTriggered,
283+
viewName: "RoktExperience",
284+
locationName: "RoktEmbedded1",
285+
attributes: attributes,
286+
config: createRoktConfig(),
287+
onEvent: { roktEvent in
288+
handleRoktEvent(roktEvent)
289+
}
290+
).roktLayout
291+
.padding(.horizontal)
292+
}
293+
}
294+
295+
// Event Log
296+
VStack(alignment: .leading, spacing: 8) {
297+
Text("Event Log")
298+
.font(.headline)
299+
.padding(.horizontal)
300+
301+
if eventLog.isEmpty {
302+
Text("No events yet. Trigger the placement to see events.")
303+
.font(.caption)
304+
.foregroundColor(.secondary)
305+
.padding(.horizontal)
306+
} else {
307+
ForEach(eventLog.reversed(), id: \.self) { event in
308+
Text(event)
309+
.font(.system(.caption, design: .monospaced))
310+
.padding(.horizontal)
311+
}
312+
}
313+
}
314+
.padding(.vertical)
315+
.background(Color(.systemGray6))
316+
.cornerRadius(10)
317+
.padding(.horizontal)
318+
319+
Spacer()
320+
}
321+
.padding(.vertical)
322+
}
323+
.navigationTitle("MPRoktLayout")
324+
.navigationBarTitleDisplayMode(.inline)
325+
}
326+
327+
private func createRoktConfig() -> RoktConfig {
328+
return RoktConfig.Builder().build()
329+
}
330+
331+
private func handleRoktEvent(_ event: RoktEvent) {
332+
let timestamp = formattedTime()
333+
334+
switch event {
335+
case is RoktEvent.ShowLoadingIndicator:
336+
eventLog.append("[\(timestamp)] Show Loading Indicator")
337+
338+
case is RoktEvent.HideLoadingIndicator:
339+
eventLog.append("[\(timestamp)] Hide Loading Indicator")
340+
341+
case let placementReady as RoktEvent.PlacementReady:
342+
eventLog.append("[\(timestamp)] Placement Ready - ID: \(placementReady.placementId ?? "unknown")")
343+
344+
case let placementInteractive as RoktEvent.PlacementInteractive:
345+
eventLog.append("[\(timestamp)] Placement Interactive - ID: \(placementInteractive.placementId ?? "unknown")")
346+
347+
case let offerEngagement as RoktEvent.OfferEngagement:
348+
eventLog.append("[\(timestamp)] Offer Engagement - ID: \(offerEngagement.placementId ?? "unknown")")
349+
350+
case let positiveEngagement as RoktEvent.PositiveEngagement:
351+
eventLog.append("[\(timestamp)] Positive Engagement - ID: \(positiveEngagement.placementId ?? "unknown")")
352+
353+
case let firstPositiveEngagement as RoktEvent.FirstPositiveEngagement:
354+
eventLog.append("[\(timestamp)] First Positive Engagement - ID: \(firstPositiveEngagement.placementId ?? "unknown")")
355+
356+
case let openUrl as RoktEvent.OpenUrl:
357+
eventLog.append("[\(timestamp)] Open URL - \(openUrl.url)")
358+
359+
case let placementClosed as RoktEvent.PlacementClosed:
360+
eventLog.append("[\(timestamp)] Placement Closed - ID: \(placementClosed.placementId ?? "unknown")")
361+
362+
case let placementCompleted as RoktEvent.PlacementCompleted:
363+
eventLog.append("[\(timestamp)] Placement Completed - ID: \(placementCompleted.placementId ?? "unknown")")
364+
365+
case let placementFailure as RoktEvent.PlacementFailure:
366+
eventLog.append("[\(timestamp)] Placement Failure - ID: \(placementFailure.placementId ?? "unknown")")
367+
368+
case let cartItem as RoktEvent.CartItemInstantPurchase:
369+
eventLog.append("[\(timestamp)] Cart Item Purchase - \(cartItem.name ?? "unknown")")
370+
371+
default:
372+
eventLog.append("[\(timestamp)] Event: \(type(of: event))")
373+
}
374+
}
375+
376+
private func formattedTime() -> String {
377+
let formatter = DateFormatter()
378+
formatter.dateFormat = "HH:mm:ss"
379+
return formatter.string(from: Date())
380+
}
381+
}
382+
205383
// MARK: - mParticle Actions
206384

207385
func logSimpleEvent() {
@@ -718,6 +896,76 @@ func selectOverlayPlacementAutoClose() {
718896
}
719897
}
720898

899+
func selectPlacementWithEventSubscription() {
900+
let customAttributes: [String: String] = [
901+
"email": "j.smit@example.com",
902+
"firstname": "Jenny",
903+
"lastname": "Smith",
904+
"sandbox": "true",
905+
"mobile": "(555)867-5309"
906+
]
907+
908+
let placementIdentifier = "RoktLayout"
909+
910+
// Subscribe to Rokt events for this placement
911+
MParticle.sharedInstance().rokt.events(placementIdentifier) { event in
912+
switch event {
913+
case let initComplete as MPRoktEvent.MPRoktInitComplete:
914+
print("Rokt Init Complete - Success: \(initComplete.success)")
915+
916+
case is MPRoktEvent.MPRoktShowLoadingIndicator:
917+
print("Rokt: Show Loading Indicator")
918+
919+
case is MPRoktEvent.MPRoktHideLoadingIndicator:
920+
print("Rokt: Hide Loading Indicator")
921+
922+
case let placementReady as MPRoktEvent.MPRoktPlacementReady:
923+
print("Rokt Placement Ready - ID: \(placementReady.placementId ?? "unknown")")
924+
925+
case let placementInteractive as MPRoktEvent.MPRoktPlacementInteractive:
926+
print("Rokt Placement Interactive - ID: \(placementInteractive.placementId ?? "unknown")")
927+
928+
case let offerEngagement as MPRoktEvent.MPRoktOfferEngagement:
929+
print("Rokt Offer Engagement - ID: \(offerEngagement.placementId ?? "unknown")")
930+
931+
case let positiveEngagement as MPRoktEvent.MPRoktPositiveEngagement:
932+
print("Rokt Positive Engagement - ID: \(positiveEngagement.placementId ?? "unknown")")
933+
934+
case let firstPositiveEngagement as MPRoktEvent.MPRoktFirstPositiveEngagement:
935+
print("Rokt First Positive Engagement - ID: \(firstPositiveEngagement.placementId ?? "unknown")")
936+
937+
case let openUrl as MPRoktEvent.MPRoktOpenUrl:
938+
print("Rokt Open URL - ID: \(openUrl.placementId ?? "unknown"), URL: \(openUrl.url)")
939+
940+
case let placementClosed as MPRoktEvent.MPRoktPlacementClosed:
941+
print("Rokt Placement Closed - ID: \(placementClosed.placementId ?? "unknown")")
942+
943+
case let placementCompleted as MPRoktEvent.MPRoktPlacementCompleted:
944+
print("Rokt Placement Completed - ID: \(placementCompleted.placementId ?? "unknown")")
945+
946+
case let placementFailure as MPRoktEvent.MPRoktPlacementFailure:
947+
print("Rokt Placement Failure - ID: \(placementFailure.placementId ?? "unknown")")
948+
949+
case let cartItem as MPRoktEvent.MPRoktCartItemInstantPurchase:
950+
print("Rokt Cart Item Instant Purchase:")
951+
print(" - Placement ID: \(cartItem.placementId)")
952+
print(" - Catalog Item ID: \(cartItem.catalogItemId)")
953+
print(" - Cart Item ID: \(cartItem.cartItemId)")
954+
print(" - Name: \(cartItem.name ?? "unknown")")
955+
print(" - Currency: \(cartItem.currency)")
956+
print(" - Unit Price: \(cartItem.unitPrice ?? 0)")
957+
print(" - Total Price: \(cartItem.totalPrice ?? 0)")
958+
print(" - Quantity: \(cartItem.quantity ?? 0)")
959+
960+
default:
961+
print("Rokt: Unknown event type - \(type(of: event))")
962+
}
963+
}
964+
965+
// Select the placement (this will trigger events)
966+
MParticle.sharedInstance().rokt.selectPlacements(placementIdentifier, attributes: customAttributes)
967+
}
968+
721969
#Preview {
722970
ContentView()
723971
}

0 commit comments

Comments
 (0)