Skip to content

Commit 5ae99a6

Browse files
Merge pull request #76 from Iterable/feature/mob-310-custom-url
[MOB-310] - custom url schemes
2 parents 1e0e8f3 + c64a3a2 commit 5ae99a6

12 files changed

+168
-110
lines changed

Tests/common/CommonMocks.swift

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -262,7 +262,7 @@ class MockInAppDisplayer : InAppDisplayerProtocol {
262262
return showing
263263
}
264264

265-
func showInApp(message: IterableInAppMessage, callback: ITEActionBlock?) -> Bool {
265+
func showInApp(message: IterableInAppMessage, callback: ITBURLCallback?) -> Bool {
266266
if showing {
267267
return false
268268
}
@@ -273,20 +273,17 @@ class MockInAppDisplayer : InAppDisplayerProtocol {
273273
return true
274274
}
275275

276-
var onShowCallback: ((IterableInAppMessage, ITEActionBlock?) -> Void)?
276+
var onShowCallback: ((IterableInAppMessage, ITBURLCallback?) -> Void)?
277277

278278
// Mimics clicking a url
279-
func click(url: String) {
279+
func click(url: URL) {
280280
ITBInfo()
281281
showing = false
282-
if let (callbackUrl, _) = InAppHelper.getCallbackAndDestinationUrl(url: URL(string: url)!) {
283-
actionCallback?(callbackUrl)
284-
} else {
285-
actionCallback?(nil)
286-
}
282+
283+
actionCallback?(url)
287284
}
288285

289-
private var actionCallback: ITEActionBlock?
286+
private var actionCallback: ITBURLCallback?
290287

291288
private var showing = false
292289

Tests/swift-sdk-swift-tests/InAppHelperTests.swift

Lines changed: 21 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -518,31 +518,38 @@ class InAppHelperTests: XCTestCase {
518518
}
519519

520520
// nil host
521-
func testCallbackUrlParsingCustomScheme1() {
521+
func testCallbackUrlParsingAppleWebdataScheme1() {
522522
let url = URL(string: "applewebdata://")!
523-
XCTAssertNil(InAppHelper.getCallbackAndDestinationUrl(url: url))
523+
XCTAssertNil(InAppHelper.parse(inAppUrl: url))
524524
}
525525

526526

527-
func testCallbackUrlParsingCustomScheme2() {
527+
func testCallbackUrlParsingAppleWebdataScheme2() {
528528
let url = URL(string: "applewebdata://this-is-uuid/the-real-url")!
529-
let (callbackUrl, destinationUrl) = InAppHelper.getCallbackAndDestinationUrl(url: url)!
530-
XCTAssertEqual(callbackUrl, "the-real-url")
531-
XCTAssertEqual(destinationUrl, "the-real-url")
529+
let parsed = InAppHelper.parse(inAppUrl: url)!
530+
if case let InAppHelper.InAppClickedUrl.localResource(name: name) = parsed {
531+
XCTAssertEqual(name, "the-real-url")
532+
} else {
533+
XCTFail("could not parse")
534+
}
532535
}
533536

534-
func testCallbackUrlParsingIterableScheme() {
535-
let url = URL(string: "itbl://buyProduct")!
536-
let (callbackUrl, destinationUrl) = InAppHelper.getCallbackAndDestinationUrl(url: url)!
537-
XCTAssertEqual(callbackUrl, "buyProduct")
538-
XCTAssertEqual(destinationUrl, "itbl://buyProduct")
537+
func testCallbackUrlParsingCustomActionScheme() {
538+
let url = URL(string: "action://buyProduct")!
539+
if case let InAppHelper.InAppClickedUrl.customAction(name: name) = InAppHelper.parse(inAppUrl: url)! {
540+
XCTAssertEqual(name, "buyProduct")
541+
} else {
542+
XCTFail("Could not parse")
543+
}
539544
}
540545

541546
func testCallbackUrlParsingRegularScheme() {
542547
let url = URL(string: "https://host/path")!
543-
let (callbackUrl, destinationUrl) = InAppHelper.getCallbackAndDestinationUrl(url: url)!
544-
XCTAssertEqual(callbackUrl, "https://host/path")
545-
XCTAssertEqual(destinationUrl, "https://host/path")
548+
if case let InAppHelper.InAppClickedUrl.regularUrl(parsedUrl) = InAppHelper.parse(inAppUrl: url)! {
549+
XCTAssertEqual(parsedUrl, url)
550+
} else {
551+
XCTFail("Could not parse")
552+
}
546553
}
547554

548555
private static let apiKey = "zeeApiKey"

Tests/swift-sdk-swift-tests/InAppTests.swift

Lines changed: 26 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ class InAppTests: XCTestCase {
3030
XCTAssertEqual(IterableAPI.inAppManager.getMessages().count, 1)
3131
expectation1.fulfill()
3232
// now click the inApp
33-
mockInAppDisplayer.click(url: TestInAppPayloadGenerator.getClickUrl(index: 1))
33+
mockInAppDisplayer.click(url: TestInAppPayloadGenerator.getClickedUrl(index: 1))
3434
}
3535

3636
let mockUrlDelegate = MockUrlDelegate(returnValue: true)
@@ -62,7 +62,7 @@ class InAppTests: XCTestCase {
6262
let mockInAppDisplayer = MockInAppDisplayer()
6363
mockInAppDisplayer.onShowCallback = {(_, _) in
6464
expectation1.fulfill()
65-
mockInAppDisplayer.click(url: TestInAppPayloadGenerator.getClickUrl(index: 1))
65+
mockInAppDisplayer.click(url: TestInAppPayloadGenerator.getClickedUrl(index: 1))
6666
}
6767

6868
let config = IterableConfig()
@@ -95,22 +95,22 @@ class InAppTests: XCTestCase {
9595

9696
let mockInAppDisplayer = MockInAppDisplayer()
9797
mockInAppDisplayer.onShowCallback = {(message, _) in
98-
mockInAppDisplayer.click(url: TestInAppPayloadGenerator.getClickUrl(index: TestInAppPayloadGenerator.index(fromCampaignId: message.campaignId)))
98+
mockInAppDisplayer.click(url: TestInAppPayloadGenerator.getClickedUrl(index: TestInAppPayloadGenerator.index(fromCampaignId: message.campaignId)))
9999
expectation0.fulfill()
100100
}
101101

102102
var callOrder = [Int]()
103103
let urlDelegate = MockUrlDelegate(returnValue: true)
104104
urlDelegate.callback = {(url, _) in
105-
if url.absoluteString == TestInAppPayloadGenerator.getClickUrl(index: 1) {
105+
if url == TestInAppPayloadGenerator.getClickedUrl(index: 1) {
106106
callOrder.append(1)
107107
expectation1.fulfill()
108108
}
109-
if url.absoluteString == TestInAppPayloadGenerator.getClickUrl(index: 2) {
109+
if url == TestInAppPayloadGenerator.getClickedUrl(index: 2) {
110110
callOrder.append(2)
111111
expectation2.fulfill()
112112
}
113-
if url.absoluteString == TestInAppPayloadGenerator.getClickUrl(index: 3) {
113+
if url == TestInAppPayloadGenerator.getClickedUrl(index: 3) {
114114
callOrder.append(3)
115115
expectation3.fulfill()
116116
}
@@ -180,15 +180,15 @@ class InAppTests: XCTestCase {
180180

181181
let mockInAppSynchronizer = MockInAppSynchronizer()
182182
let mockUrlOpener = MockUrlOpener { (url) in
183-
XCTAssertEqual(url.absoluteString, TestInAppPayloadGenerator.getClickUrl(index: 1))
183+
XCTAssertEqual(url, TestInAppPayloadGenerator.getClickedUrl(index: 1))
184184
XCTAssertEqual(IterableAPI.inAppManager.getMessages().count, 0)
185185
expectation1.fulfill()
186186
}
187187

188188
let mockInAppDisplayer = MockInAppDisplayer()
189189
mockInAppDisplayer.onShowCallback = {(_, _) in
190190
XCTAssertEqual(IterableAPI.inAppManager.getMessages().count, 1)
191-
mockInAppDisplayer.click(url: TestInAppPayloadGenerator.getClickUrl(index: 1))
191+
mockInAppDisplayer.click(url: TestInAppPayloadGenerator.getClickedUrl(index: 1))
192192
}
193193

194194
IterableAPI.initializeForTesting(
@@ -210,7 +210,7 @@ class InAppTests: XCTestCase {
210210

211211
let mockInAppSynchronizer = MockInAppSynchronizer()
212212
let mockUrlOpener = MockUrlOpener { (url) in
213-
XCTAssertEqual(url.absoluteString, TestInAppPayloadGenerator.getClickUrl(index: 1))
213+
XCTAssertEqual(url, TestInAppPayloadGenerator.getClickedUrl(index: 1))
214214
let messages = IterableAPI.inAppManager.getMessages()
215215
// Message count is 0 because inApp is still being shown. It is just not opening external url on click.
216216
XCTAssertEqual(messages.count, 0)
@@ -220,7 +220,7 @@ class InAppTests: XCTestCase {
220220
let mockInAppDisplayer = MockInAppDisplayer()
221221
mockInAppDisplayer.onShowCallback = {(_, _) in
222222
XCTAssertEqual(IterableAPI.inAppManager.getMessages().count, 1)
223-
mockInAppDisplayer.click(url: TestInAppPayloadGenerator.getClickUrl(index: 1))
223+
mockInAppDisplayer.click(url: TestInAppPayloadGenerator.getClickedUrl(index: 1))
224224
}
225225

226226
let mockUrlDelegate = MockUrlDelegate(returnValue: true)
@@ -246,11 +246,11 @@ class InAppTests: XCTestCase {
246246

247247
let mockInAppDisplayer = MockInAppDisplayer()
248248
mockInAppDisplayer.onShowCallback = {(_, _) in
249-
mockInAppDisplayer.click(url: TestInAppPayloadGenerator.getClickUrl(index: 1))
249+
mockInAppDisplayer.click(url: TestInAppPayloadGenerator.getClickedUrl(index: 1))
250250
}
251251

252252
let mockUrlOpener = MockUrlOpener { (url) in
253-
XCTAssertEqual(url.absoluteString, TestInAppPayloadGenerator.getClickUrl(index: 1))
253+
XCTAssertEqual(url, TestInAppPayloadGenerator.getClickedUrl(index: 1))
254254
XCTAssertEqual(IterableAPI.inAppManager.getMessages().count, 0)
255255

256256
expectation2.fulfill()
@@ -272,7 +272,7 @@ class InAppTests: XCTestCase {
272272
XCTAssertEqual(messages.count, 1)
273273

274274
IterableAPI.inAppManager.show(message: messages[0], consume: true) { (clickedUrl) in
275-
XCTAssertEqual(clickedUrl, TestInAppPayloadGenerator.getClickUrl(index: 1))
275+
XCTAssertEqual(clickedUrl, TestInAppPayloadGenerator.getClickedUrl(index: 1))
276276
expectation1.fulfill()
277277
}
278278

@@ -287,11 +287,11 @@ class InAppTests: XCTestCase {
287287

288288
let mockInAppDisplayer = MockInAppDisplayer()
289289
mockInAppDisplayer.onShowCallback = {(_, _) in
290-
mockInAppDisplayer.click(url: TestInAppPayloadGenerator.getClickUrl(index: 1))
290+
mockInAppDisplayer.click(url: TestInAppPayloadGenerator.getClickedUrl(index: 1))
291291
}
292292

293293
let mockUrlOpener = MockUrlOpener { (url) in
294-
XCTAssertEqual(url.absoluteString, TestInAppPayloadGenerator.getClickUrl(index: 1))
294+
XCTAssertEqual(url, TestInAppPayloadGenerator.getClickedUrl(index: 1))
295295
let messages = IterableAPI.inAppManager.getMessages()
296296
XCTAssertEqual(messages.count, 1)
297297
XCTAssertEqual(messages[0].processed, true)
@@ -314,7 +314,7 @@ class InAppTests: XCTestCase {
314314
var messages = IterableAPI.inAppManager.getMessages()
315315
// Now show the first message, but don't consume
316316
IterableAPI.inAppManager.show(message: messages[0], consume: false) { (clickedUrl) in
317-
XCTAssertEqual(clickedUrl, TestInAppPayloadGenerator.getClickUrl(index: 1))
317+
XCTAssertEqual(clickedUrl, TestInAppPayloadGenerator.getClickedUrl(index: 1))
318318
expectation1.fulfill()
319319
}
320320

@@ -355,8 +355,8 @@ class InAppTests: XCTestCase {
355355
let messages = IterableAPI.inAppManager.getMessages()
356356
XCTAssertEqual(messages.count, 1)
357357

358-
IterableAPI.inAppManager.show(message: messages[0], consume: true) { (customActionName) in
359-
XCTAssertEqual(customActionName, TestInAppPayloadGenerator.getCustomActionName(index: 1))
358+
IterableAPI.inAppManager.show(message: messages[0], consume: true) { (customActionUrl) in
359+
XCTAssertEqual(customActionUrl, TestInAppPayloadGenerator.getCustomActionUrl(index: 1))
360360
expectation1.fulfill()
361361
}
362362

@@ -563,13 +563,13 @@ class InAppTests: XCTestCase {
563563
mockInAppDisplayer.onShowCallback = {(_, _) in
564564
if messageNumber == 1 {
565565
expectation1.fulfill()
566-
mockInAppDisplayer.click(url: TestInAppPayloadGenerator.getClickUrl(index: messageNumber))
566+
mockInAppDisplayer.click(url: TestInAppPayloadGenerator.getClickedUrl(index: messageNumber))
567567
} else if messageNumber == 2 {
568568
expectation2.fulfill()
569-
mockInAppDisplayer.click(url: TestInAppPayloadGenerator.getClickUrl(index: messageNumber))
569+
mockInAppDisplayer.click(url: TestInAppPayloadGenerator.getClickedUrl(index: messageNumber))
570570
} else if messageNumber == 3 {
571571
expectation3.fulfill()
572-
mockInAppDisplayer.click(url: TestInAppPayloadGenerator.getClickUrl(index: messageNumber))
572+
mockInAppDisplayer.click(url: TestInAppPayloadGenerator.getClickedUrl(index: messageNumber))
573573
} else {
574574
// unexpected message number
575575
XCTFail()
@@ -609,7 +609,7 @@ class InAppTests: XCTestCase {
609609
let mockInAppDisplayer = MockInAppDisplayer()
610610
mockInAppDisplayer.onShowCallback = {(_, _) in
611611
expectation1.fulfill()
612-
mockInAppDisplayer.click(url: TestInAppPayloadGenerator.getClickUrl(index: 1))
612+
mockInAppDisplayer.click(url: TestInAppPayloadGenerator.getClickedUrl(index: 1))
613613
}
614614

615615
IterableAPI.initializeForTesting(
@@ -645,25 +645,25 @@ class InAppTests: XCTestCase {
645645

646646
let mockInAppDisplayer = MockInAppDisplayer()
647647
mockInAppDisplayer.onShowCallback = {(message, _) in
648-
mockInAppDisplayer.click(url: TestInAppPayloadGenerator.getClickUrl(index: TestInAppPayloadGenerator.index(fromCampaignId: message.campaignId)))
648+
mockInAppDisplayer.click(url: TestInAppPayloadGenerator.getClickedUrl(index: TestInAppPayloadGenerator.index(fromCampaignId: message.campaignId)))
649649
expectation0.fulfill()
650650
}
651651

652652
var callOrder = [Int]()
653653
var callTimes = [Date]()
654654
let urlDelegate = MockUrlDelegate(returnValue: true)
655655
urlDelegate.callback = {(url, _) in
656-
if url.absoluteString == TestInAppPayloadGenerator.getClickUrl(index: 1) {
656+
if url == TestInAppPayloadGenerator.getClickedUrl(index: 1) {
657657
callTimes.append(Date())
658658
callOrder.append(1)
659659
expectation1.fulfill()
660660
}
661-
if url.absoluteString == TestInAppPayloadGenerator.getClickUrl(index: 2) {
661+
if url == TestInAppPayloadGenerator.getClickedUrl(index: 2) {
662662
callTimes.append(Date())
663663
callOrder.append(2)
664664
expectation2.fulfill()
665665
}
666-
if url.absoluteString == TestInAppPayloadGenerator.getClickUrl(index: 3) {
666+
if url == TestInAppPayloadGenerator.getClickedUrl(index: 3) {
667667
callTimes.append(Date())
668668
callOrder.append(3)
669669
expectation3.fulfill()

Tests/swift-sdk-swift-tests/TestInAppPayloadGenerator.swift

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -37,12 +37,12 @@ struct TestInAppPayloadGenerator {
3737
return "campaign\(index)"
3838
}
3939

40-
static func getClickUrl(index: Int) -> String {
41-
return "https://www.site\(index).com"
40+
static func getClickedUrl(index: Int) -> URL {
41+
return URL(string: getClickedLink(index: index))!
4242
}
43-
44-
static func getCustomActionUrl(index: Int) -> String {
45-
return "itbl://\(getCustomActionName(index: index))"
43+
44+
static func getCustomActionUrl(index: Int) -> URL {
45+
return URL(string: "action://\(getCustomActionName(index: index))")!
4646
}
4747

4848
static func getCustomActionName(index: Int) -> String {
@@ -54,15 +54,15 @@ struct TestInAppPayloadGenerator {
5454
}
5555

5656
static func createOneInAppDictWithUrl(index: Int, trigger: IterableInAppTrigger?, expiresAt: Date? = nil) -> [AnyHashable : Any] {
57-
return createOneInAppDict(withHref: getClickUrl(index: index), index: index, trigger: trigger, expiresAt: expiresAt)
57+
return createOneInAppDict(withHref: getClickedLink(index: index), index: index, trigger: trigger, expiresAt: expiresAt)
5858
}
5959

6060
static func createOneInAppDictWithUrl(index: Int, triggerType: IterableInAppTriggerType, expiresAt: Date? = nil) -> [AnyHashable : Any] {
61-
return createOneInAppDict(withHref: getClickUrl(index: index), index: index, trigger: trigger(fromTriggerType: triggerType), expiresAt: expiresAt)
61+
return createOneInAppDict(withHref: getClickedLink(index: index), index: index, trigger: trigger(fromTriggerType: triggerType), expiresAt: expiresAt)
6262
}
6363

6464
static func createOneInAppDictWithCustomAction(index: Int, triggerType: IterableInAppTriggerType) -> [AnyHashable : Any] {
65-
return createOneInAppDict(withHref: getCustomActionUrl(index: index), index: index, trigger: trigger(fromTriggerType: triggerType), expiresAt: nil)
65+
return createOneInAppDict(withHref: getCustomActionUrl(index: index).absoluteString, index: index, trigger: trigger(fromTriggerType: triggerType), expiresAt: nil)
6666
}
6767

6868
private static func createOneInAppDict(withHref href: String, index: Int, trigger: IterableInAppTrigger?, expiresAt: Date?) -> [AnyHashable : Any] {
@@ -95,4 +95,8 @@ struct TestInAppPayloadGenerator {
9595
private static func trigger(fromTriggerType triggerType: IterableInAppTriggerType) -> IterableInAppTrigger {
9696
return IterableInAppTrigger(dict: ["type" : String(describing: triggerType)])
9797
}
98+
99+
private static func getClickedLink(index: Int) -> String {
100+
return "https://www.site\(index).com"
101+
}
98102
}

host-app/ViewController.swift

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -63,9 +63,13 @@ class ViewController: UIViewController {
6363
let html = """
6464
<a href="http://website/resource#something">Click Me</a>
6565
"""
66-
InAppHelper.showIterableNotificationHTML(html) { (str) in
67-
ITBInfo("callback: \(str ?? "<nil>")")
68-
self.statusLbl.text = str
66+
InAppHelper.showIterableNotificationHTML(html) { (url) in
67+
guard let url = url else {
68+
ITBError("Could not find url")
69+
return
70+
}
71+
ITBInfo("callback: \(url)")
72+
self.statusLbl.text = url.absoluteString
6973
}
7074
}
7175

@@ -90,8 +94,8 @@ class ViewController: UIViewController {
9094
mockInAppSynchronizer.mockInAppPayloadFromServer(payload)
9195
let message = IterableAPI.inAppManager.getMessages()[0]
9296

93-
IterableAPI.inAppManager.show(message: message, consume: true) { (str) in
94-
self.statusLbl.text = str
97+
IterableAPI.inAppManager.show(message: message, consume: true) { (url) in
98+
self.statusLbl.text = url!.absoluteString
9599
}
96100
}
97101

@@ -120,8 +124,8 @@ class ViewController: UIViewController {
120124
mockInAppSynchronizer.mockInAppPayloadFromServer(payload)
121125
let message = IterableAPI.inAppManager.getMessages()[0]
122126

123-
IterableAPI.inAppManager.show(message: message, consume: true) { (str) in
124-
self.statusLbl.text = str
127+
IterableAPI.inAppManager.show(message: message, consume: true) { (url) in
128+
self.statusLbl.text = url!.absoluteString
125129
}
126130
}
127131

0 commit comments

Comments
 (0)