Skip to content
7 changes: 7 additions & 0 deletions swift-sdk/Core/Constants.swift
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,7 @@ enum JsonKey {
// Embedded Messages
static let embeddedSessionId = "session"
static let placementId = "placementId"
static let placementIds = "placementIds"
static let embeddedSessionStart = "embeddedSessionStart"
static let embeddedSessionEnd = "embeddedSessionEnd"
static let embeddedButtonId = "buttonIdentifier"
Expand Down Expand Up @@ -316,6 +317,12 @@ enum JsonKey {
enum Embedded {
static let packageName = "packageName"
static let sdkVersion = "SDKVersion"

enum Session {
static let id = "id"
static let start = "start"
static let end = "end"
}
}

enum Header {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ public protocol IterableEmbeddedManagerProtocol {
func removeUpdateListener(_ listener: IterableEmbeddedUpdateDelegate)

func syncMessages(completion: @escaping () -> Void)
func syncMessages(placementIds: [Int]?, completion: @escaping () -> Void)
func handleEmbeddedClick(message: IterableEmbeddedMessage, buttonIdentifier: String?, clickedUrl: String)
func reset()
}
4 changes: 4 additions & 0 deletions swift-sdk/Internal/EmptyEmbeddedManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ class EmptyEmbeddedManager: IterableInternalEmbeddedManagerProtocol {

}

func syncMessages(placementIds: [Int]?, completion: @escaping () -> Void) {

}

public func handleEmbeddedClick(message: IterableEmbeddedMessage, buttonIdentifier: String?, clickedUrl: String) {

}
Expand Down
11 changes: 8 additions & 3 deletions swift-sdk/Internal/IterableEmbeddedManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -161,8 +161,8 @@ class IterableEmbeddedManager: NSObject, IterableInternalEmbeddedManagerProtocol
syncMessages { }
}

private func retrieveEmbeddedMessages(completion: @escaping () -> Void) {
apiClient.getEmbeddedMessages()
private func retrieveEmbeddedMessages(placementIds: [Int]?, completion: @escaping () -> Void) {
apiClient.getEmbeddedMessages(placementIds: placementIds)
.onCompletion(
receiveValue: { embeddedMessagesPayload in
let placements = embeddedMessagesPayload.placements
Expand Down Expand Up @@ -245,8 +245,13 @@ class IterableEmbeddedManager: NSObject, IterableInternalEmbeddedManagerProtocol

extension IterableEmbeddedManager: EmbeddedNotifiable {
public func syncMessages(completion: @escaping () -> Void) {
syncMessages(placementIds: nil, completion: completion)

}

public func syncMessages(placementIds: [Int]?, completion: @escaping () -> Void) {
if (enableEmbeddedMessaging) {
retrieveEmbeddedMessages(completion: completion)
retrieveEmbeddedMessages(placementIds: placementIds, completion: completion)
}
}
}
6 changes: 5 additions & 1 deletion swift-sdk/Internal/api-client/ApiClient.swift
Original file line number Diff line number Diff line change
Expand Up @@ -301,7 +301,11 @@ extension ApiClient: ApiClientProtocol {
// MARK: - Embedded Messaging

func getEmbeddedMessages() -> Pending<PlacementsPayload, SendRequestError> {
let result = createRequestCreator().flatMap { $0.createGetEmbeddedMessagesRequest() }
return getEmbeddedMessages(placementIds: nil)
}

func getEmbeddedMessages(placementIds: [Int]?) -> Pending<PlacementsPayload, SendRequestError> {
let result = createRequestCreator().flatMap { $0.createGetEmbeddedMessagesRequest(placementIds: placementIds) }
return send(iterableRequestResult: result)
}

Expand Down
2 changes: 2 additions & 0 deletions swift-sdk/Internal/api-client/ApiClientProtocol.swift
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@ protocol ApiClientProtocol: AnyObject {

func getEmbeddedMessages() -> Pending<PlacementsPayload, SendRequestError>

func getEmbeddedMessages(placementIds: [Int]?) -> Pending<PlacementsPayload, SendRequestError>

@discardableResult func track(embeddedMessageReceived message: IterableEmbeddedMessage) -> Pending<SendRequestValue, SendRequestError>

@discardableResult func track(embeddedMessageClick message: IterableEmbeddedMessage, buttonIdentifier: String?, clickedUrl: String) -> Pending<SendRequestValue, SendRequestError>
Expand Down
13 changes: 9 additions & 4 deletions swift-sdk/Internal/api-client/Request/RequestCreator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -500,7 +500,7 @@ struct RequestCreator {

// MARK: - Embedded Messaging Request Calls

func createGetEmbeddedMessagesRequest() -> Result<IterableRequest, IterableError> {
func createGetEmbeddedMessagesRequest(placementIds: [Int]? = []) -> Result<IterableRequest, IterableError> {
if case .none = auth.emailOrUserId {
ITBError(Self.authMissingMessage)
return .failure(IterableError.general(description: Self.authMissingMessage))
Expand All @@ -514,6 +514,11 @@ struct RequestCreator {
args[JsonKey.Embedded.packageName] = packageName
}

if let placementIds = placementIds,
!placementIds.isEmpty {
args[JsonKey.placementIds] = placementIds
}

setCurrentUser(inDict: &args)

return .success(.get(createGetRequest(forPath: Const.Path.getEmbeddedMessages, withArgs: args as! [String: String])))
Expand Down Expand Up @@ -619,9 +624,9 @@ struct RequestCreator {
setCurrentUser(inDict: &body)

body.setValue(for: JsonKey.embeddedSessionId, value: [
"id": embeddedSessionId,
"start": IterableUtil.int(fromDate: sessionStartTime),
"end": IterableUtil.int(fromDate: sessionEndTime)
JsonKey.Embedded.Session.id: embeddedSessionId,
JsonKey.Embedded.Session.start: IterableUtil.int(fromDate: sessionStartTime),
JsonKey.Embedded.Session.end: IterableUtil.int(fromDate: sessionEndTime)
])

body.setValue(for: JsonKey.impressions, value: embeddedSession.impressions.compactMap { $0.asDictionary() })
Expand Down
4 changes: 4 additions & 0 deletions tests/unit-tests/BlankApiClient.swift
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,10 @@ class BlankApiClient: ApiClientProtocol {
Pending()
}

func getEmbeddedMessages(placementIds: [Int]?) -> Pending<PlacementsPayload, SendRequestError> {
return Pending()
}

func track(embeddedMessageReceived message: IterableEmbeddedMessage) -> Pending<SendRequestValue, SendRequestError> {
Pending()
}
Expand Down
52 changes: 49 additions & 3 deletions tests/unit-tests/EmbeddedManagerTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ final class EmbeddedManagerTests: XCTestCase {
XCTAssertEqual(message.metadata.placementId, 2, "Fetched message should have placementId 2")
}
}

// syncMessages
func testSyncMessagesSuccessful() {
let syncMessagesExpectation = expectation(description: "syncMessages should complete")
Expand Down Expand Up @@ -105,6 +105,40 @@ final class EmbeddedManagerTests: XCTestCase {
wait(for: [syncMessagesExpectation, delegateExpectation], timeout: 2)
}

func testSyncMessagesForSpecifiedPlacement() {
let mockApiClient = MockApiClient()
mockApiClient.populateMessages([
1: [IterableEmbeddedMessage(messageId: "1", placementId: 1)],
2: [IterableEmbeddedMessage(messageId: "2", placementId: 2),
IterableEmbeddedMessage(messageId: "3", placementId: 2)],
3: [IterableEmbeddedMessage(messageId: "4", placementId: 3)],
])
let manager = IterableEmbeddedManager(apiClient: mockApiClient,
urlDelegate: nil,
customActionDelegate: nil,
urlOpener: MockUrlOpener(),
allowedProtocols: [],
enableEmbeddedMessaging: true)

// Sync only placement 2
manager.syncMessages(placementIds: [2]) { }

// Verify we got updated messages for placement 2
let messagesForPlacement2 = manager.getMessages(for: 2)
XCTAssertEqual(messagesForPlacement2.count, 2, "Should have 2 messages for placementId 2")
for message in messagesForPlacement2 {
XCTAssertEqual(message.metadata.placementId, 2, "Fetched message should have placementId 2")
}

// Verify other placements are not synced
let messagesForPlacement1 = manager.getMessages(for: 1)
XCTAssertEqual(messagesForPlacement1.count, 0, "Should have no messages for placementId 1")

let messagesForPlacement3 = manager.getMessages(for: 3)
XCTAssertEqual(messagesForPlacement3.count, 0, "Should have no messages for placementId 3")
}


func testManagerReset() {
let syncMessagesExpectation = expectation(description: "syncMessages should complete")

Expand Down Expand Up @@ -352,7 +386,8 @@ final class EmbeddedManagerTests: XCTestCase {
private var newMessages = false
private var invalidApiKey = false
private var mockMessages: [Int: [IterableEmbeddedMessage]] = [:]

private var lastRequestedPlacementIds: [Int]?

func haveNewEmbeddedMessages() {
newMessages = true
}
Expand All @@ -367,13 +402,24 @@ final class EmbeddedManagerTests: XCTestCase {
}

override func getEmbeddedMessages() -> IterableSDK.Pending<IterableSDK.PlacementsPayload, IterableSDK.SendRequestError> {
return getEmbeddedMessages(placementIds: nil)
}

override func getEmbeddedMessages(placementIds: [Int]?) -> IterableSDK.Pending<IterableSDK.PlacementsPayload, IterableSDK.SendRequestError> {
lastRequestedPlacementIds = placementIds

if invalidApiKey {
return FailPending(error: IterableSDK.SendRequestError(reason: "Invalid API Key"))
}

if newMessages {
var filteredMessages = mockMessages
if let placementIds = placementIds, !placementIds.isEmpty {
filteredMessages = mockMessages.filter { placementIds.contains($0.key) }
}

var placements: [Placement] = []
for (placementId, messages) in mockMessages {
for (placementId, messages) in filteredMessages {
let placement = Placement(placementId: placementId, embeddedMessages: messages)
placements.append(placement)
}
Expand Down