Skip to content

Commit 965be64

Browse files
authored
MOB-11490 - Fix redirect issue with deeplinks (#915)
1 parent 048d815 commit 965be64

File tree

4 files changed

+481
-1
lines changed

4 files changed

+481
-1
lines changed

swift-sdk.xcodeproj/project.pbxproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
00B6FAD1210E8D90007535CF /* dev-1.mobileprovision in Resources */ = {isa = PBXBuildFile; fileRef = 00B6FAD0210E8D90007535CF /* dev-1.mobileprovision */; };
1313
00CB31B621096129004ACDEC /* TestUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 00CB31B4210960C4004ACDEC /* TestUtils.swift */; };
1414
092D01942D3038F600E3066A /* NotificationObserverTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 092D01932D3038F600E3066A /* NotificationObserverTests.swift */; };
15+
09876F3D2DF1D0290051F047 /* RedirectNetworkSessionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09876F3C2DF1D0290051F047 /* RedirectNetworkSessionTests.swift */; };
1516
1CBFFE1A2A97AEEF00ED57EE /* EmbeddedManagerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1CBFFE162A97AEEE00ED57EE /* EmbeddedManagerTests.swift */; };
1617
1CBFFE1B2A97AEEF00ED57EE /* EmbeddedMessagingProcessorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1CBFFE172A97AEEE00ED57EE /* EmbeddedMessagingProcessorTests.swift */; };
1718
1CBFFE1C2A97AEEF00ED57EE /* EmbeddedSessionManagerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1CBFFE182A97AEEE00ED57EE /* EmbeddedSessionManagerTests.swift */; };
@@ -547,6 +548,7 @@
547548
00B6FAD0210E8D90007535CF /* dev-1.mobileprovision */ = {isa = PBXFileReference; lastKnownFileType = file; path = "dev-1.mobileprovision"; sourceTree = "<group>"; };
548549
00CB31B4210960C4004ACDEC /* TestUtils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestUtils.swift; sourceTree = "<group>"; };
549550
092D01932D3038F600E3066A /* NotificationObserverTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationObserverTests.swift; sourceTree = "<group>"; };
551+
09876F3C2DF1D0290051F047 /* RedirectNetworkSessionTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RedirectNetworkSessionTests.swift; sourceTree = "<group>"; };
550552
1CBFFE162A97AEEE00ED57EE /* EmbeddedManagerTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EmbeddedManagerTests.swift; sourceTree = "<group>"; };
551553
1CBFFE172A97AEEE00ED57EE /* EmbeddedMessagingProcessorTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EmbeddedMessagingProcessorTests.swift; sourceTree = "<group>"; };
552554
1CBFFE182A97AEEE00ED57EE /* EmbeddedSessionManagerTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EmbeddedSessionManagerTests.swift; sourceTree = "<group>"; };
@@ -1283,6 +1285,7 @@
12831285
AC3A3029262EE04400425435 /* deep-linking-tests */ = {
12841286
isa = PBXGroup;
12851287
children = (
1288+
09876F3C2DF1D0290051F047 /* RedirectNetworkSessionTests.swift */,
12861289
55E6F45E238E066400808BCE /* DeepLinkTests.swift */,
12871290
);
12881291
name = "deep-linking-tests";
@@ -2228,6 +2231,7 @@
22282231
AC776DA4211A17C700C27C27 /* IterableRequestUtilTests.swift in Sources */,
22292232
ACAA816E231163660035C743 /* RequestCreatorTests.swift in Sources */,
22302233
ACE34AB5213776CB00691224 /* LocalStorageTests.swift in Sources */,
2234+
09876F3D2DF1D0290051F047 /* RedirectNetworkSessionTests.swift in Sources */,
22312235
55B37FEE229F59290042F13A /* InAppPersistenceTests.swift in Sources */,
22322236
8A272FD02DD3775800634559 /* IterableDataRegionObjCTests.m in Sources */,
22332237
AC6FDD8C20F56309005D811E /* InAppParsingTests.swift in Sources */,

swift-sdk/Internal/Network/NetworkSession.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ extension RedirectNetworkSession: URLSessionDelegate, URLSessionTaskDelegate {
133133
}
134134

135135
delegate?.onRedirect(deepLinkLocation: deepLinkLocation, campaignId: campaignId, templateId: templateId, messageId: messageId)
136-
completionHandler(nil)
136+
completionHandler(request)
137137
}
138138

139139
private func number(fromString str: String) -> NSNumber {

tests/unit-tests/DeepLinkTests.swift

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,94 @@ class DeepLinkTests: XCTestCase {
182182
private func createCookieValue(nameValuePairs values: Any...) -> String {
183183
values.take(2).map { "\($0[0])=\($0[1])" }.joined(separator: ";,")
184184
}
185+
186+
// MARK: - GreenFi SMS Deep Link Tests
187+
188+
func testGreenFiSMSDeepLinkRedirect() {
189+
let expectation1 = expectation(description: "Deep link resolves successfully")
190+
let expectation2 = expectation(description: "Attribution info extracted")
191+
192+
let greenfiSmsUrl = "https://links.greenfi.com/a/JsvVI"
193+
let destinationUrl = "https://app.greenfi.com/dashboard"
194+
let campaignId = 123456
195+
let templateId = 789012
196+
let messageId = "sms-campaign-123"
197+
198+
let mockUrlDelegate = MockUrlDelegate(returnValue: true)
199+
mockUrlDelegate.callback = { url, context in
200+
XCTAssertEqual(url.absoluteString, destinationUrl)
201+
XCTAssertEqual(context.action.type, IterableAction.actionTypeOpenUrl)
202+
XCTAssertTrue(Thread.isMainThread)
203+
expectation1.fulfill()
204+
}
205+
206+
// Create network session that simulates GreenFi's 303 redirect response
207+
let networkSession = MockNetworkSession()
208+
networkSession.responseCallback = { _ in
209+
MockNetworkSession.MockResponse(
210+
statusCode: 303, // GreenFi returns 303 redirect
211+
data: Dictionary<AnyHashable, Any>().toJsonData(),
212+
delay: 0.0,
213+
error: nil,
214+
headerFields: [
215+
"Location": destinationUrl,
216+
"Set-Cookie": self.createCookieValue(nameValuePairs: "iterableEmailCampaignId", campaignId, "iterableTemplateId", templateId, "iterableMessageId", messageId),
217+
]
218+
)
219+
}
220+
221+
let networkSessionProvider = MockRedirectNetworkSessionProvider(networkSession: networkSession)
222+
let deepLinkManager = DeepLinkManager(redirectNetworkSessionProvider: networkSessionProvider)
223+
224+
let (isIterableLink, attributionInfoFuture) = deepLinkManager.handleUniversalLink(
225+
URL(string: greenfiSmsUrl)!,
226+
urlDelegate: mockUrlDelegate,
227+
urlOpener: MockUrlOpener()
228+
)
229+
230+
XCTAssertTrue(isIterableLink, "GreenFi URL should be recognized as Iterable deep link")
231+
232+
attributionInfoFuture.onSuccess { attributionInfo in
233+
XCTAssertNotNil(attributionInfo, "Should extract attribution info from 303 response")
234+
XCTAssertEqual(attributionInfo?.campaignId, NSNumber(value: campaignId))
235+
XCTAssertEqual(attributionInfo?.templateId, NSNumber(value: templateId))
236+
XCTAssertEqual(attributionInfo?.messageId, messageId)
237+
expectation2.fulfill()
238+
}
239+
240+
wait(for: [expectation1, expectation2], timeout: testExpectationTimeout)
241+
}
242+
243+
func testGreenFiDeepLinkWithoutRedirect() {
244+
let expectation1 = expectation(description: "Deep link handled without redirect")
245+
246+
let greenfiSmsUrl = "https://links.greenfi.com/a/JsvVI"
247+
248+
let mockUrlDelegate = MockUrlDelegate(returnValue: true)
249+
mockUrlDelegate.callback = { url, context in
250+
// When no redirect occurs, should get original URL
251+
XCTAssertEqual(url.absoluteString, greenfiSmsUrl)
252+
XCTAssertEqual(context.action.type, IterableAction.actionTypeOpenUrl)
253+
expectation1.fulfill()
254+
}
255+
256+
// Use no-redirect provider to simulate timeout/failure scenario
257+
let deepLinkManager = DeepLinkManager(redirectNetworkSessionProvider: createNoRedirectNetworkSessionProvider())
258+
259+
let (isIterableLink, attributionInfoFuture) = deepLinkManager.handleUniversalLink(
260+
URL(string: greenfiSmsUrl)!,
261+
urlDelegate: mockUrlDelegate,
262+
urlOpener: MockUrlOpener()
263+
)
264+
265+
XCTAssertTrue(isIterableLink, "GreenFi URL should be recognized as Iterable deep link")
266+
267+
attributionInfoFuture.onSuccess { attributionInfo in
268+
XCTAssertNil(attributionInfo, "Should not have attribution info when redirect fails")
269+
}
270+
271+
wait(for: [expectation1], timeout: testExpectationTimeout)
272+
}
185273
}
186274

187275
private struct MockNoRedirectNetworkSessionProvider: RedirectNetworkSessionProvider {

0 commit comments

Comments
 (0)