Skip to content

Commit

Permalink
Merge pull request #849 from Iterable/feature/MOB-9746-Use-destinatio…
Browse files Browse the repository at this point in the history
…nUser-JWT-when-calling-merge

Added support for fetching new JWT prior to calling merge
  • Loading branch information
evantk91 authored Oct 30, 2024
2 parents 9a26368 + 49eb8f3 commit 9ed3cdd
Show file tree
Hide file tree
Showing 7 changed files with 515 additions and 56 deletions.
23 changes: 21 additions & 2 deletions sample-apps/swift-sample-app/swift-sample-app/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,28 @@ import UserNotifications
import IterableSDK

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
class AppDelegate: UIResponder, UIApplicationDelegate, IterableAuthDelegate {
func onAuthTokenRequested(completion: @escaping IterableSDK.AuthTokenRetrievalHandler) {
// ITBL: Set your actual secret.
let jwt = IterableTokenGenerator.generateJwtForUserId(
secret: "",
iat: Int(Date().timeIntervalSince1970),
exp: Int(Date().timeIntervalSince1970) + (24*60),
userId: IterableAPI.userId ?? "")
print(jwt)
completion(jwt)
}


func onAuthFailure(_ authFailure: IterableSDK.AuthFailure) {

}

var window: UIWindow?

// ITBL: Set your actual api key here.
let iterableApiKey = ""

func application(_: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// ITBL: Setup Notification
setupNotifications()
Expand All @@ -28,6 +44,8 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
config.urlDelegate = self
config.inAppDisplayInterval = 1
config.anonUserDelegate = self
config.enableAnonTracking = true
config.authDelegate = self
IterableAPI.initialize(apiKey: iterableApiKey,
launchOptions: launchOptions,
config: config)
Expand Down Expand Up @@ -177,3 +195,4 @@ extension AppDelegate: IterableCustomActionDelegate {
return false
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ class CoffeeListTableViewController: UITableViewController {
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.section == 0 {
let cell = tableView.dequeueReusableCell(withIdentifier: "anonymousUsageTrackCell", for: indexPath)
cell.textLabel?.text = IterableAPI.getAnonymousUsageTracked() ? "Tap to enable Anonymous Usage Track" : "Tap to disable Anonymous Usage Track"
cell.textLabel?.text = IterableAPI.getAnonymousUsageTracked() ? "Tap to disable Anonymous Usage Track" : "Tap to enable Anonymous Usage Track"
cell.textLabel?.numberOfLines = 0
cell.accessoryType = IterableAPI.getAnonymousUsageTracked() ? .checkmark : .none
return cell
Expand Down
8 changes: 8 additions & 0 deletions swift-sdk.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
18A3520C2C85BAF0007FED53 /* IsOneOfInNotOneOfCriteareaTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18A3520B2C85BAF0007FED53 /* IsOneOfInNotOneOfCriteareaTest.swift */; };
18BB8B7A2C64DC8D007EBF23 /* ComparatorTypeDoesNotEqualMatchTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18BB8B792C64DC8D007EBF23 /* ComparatorTypeDoesNotEqualMatchTest.swift */; };
18E23AE02C6CDE97002B2D92 /* CombinationLogicEventTypeCriteria.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18E23ADF2C6CDE97002B2D92 /* CombinationLogicEventTypeCriteria.swift */; };
18E5B5D12CC77BCE00A558EC /* IterableTokenGenerator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18E5B5D02CC77BCE00A558EC /* IterableTokenGenerator.swift */; };
18E5B5D32CC7853D00A558EC /* ValidateTokenForDestinationUserTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18E5B5D22CC7853D00A558EC /* ValidateTokenForDestinationUserTest.swift */; };
1CBFFE1A2A97AEEF00ED57EE /* EmbeddedManagerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1CBFFE162A97AEEE00ED57EE /* EmbeddedManagerTests.swift */; };
1CBFFE1B2A97AEEF00ED57EE /* EmbeddedMessagingProcessorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1CBFFE172A97AEEE00ED57EE /* EmbeddedMessagingProcessorTests.swift */; };
1CBFFE1C2A97AEEF00ED57EE /* EmbeddedSessionManagerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1CBFFE182A97AEEE00ED57EE /* EmbeddedSessionManagerTests.swift */; };
Expand Down Expand Up @@ -579,6 +581,8 @@
18A3520B2C85BAF0007FED53 /* IsOneOfInNotOneOfCriteareaTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IsOneOfInNotOneOfCriteareaTest.swift; sourceTree = "<group>"; };
18BB8B792C64DC8D007EBF23 /* ComparatorTypeDoesNotEqualMatchTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComparatorTypeDoesNotEqualMatchTest.swift; sourceTree = "<group>"; };
18E23ADF2C6CDE97002B2D92 /* CombinationLogicEventTypeCriteria.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CombinationLogicEventTypeCriteria.swift; sourceTree = "<group>"; };
18E5B5D02CC77BCE00A558EC /* IterableTokenGenerator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IterableTokenGenerator.swift; sourceTree = "<group>"; };
18E5B5D22CC7853D00A558EC /* ValidateTokenForDestinationUserTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ValidateTokenForDestinationUserTest.swift; sourceTree = "<group>"; };
1CBFFE162A97AEEE00ED57EE /* EmbeddedManagerTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EmbeddedManagerTests.swift; sourceTree = "<group>"; };
1CBFFE172A97AEEE00ED57EE /* EmbeddedMessagingProcessorTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EmbeddedMessagingProcessorTests.swift; sourceTree = "<group>"; };
1CBFFE182A97AEEE00ED57EE /* EmbeddedSessionManagerTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EmbeddedSessionManagerTests.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -1105,6 +1109,7 @@
AC72A0BF20CF4CB8004D7997 /* IterableAction.swift */,
ACF560E720E55A6B000AAC23 /* IterableActionContext.swift */,
AC6FDD8720F4372E005D811E /* IterableAPI.swift */,
18E5B5D02CC77BCE00A558EC /* IterableTokenGenerator.swift */,
AC72A0C620CF4CB9004D7997 /* IterableAppIntegration.swift */,
AC72A0C020CF4CB8004D7997 /* IterableAttributionInfo.swift */,
55DD207E26A0D83800773CC7 /* IterableAuthManagerProtocol.swift */,
Expand Down Expand Up @@ -1701,6 +1706,7 @@
181063DC2C994FA40078E0ED /* ValidateCustomEventUserUpdateAPITest.swift */,
181063DE2C9D51000078E0ED /* ValidateStoredEventCheckUnknownToKnownUserTest.swift */,
1802C00E2CA2C99E009DEA2B /* CombinationComplexCriteria.swift */,
18E5B5D22CC7853D00A558EC /* ValidateTokenForDestinationUserTest.swift */,
);
name = "anonymous-tracking-tests";
sourceTree = "<group>";
Expand Down Expand Up @@ -2216,6 +2222,7 @@
5555425028BED1B400DB5D20 /* KeychainWrapper.swift in Sources */,
9F0616412C9CA9D400FE2E6A /* IterableIdentityResolution.swift in Sources */,
AC81918A22713A400014955E /* AbstractDiffCalculator.swift in Sources */,
18E5B5D12CC77BCE00A558EC /* IterableTokenGenerator.swift in Sources */,
ACA95D2D275494A100AF4666 /* InboxViewRepresentable.swift in Sources */,
AC684A88222F4FDD00F29749 /* InAppDisplayer.swift in Sources */,
AC72A0D220CF4D12004D7997 /* IterableUtil.swift in Sources */,
Expand Down Expand Up @@ -2370,6 +2377,7 @@
5588DFA928C045AE000697D7 /* MockInAppFetcher.swift in Sources */,
55CC257B2462064F00A77FD5 /* InAppPresenterTests.swift in Sources */,
AC4BA00224163D8F007359F1 /* IterableHtmlMessageViewControllerTests.swift in Sources */,
18E5B5D32CC7853D00A558EC /* ValidateTokenForDestinationUserTest.swift in Sources */,
55B37FC822975A840042F13A /* InboxMessageViewModelTests.swift in Sources */,
182A2A152C661C9A002FF058 /* DataTypeComparatorSearchQueryCriteria.swift in Sources */,
55E6F462238E066400808BCE /* DeepLinkTests.swift in Sources */,
Expand Down
12 changes: 8 additions & 4 deletions swift-sdk/Internal/AuthManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -161,15 +161,19 @@ class AuthManager: IterableAuthManagerProtocol {
let isRefreshQueued = queueAuthTokenExpirationRefresh(retrievedAuthToken, onSuccess: onSuccess)
if !isRefreshQueued {
onSuccess?(authToken)
authToken = retrievedAuthToken
storeAuthToken()
} else {
authToken = retrievedAuthToken
storeAuthToken()
onSuccess?(authToken)
}
} else {
handleAuthFailure(failedAuthToken: nil, reason: .authTokenNull)
scheduleAuthTokenRefreshTimer(interval: getNextRetryInterval(), successCallback: onSuccess)
authToken = retrievedAuthToken
storeAuthToken()
}

authToken = retrievedAuthToken

storeAuthToken()
}

func handleAuthFailure(failedAuthToken: String?, reason: AuthFailureReason) {
Expand Down
108 changes: 59 additions & 49 deletions swift-sdk/Internal/InternalIterableAPI.swift
Original file line number Diff line number Diff line change
Expand Up @@ -133,83 +133,90 @@ final class InternalIterableAPI: NSObject, PushTrackerProtocol, AuthProvider {
func setEmail(_ email: String?, authToken: String? = nil, successHandler: OnSuccessHandler? = nil, failureHandler: OnFailureHandler? = nil, identityResolution: IterableIdentityResolution? = nil) {

ITBInfo()

let merge = identityResolution?.mergeOnAnonymousToKnown ?? config.identityResolution.mergeOnAnonymousToKnown
let replay = identityResolution?.replayOnVisitorToKnown ?? config.identityResolution.replayOnVisitorToKnown

if self._email == email && email != nil {
self.checkAndUpdateAuthToken(authToken)
return
}

if self._email == email {
return
}

self.logoutPreviousUser()

self._email = email
self._userId = nil

if config.enableAnonTracking, let email = email {
attemptAndProcessMerge(
merge: merge ?? true,
replay: replay ?? true,
destinationUser: email,
isEmail: true,
failureHandler: failureHandler
)
self.localStorage.userIdAnnon = nil

self.onLogin(authToken) { [weak self] in
guard let config = self?.config else {
return
}
let merge = identityResolution?.mergeOnAnonymousToKnown ?? config.identityResolution.mergeOnAnonymousToKnown
let replay = identityResolution?.replayOnVisitorToKnown ?? config.identityResolution.replayOnVisitorToKnown
if config.enableAnonTracking, let email = email {
self?.attemptAndProcessMerge(
merge: merge ?? true,
replay: replay ?? true,
destinationUser: email,
isEmail: true,
failureHandler: failureHandler
)
self?.localStorage.userIdAnnon = nil
}
}


self._successCallback = successHandler
self._failureCallback = failureHandler
self.storeIdentifierData()
self.onLogin(authToken)

}

func setUserId(_ userId: String?, authToken: String? = nil, successHandler: OnSuccessHandler? = nil, failureHandler: OnFailureHandler? = nil, isAnon: Bool = false, identityResolution: IterableIdentityResolution? = nil) {
ITBInfo()

let merge = identityResolution?.mergeOnAnonymousToKnown ?? config.identityResolution.mergeOnAnonymousToKnown
let replay = identityResolution?.replayOnVisitorToKnown ?? config.identityResolution.replayOnVisitorToKnown


if self._userId == userId && userId != nil {
self.checkAndUpdateAuthToken(authToken)
return
}

if self._userId == userId {
return
}

self.logoutPreviousUser()

self._email = nil
self._userId = userId

if config.enableAnonTracking {
if let userId = userId, userId != localStorage.userIdAnnon {
attemptAndProcessMerge(
merge: merge ?? true,
replay: replay ?? true,
destinationUser: userId,
isEmail: false,
failureHandler: failureHandler
)
self.onLogin(authToken) { [weak self] in
guard let config = self?.config else {
return
}

if !isAnon {
localStorage.userIdAnnon = nil
if config.enableAnonTracking {
if let userId = userId, userId != (self?.localStorage.userIdAnnon ?? "") {
let merge = identityResolution?.mergeOnAnonymousToKnown ?? config.identityResolution.mergeOnAnonymousToKnown
let replay = identityResolution?.replayOnVisitorToKnown ?? config.identityResolution.replayOnVisitorToKnown
self?.attemptAndProcessMerge(
merge: merge ?? true,
replay: replay ?? true,
destinationUser: userId,
isEmail: false,
failureHandler: failureHandler
)
}

if !isAnon {
self?.localStorage.userIdAnnon = nil
}
}
}

self._successCallback = successHandler
self._failureCallback = failureHandler
self.storeIdentifierData()
self.onLogin(authToken)

}

func logoutUser() {
logoutPreviousUser()
}
Expand All @@ -233,6 +240,7 @@ final class InternalIterableAPI: NSObject, PushTrackerProtocol, AuthProvider {
self.localStorage.anonymousUserEvents = nil
self.localStorage.anonymousSessions = nil
self.localStorage.anonymousUserUpdate = nil
self.localStorage.userIdAnnon = nil

if isAnonymousUsageTracked && config.enableAnonTracking {
ITBInfo("CONSENT GIVEN and ANON TRACKING ENABLED - Criteria fetched")
Expand Down Expand Up @@ -738,35 +746,34 @@ final class InternalIterableAPI: NSObject, PushTrackerProtocol, AuthProvider {
localStorage.userId = _userId
}

private func onLogin(_ authToken: String? = nil) {
private func onLogin(_ authToken: String? = nil, onloginSuccess onloginSuccessCallBack: (()->())? = nil) {
guard isSDKInitialized() else { return }

ITBInfo()

self.authManager.pauseAuthRetries(false)
if let authToken {
self.authManager.setNewToken(authToken)
completeUserLogin()
completeUserLogin(onloginSuccessCallBack: onloginSuccessCallBack)
} else if isEitherUserIdOrEmailSet() && config.authDelegate != nil {
requestNewAuthToken()
requestNewAuthToken(onloginSuccessCallBack: onloginSuccessCallBack)
} else {
completeUserLogin()
completeUserLogin(onloginSuccessCallBack: onloginSuccessCallBack)
}
}

private func requestNewAuthToken() {
private func requestNewAuthToken(onloginSuccessCallBack: (()->())? = nil) {
ITBInfo()

authManager.requestNewAuthToken(hasFailedPriorAuth: false, onSuccess: { [weak self] token in
if token != nil {
self?.completeUserLogin()
self?.completeUserLogin(onloginSuccessCallBack: onloginSuccessCallBack)
}
}, shouldIgnoreRetryPolicy: true)
}

private func completeUserLogin() {
ITBInfo()

private func completeUserLogin(onloginSuccessCallBack: (()->())? = nil) {
ITBInfo()
guard isSDKInitialized() else { return }

if config.autoPushRegistration {
Expand All @@ -776,6 +783,9 @@ final class InternalIterableAPI: NSObject, PushTrackerProtocol, AuthProvider {
}

_ = inAppManager.scheduleSync()
if onloginSuccessCallBack != nil {
onloginSuccessCallBack!()
}
}

private func retrieveIdentifierData() {
Expand Down
Loading

0 comments on commit 9ed3cdd

Please sign in to comment.