diff --git a/Example/Base.lproj/Main.storyboard b/Example/Base.lproj/Main.storyboard
index 821d493..3c2c3e0 100644
--- a/Example/Base.lproj/Main.storyboard
+++ b/Example/Base.lproj/Main.storyboard
@@ -157,48 +157,78 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -217,9 +247,6 @@
-
-
-
diff --git a/Example/Example/ProductViewController.m b/Example/Example/ProductViewController.m
index 4e00b84..46ad054 100644
--- a/Example/Example/ProductViewController.m
+++ b/Example/Example/ProductViewController.m
@@ -13,20 +13,16 @@ @interface ProductViewController ()
@end
@implementation ProductViewController
-
-- (void)viewDidLoad {
- [super viewDidLoad];
+- (void)viewDidAppear:(BOOL)animated {
+ [super viewDidAppear:animated];
ATTNItem* item = [self buildItem];
ATTNProductViewEvent* productView = [[ATTNProductViewEvent alloc] initWithItems:@[ item ]];
+ productView.deeplink = @"https://mydeeplink.com/products/32432423";
[[ATTNEventTracker sharedInstance] recordEvent:productView];
-}
-- (void)viewDidAppear:(BOOL)animated {
- [super viewDidAppear:animated];
-
- [self showToast:@"Product View event sent"];
+ [self showToast:@"Product View event sent" duration:2];
}
@@ -35,7 +31,16 @@ - (IBAction)addToCartButtonPressed:(id)sender {
ATTNAddToCartEvent* addToCart = [[ATTNAddToCartEvent alloc] initWithItems:@[ item ]];
[[ATTNEventTracker sharedInstance] recordEvent:addToCart];
- [self showToast:@"Add To Cart event sent"];
+ [self showToast:@"Add To Cart event sent" duration:2];
+}
+
+- (IBAction)addToCartWithDeeplinkButtonPressed:(id)sender {
+ ATTNItem* item = [self buildItem];
+ ATTNAddToCartEvent* addToCart = [[ATTNAddToCartEvent alloc] initWithItems:@[ item ]];
+ addToCart.deeplink = @"https://mydeeplink.com/products/32432423";
+
+ [[ATTNEventTracker sharedInstance] recordEvent:addToCart];
+ [self showToast: [NSString stringWithFormat:@"Add To Cart event sent with requestURL(pd): '%@'", addToCart.deeplink] duration:4];
}
- (IBAction)purchaseButtonPressed:(id)sender {
@@ -50,7 +55,7 @@ - (IBAction)purchaseButtonPressed:(id)sender {
[[ATTNEventTracker sharedInstance] recordEvent:purchase];
- [self showToast:@"Purchase event sent"];
+ [self showToast:@"Purchase event sent" duration:2];
}
- (ATTNItem*)buildItem {
@@ -67,19 +72,16 @@ - (IBAction)customEventButtonPressed:(id)sender {
[[ATTNEventTracker sharedInstance] recordEvent:customEvent];
- [self showToast:@"Custom event sent"];
+ [self showToast:@"Custom event sent" duration:2];
}
-
-- (void)showToast:(NSString*)message {
+- (void)showToast:(NSString*)message duration:(int)duration {
UIAlertController* alert = [UIAlertController alertControllerWithTitle:nil
message:message
preferredStyle:UIAlertControllerStyleAlert];
[self presentViewController:alert animated:YES completion:nil];
- int duration = 1; // duration in seconds
-
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, duration * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
[alert dismissViewControllerAnimated:YES completion:nil];
});
diff --git a/Sources/API/ATTNEventRequest.swift b/Sources/API/ATTNEventRequest.swift
index 17b33a7..4abc5b1 100644
--- a/Sources/API/ATTNEventRequest.swift
+++ b/Sources/API/ATTNEventRequest.swift
@@ -11,6 +11,7 @@ import Foundation
final class ATTNEventRequest {
var metadata: [String: Any]
let eventNameAbbreviation: String
+ var deeplink: String?
init(metadata: [String: Any], eventNameAbbreviation: String) {
self.metadata = metadata
diff --git a/Sources/Helpers/Extension/ATTNAddToCartEvent+Extension.swift b/Sources/Helpers/Extension/ATTNAddToCartEvent+Extension.swift
index 86678e5..bf32d18 100644
--- a/Sources/Helpers/Extension/ATTNAddToCartEvent+Extension.swift
+++ b/Sources/Helpers/Extension/ATTNAddToCartEvent+Extension.swift
@@ -19,7 +19,17 @@ extension ATTNAddToCartEvent: ATTNEventRequestProvider {
for item in items {
var metadata = [String: Any]()
item.addItem(toDictionary: &metadata, with: priceFormatter)
- eventRequests.append(.init(metadata: metadata, eventNameAbbreviation: ATTNEventTypes.addToCart))
+
+ let eventRequest = ATTNEventRequest(
+ metadata: metadata,
+ eventNameAbbreviation: ATTNEventTypes.addToCart
+ )
+
+ if let deeplink {
+ eventRequest.deeplink = deeplink
+ }
+
+ eventRequests.append(eventRequest)
}
return eventRequests
diff --git a/Sources/Helpers/Extension/ATTNProductViewEvent+Extension.swift b/Sources/Helpers/Extension/ATTNProductViewEvent+Extension.swift
index c77c347..3ce0df7 100644
--- a/Sources/Helpers/Extension/ATTNProductViewEvent+Extension.swift
+++ b/Sources/Helpers/Extension/ATTNProductViewEvent+Extension.swift
@@ -19,7 +19,17 @@ extension ATTNProductViewEvent: ATTNEventRequestProvider {
for item in items {
var metadata = [String: Any]()
item.addItem(toDictionary: &metadata, with: priceFormatter)
- eventRequests.append(.init(metadata: metadata, eventNameAbbreviation: ATTNEventTypes.productView))
+
+ let eventRequest = ATTNEventRequest(
+ metadata: metadata,
+ eventNameAbbreviation: ATTNEventTypes.productView
+ )
+
+ if let deeplink {
+ eventRequest.deeplink = deeplink
+ }
+
+ eventRequests.append(eventRequest)
}
return eventRequests
diff --git a/Sources/Public/Events/ATTNAddToCartEvent.swift b/Sources/Public/Events/ATTNAddToCartEvent.swift
index c72c0b1..181f454 100644
--- a/Sources/Public/Events/ATTNAddToCartEvent.swift
+++ b/Sources/Public/Events/ATTNAddToCartEvent.swift
@@ -10,10 +10,17 @@ import Foundation
@objc(ATTNAddToCartEvent)
public final class ATTNAddToCartEvent: NSObject, ATTNEvent {
@objc public let items: [ATTNItem]
+ @objc public var deeplink: String?
- @objc
- public init(items: [ATTNItem]) {
+ @objc(initWithItems:)
+ public convenience init(items: [ATTNItem]) {
+ self.init(items: items, deeplink: nil)
+ }
+
+ @objc(initWithItems:deeplink:)
+ public init(items: [ATTNItem], deeplink: String?) {
self.items = items
+ self.deeplink = deeplink
super.init()
}
@@ -21,3 +28,5 @@ public final class ATTNAddToCartEvent: NSObject, ATTNEvent {
fatalError("init() has not been implemented")
}
}
+
+extension ATTNAddToCartEvent: ATTNDeeplinkHandling { }
diff --git a/Sources/Public/Events/ATTNDeeplinkHandling.swift b/Sources/Public/Events/ATTNDeeplinkHandling.swift
new file mode 100644
index 0000000..a2d7d17
--- /dev/null
+++ b/Sources/Public/Events/ATTNDeeplinkHandling.swift
@@ -0,0 +1,12 @@
+//
+// ATTNDeeplinkHandling.swift
+// attentive-ios-sdk-framework
+//
+// Created by Vladimir - Work on 2024-07-10.
+//
+
+import Foundation
+
+protocol ATTNDeeplinkHandling {
+ var deeplink: String? { get set }
+}
diff --git a/Sources/Public/Events/ATTNProductViewEvent.swift b/Sources/Public/Events/ATTNProductViewEvent.swift
index 23af889..7ac0176 100644
--- a/Sources/Public/Events/ATTNProductViewEvent.swift
+++ b/Sources/Public/Events/ATTNProductViewEvent.swift
@@ -10,10 +10,17 @@ import Foundation
@objc(ATTNProductViewEvent)
public final class ATTNProductViewEvent: NSObject, ATTNEvent {
@objc public let items: [ATTNItem]
+ @objc public var deeplink: String?
@objc(initWithItems:)
- public init(items: [ATTNItem]) {
+ public convenience init(items: [ATTNItem]) {
+ self.init(items: items, deeplink: nil)
+ }
+
+ @objc(initWithItems:deeplink:)
+ public init(items: [ATTNItem], deeplink: String?) {
self.items = items
+ self.deeplink = deeplink
super.init()
}
@@ -21,3 +28,5 @@ public final class ATTNProductViewEvent: NSObject, ATTNEvent {
fatalError("init() has not been implemented")
}
}
+
+extension ATTNProductViewEvent: ATTNDeeplinkHandling { }
diff --git a/Sources/URLProviders/ATTNEventURLProvider.swift b/Sources/URLProviders/ATTNEventURLProvider.swift
index d0dbd65..3072978 100644
--- a/Sources/URLProviders/ATTNEventURLProvider.swift
+++ b/Sources/URLProviders/ATTNEventURLProvider.swift
@@ -39,6 +39,10 @@ struct ATTNEventURLProvider: ATTNEventURLProviding {
queryParams["m"] = try? ATTNJsonUtils.convertObjectToJson(combinedMetadata) ?? "{}"
queryParams["t"] = eventRequest.eventNameAbbreviation
+ if let deeplink = eventRequest.deeplink {
+ queryParams["pd"] = deeplink
+ }
+
urlComponents.queryItems = queryParams.map { .init(name: $0.key, value: $0.value) }
return urlComponents.url
}
diff --git a/Tests/TestCases/ATTNAddToCartEventTests.swift b/Tests/TestCases/ATTNAddToCartEventTests.swift
new file mode 100644
index 0000000..2d58e8d
--- /dev/null
+++ b/Tests/TestCases/ATTNAddToCartEventTests.swift
@@ -0,0 +1,28 @@
+//
+// ATTNAddToCartEventTests.swift
+// attentive-ios-sdk Tests
+//
+// Created by Vladimir - Work on 2024-07-11.
+//
+
+import XCTest
+@testable import ATTNSDKFramework
+
+final class ATTNAddToCartEventTests: XCTestCase {
+ func testAddCart_GivenData_ShouldBuildURL() {
+ let item = ATTNTestEventUtils.buildItem()
+ let addToCart = ATTNAddToCartEvent(items: [item])
+ XCTAssertFalse(addToCart.eventRequests.isEmpty)
+ XCTAssertNil(addToCart.eventRequests.first?.deeplink)
+ }
+
+ func testAddCart_GivenData_ShouldBuildURLWithRequestURL() {
+ let item = ATTNTestEventUtils.buildItem()
+ let addToCart = ATTNAddToCartEvent(items: [item])
+ addToCart.deeplink = "https://mydeeplink.com/products/32432423"
+ XCTAssertFalse(addToCart.eventRequests.isEmpty)
+ let requestURL = addToCart.eventRequests.first?.deeplink as? String
+ XCTAssertNotNil(requestURL)
+ XCTAssertFalse(requestURL?.isEmpty ?? true)
+ }
+}
diff --git a/Tests/TestCases/ATTNProductViewEventTests.swift b/Tests/TestCases/ATTNProductViewEventTests.swift
new file mode 100644
index 0000000..4050c40
--- /dev/null
+++ b/Tests/TestCases/ATTNProductViewEventTests.swift
@@ -0,0 +1,29 @@
+//
+// ATTNProductViewEventTests.swift
+// attentive-ios-sdk Tests
+//
+// Created by Vladimir - Work on 2024-07-11.
+//
+
+import Foundation
+
+import XCTest
+@testable import ATTNSDKFramework
+
+final class ATTNProductViewEventTests: XCTestCase {
+ func testProductView_GivenData_ShouldBuildURL() {
+ let item = ATTNTestEventUtils.buildItem()
+ let productView = ATTNProductViewEvent(items: [item])
+ XCTAssertFalse(productView.eventRequests.isEmpty)
+ XCTAssertNil(productView.eventRequests.first?.deeplink)
+ }
+
+ func testProductView_GivenData_ShouldBuildURLWithRequestURL() {
+ let item = ATTNTestEventUtils.buildItem()
+ let productView = ATTNProductViewEvent(items: [item], deeplink: "https://mydeeplink.com/products/32432423")
+ XCTAssertFalse(productView.eventRequests.isEmpty)
+ let requestURL = productView.eventRequests.first?.deeplink as? String
+ XCTAssertNotNil(requestURL)
+ XCTAssertFalse(requestURL?.isEmpty ?? true)
+ }
+}
diff --git a/attentive-ios-sdk.xcodeproj/project.pbxproj b/attentive-ios-sdk.xcodeproj/project.pbxproj
index a8bf9b0..7b21641 100644
--- a/attentive-ios-sdk.xcodeproj/project.pbxproj
+++ b/attentive-ios-sdk.xcodeproj/project.pbxproj
@@ -52,6 +52,9 @@
FB60AF0B2C1211C700C61537 /* ATTNEventURLProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = FB60AF0A2C1211C700C61537 /* ATTNEventURLProvider.swift */; };
FB65536A2C1B72D4008DB3B1 /* ATTNSDKTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = FB6553692C1B72D4008DB3B1 /* ATTNSDKTests.swift */; };
FB65536C2C1B74A9008DB3B1 /* ATTNAPIProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = FB65536B2C1B74A9008DB3B1 /* ATTNAPIProtocol.swift */; };
+ FB84E3032C3F30FF0011936B /* ATTNDeeplinkHandling.swift in Sources */ = {isa = PBXBuildFile; fileRef = FB84E3022C3F30FF0011936B /* ATTNDeeplinkHandling.swift */; };
+ FB86C03E2C40611A00E35580 /* ATTNAddToCartEventTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = FB86C03D2C40611A00E35580 /* ATTNAddToCartEventTests.swift */; };
+ FB86C0402C40669400E35580 /* ATTNProductViewEventTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = FB86C03F2C40669400E35580 /* ATTNProductViewEventTests.swift */; };
FB90EF0B2C109CB4004DFC4A /* ATTNAPIITTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = FB90EF0A2C109CB4004DFC4A /* ATTNAPIITTests.swift */; };
FB90EF0D2C10A7F7004DFC4A /* NSURLSessionDataTaskMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = FB90EF0C2C10A7F7004DFC4A /* NSURLSessionDataTaskMock.swift */; };
FB90EF0F2C10A81E004DFC4A /* NSURLSessionMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = FB90EF0E2C10A81E004DFC4A /* NSURLSessionMock.swift */; };
@@ -156,6 +159,9 @@
FB6553692C1B72D4008DB3B1 /* ATTNSDKTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ATTNSDKTests.swift; sourceTree = ""; };
FB65536B2C1B74A9008DB3B1 /* ATTNAPIProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ATTNAPIProtocol.swift; sourceTree = ""; };
FB65536D2C1B7747008DB3B1 /* ATTNAPISpy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ATTNAPISpy.swift; sourceTree = ""; };
+ FB84E3022C3F30FF0011936B /* ATTNDeeplinkHandling.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ATTNDeeplinkHandling.swift; sourceTree = ""; };
+ FB86C03D2C40611A00E35580 /* ATTNAddToCartEventTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ATTNAddToCartEventTests.swift; sourceTree = ""; };
+ FB86C03F2C40669400E35580 /* ATTNProductViewEventTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ATTNProductViewEventTests.swift; sourceTree = ""; };
FB90EF0A2C109CB4004DFC4A /* ATTNAPIITTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ATTNAPIITTests.swift; sourceTree = ""; };
FB90EF0C2C10A7F7004DFC4A /* NSURLSessionDataTaskMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSURLSessionDataTaskMock.swift; sourceTree = ""; };
FB90EF0E2C10A81E004DFC4A /* NSURLSessionMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSURLSessionMock.swift; sourceTree = ""; };
@@ -335,6 +341,8 @@
FB2984072C0FAE040039759C /* ATTNAPITests.swift */,
FB90EF0A2C109CB4004DFC4A /* ATTNAPIITTests.swift */,
FB6553692C1B72D4008DB3B1 /* ATTNSDKTests.swift */,
+ FB86C03D2C40611A00E35580 /* ATTNAddToCartEventTests.swift */,
+ FB86C03F2C40669400E35580 /* ATTNProductViewEventTests.swift */,
);
path = TestCases;
sourceTree = "";
@@ -437,6 +445,7 @@
FBA9F9F72C0A77AB00C65024 /* ATTNPrice.swift */,
FBA9F9F82C0A77AB00C65024 /* ATTNProductViewEvent.swift */,
FBA9F9F92C0A77AB00C65024 /* ATTNPurchaseEvent.swift */,
+ FB84E3022C3F30FF0011936B /* ATTNDeeplinkHandling.swift */,
);
path = Events;
sourceTree = "";
@@ -680,6 +689,7 @@
FB4E3FE72C372C54004B8FF0 /* ATTNWebViewProviding.swift in Sources */,
FBA9FA0A2C0A77AB00C65024 /* ATTNCreativeUrlProvider.swift in Sources */,
FB65536C2C1B74A9008DB3B1 /* ATTNAPIProtocol.swift in Sources */,
+ FB84E3032C3F30FF0011936B /* ATTNDeeplinkHandling.swift in Sources */,
FB35C17D2C0E039E009FA048 /* ATTNConstants.swift in Sources */,
FB56D4DC2C208D6100AF7530 /* Boolean+Extension.swift in Sources */,
FBA9FA082C0A77AB00C65024 /* Dictionary+Extension.swift in Sources */,
@@ -700,7 +710,9 @@
FB90EF0F2C10A81E004DFC4A /* NSURLSessionMock.swift in Sources */,
FB2983E42C0F73990039759C /* ATTNAppInfoMock.swift in Sources */,
FB2983F82C0F7FB60039759C /* ATTNUserAgentBuilderTests.swift in Sources */,
+ FB86C03E2C40611A00E35580 /* ATTNAddToCartEventTests.swift in Sources */,
FB2983F62C0F7CF10039759C /* ATTNUserIdentityTests.swift in Sources */,
+ FB86C0402C40669400E35580 /* ATTNProductViewEventTests.swift in Sources */,
FB2983F42C0F759D0039759C /* ATTNVisitorServiceTests.swift in Sources */,
FB2983FA2C0F80A30039759C /* ATTNPersistentStorageTests.swift in Sources */,
FB080C722C1C755F00834BAA /* ATTNCreativeUrlProviderSpy.swift in Sources */,