Skip to content

Commit e5a4972

Browse files
authored
Handle App Store links in Web and Rich Interstitials (#388)
1 parent a96d68e commit e5a4972

File tree

4 files changed

+135
-0
lines changed

4 files changed

+135
-0
lines changed

Example/Leanplum-SDK.xcodeproj/project.pbxproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@
9393
65E189C421643631005E6B93 /* LPRequestSenderTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 65E189C321643631005E6B93 /* LPRequestSenderTest.m */; };
9494
65E189C6216BDB82005E6B93 /* LPRequestFactoryTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 65E189C5216BDB82005E6B93 /* LPRequestFactoryTest.m */; };
9595
65E53E982148786C00A05040 /* LPCountAggregatorTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 65E53E962148786C00A05040 /* LPCountAggregatorTest.m */; };
96+
6AFFF5CB24BE0960009E68DB /* LPWebInterstitialViewControllerTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 6AFFF5CA24BE0960009E68DB /* LPWebInterstitialViewControllerTest.m */; };
9697
873B8AEB1B1F5CCA007FD442 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 873B8AEA1B1F5CCA007FD442 /* Main.storyboard */; };
9798
9CB691DE1F15FFF5002D83D8 /* batch_response.json in Resources */ = {isa = PBXBuildFile; fileRef = 9CB691DD1F15FFF5002D83D8 /* batch_response.json */; };
9899
9CB691DF1F15FFFF002D83D8 /* batch_response.json in Resources */ = {isa = PBXBuildFile; fileRef = 9CB691DD1F15FFF5002D83D8 /* batch_response.json */; };
@@ -207,6 +208,7 @@
207208
65E189C321643631005E6B93 /* LPRequestSenderTest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = LPRequestSenderTest.m; sourceTree = "<group>"; };
208209
65E189C5216BDB82005E6B93 /* LPRequestFactoryTest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = LPRequestFactoryTest.m; sourceTree = "<group>"; };
209210
65E53E962148786C00A05040 /* LPCountAggregatorTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LPCountAggregatorTest.m; sourceTree = "<group>"; };
211+
6AFFF5CA24BE0960009E68DB /* LPWebInterstitialViewControllerTest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = LPWebInterstitialViewControllerTest.m; sourceTree = "<group>"; };
210212
73B565AA61D6B6A4E92607C4 /* Pods-Leanplum-SDK_Tests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Leanplum-SDK_Tests.release.xcconfig"; path = "Pods/Target Support Files/Pods-Leanplum-SDK_Tests/Pods-Leanplum-SDK_Tests.release.xcconfig"; sourceTree = "<group>"; };
211213
7B3A029531D9DAB706B77C73 /* Pods_Leanplum_tvOS_SDK_Example.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Leanplum_tvOS_SDK_Example.framework; sourceTree = BUILT_PRODUCTS_DIR; };
212214
84A3C33C701600A874B8C63F /* README.md */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = net.daringfireball.markdown; name = README.md; path = ../README.md; sourceTree = "<group>"; };
@@ -276,6 +278,7 @@
276278
07E5C86A1F052B7800A4B092 /* Classes */ = {
277279
isa = PBXGroup;
278280
children = (
281+
6AFFF5CA24BE0960009E68DB /* LPWebInterstitialViewControllerTest.m */,
279282
A86C8CF22405E23E003F5E4E /* Snapshot Tests */,
280283
07E5C86F1F052B7800A4B092 /* Extensions */,
281284
07E5C8841F052B7800A4B092 /* Utilities */,
@@ -817,6 +820,7 @@
817820
A8F4479E2449769000F6978A /* LPNetworkOperationTest.m in Sources */,
818821
A86C8D02240844C7003F5E4E /* LPConfirmMessageSnapshotTest.m in Sources */,
819822
07E5C8B11F052B7800A4B092 /* LPNetworkEngine+Category.m in Sources */,
823+
6AFFF5CB24BE0960009E68DB /* LPWebInterstitialViewControllerTest.m in Sources */,
820824
07E5C8B61F052B7800A4B092 /* LeanplumTest.m in Sources */,
821825
9E53F6E1247438440097955F /* LPPushNotificationsManagerTest.m in Sources */,
822826
A824579A2411CB600044B1EB /* LPWebInterstitialMessageSnapshotTest.m in Sources */,
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
//
2+
// LPWebInterstitialViewControllerTest.m
3+
// Leanplum-SDK_Tests
4+
//
5+
// Created by Nikola Zagorchev on 14.07.20.
6+
// Copyright © 2020 Leanplum. All rights reserved.
7+
//
8+
9+
#import <XCTest/XCTest.h>
10+
#import <OCMock/OCMock.h>
11+
#import "LPWebInterstitialViewController.h"
12+
#import "LPMessageTemplateConstants.h"
13+
#import "Leanplum+Extensions.h"
14+
#import "LeanplumHelper.h"
15+
16+
/*
17+
* Tests WebView delegate methods of LPWebInterstitialViewController
18+
*/
19+
@interface LPWebInterstitialViewControllerTest : XCTestCase
20+
21+
@end
22+
23+
@implementation LPWebInterstitialViewControllerTest
24+
25+
- (void)setUp
26+
{
27+
[super setUp];
28+
}
29+
30+
- (void)tearDown
31+
{
32+
[super tearDown];
33+
}
34+
35+
// Blocks for decidePolicyForNavigationAction
36+
typedef void (^AfterBlock)(UIApplication *mockApplication, WKNavigationActionPolicy policy);
37+
typedef void (^BeforeBlock)(UIApplication *mockApplication);
38+
39+
/*
40+
* Executes the WKWebView decidePolicyForNavigationAction
41+
* @param url The URL passed to the WKWebView for the WKNavigationAction
42+
* @param initialPolicy The action policy
43+
* @param beforeBlock Test block to execute before calling decidePolicyForNavigationAction
44+
* @param afterBlock Test block to execute after calling decidePolicyForNavigationAction
45+
*/
46+
- (void) execute_decidePolicyForNavigationAction:(NSURL *)url withInitialPolicy:(WKNavigationActionPolicy)initialPolicy withBeforeBlock:(BeforeBlock)beforeBlock withAfterBlock:(AfterBlock)afterBlock
47+
{
48+
LPWebInterstitialViewController *viewController = [LPWebInterstitialViewController instantiateFromStoryboard];
49+
WKWebView *currentWebView;
50+
for (id view in viewController.view.subviews) {
51+
if ([view isMemberOfClass:WKWebView.class]) {
52+
currentWebView = view;
53+
}
54+
}
55+
56+
LPActionContext *context = [LPActionContext actionContextWithName:LPMT_WEB_INTERSTITIAL_NAME args:@{
57+
LPMT_ARG_URL_CLOSE: LPMT_DEFAULT_CLOSE_URL
58+
} messageId:0];
59+
viewController.context = context;
60+
61+
NSURLRequest *request = [NSURLRequest requestWithURL:url];
62+
id action = OCMPartialMock([[WKNavigationAction alloc] init]);
63+
id reqMock = OCMStub([action request]);
64+
[reqMock andReturn:request];
65+
__block WKNavigationActionPolicy policy = WKNavigationActionPolicyAllow;
66+
void (^decisionBlock)(WKNavigationActionPolicy) = ^(WKNavigationActionPolicy dPolicy){
67+
policy = dPolicy;
68+
};
69+
70+
id mockApplication = OCMClassMock([UIApplication class]);
71+
OCMStub([mockApplication sharedApplication]).andReturn(mockApplication);
72+
73+
if (beforeBlock != nil) {
74+
beforeBlock(mockApplication);
75+
}
76+
77+
[viewController webView:currentWebView decidePolicyForNavigationAction:action decisionHandler:decisionBlock];
78+
79+
if (afterBlock != nil) {
80+
afterBlock(mockApplication, policy);
81+
}
82+
}
83+
84+
- (void) test_app_store_url
85+
{
86+
NSString *urlAppStore = [NSString stringWithFormat:@"%@://itunes.apple.com/us/app/id", LPMT_APP_STORE_SCHEMA];
87+
NSURL *url = [NSURL URLWithString:urlAppStore];
88+
WKNavigationActionPolicy expectedPolicy = WKNavigationActionPolicyCancel;
89+
[self execute_decidePolicyForNavigationAction:url withInitialPolicy: !expectedPolicy withBeforeBlock:nil withAfterBlock:^(UIApplication *mockApplication, WKNavigationActionPolicy policy){
90+
#if TARGET_IPHONE_SIMULATOR
91+
OCMVerify([mockApplication canOpenURL:[OCMArg any]]);
92+
#elif TARGET_OS_IPHONE
93+
OCMVerify([mockApplication canOpenURL:[OCMArg any]]);
94+
OCMVerify([mockApplication openURL:[OCMArg any]]);
95+
#endif
96+
97+
XCTAssertEqual(policy, expectedPolicy);
98+
}];
99+
}
100+
101+
- (void) test_default_url
102+
{
103+
NSURL *url = [NSURL URLWithString:LPMT_DEFAULT_URL];
104+
WKNavigationActionPolicy expectedPolicy = WKNavigationActionPolicyAllow;
105+
[self execute_decidePolicyForNavigationAction:url withInitialPolicy: !expectedPolicy withBeforeBlock:^(UIApplication *mockApplication){
106+
OCMReject([mockApplication openURL:[OCMArg any]]);
107+
} withAfterBlock:^(UIApplication *mockApplication, WKNavigationActionPolicy policy){
108+
XCTAssertEqual(policy, WKNavigationActionPolicyAllow);
109+
}];
110+
}
111+
@end

Leanplum-SDK/Classes/MessageTemplates/LPMessageTemplateConstants.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,8 @@
8080
#define LPMT_ICON_FILE_PREFIX @"__iOSAppIcon-"
8181
#define LPMT_ICON_PRIMARY_NAME @"PrimaryIcon"
8282

83+
#define LPMT_APP_STORE_SCHEMA @"itms-apps"
84+
8385
#define LPMT_DEFAULT_CENTER_POPUP_WIDTH 300
8486
#define LPMT_DEFAULT_CENTER_POPUP_HEIGHT 250
8587

Leanplum-SDK/Classes/MessageTemplates/ViewControllers/LPWebInterstitialViewController.m

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,24 @@ - (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigati
229229
NSString *url = [navigationAction request].URL.absoluteString;
230230
NSDictionary *queryComponents = [self queryComponentsFromUrl:url];
231231

232+
// Handle AppStore links
233+
// Example URL: itms-apps://itunes.apple.com/us/app/id
234+
NSURL *navigationUrl = [navigationAction request].URL;
235+
if ([navigationUrl.scheme isEqualToString:LPMT_APP_STORE_SCHEMA])
236+
{
237+
UIApplication *app = [UIApplication sharedApplication];
238+
if ([app canOpenURL:navigationUrl])
239+
{
240+
[self.webView stopLoading];
241+
[app openURL:[NSURL URLWithString:url]];
242+
decisionHandler(WKNavigationActionPolicyCancel);
243+
return;
244+
} else{
245+
decisionHandler(WKNavigationActionPolicyCancel);
246+
return;
247+
}
248+
}
249+
232250
if ([url rangeOfString:[context stringNamed:LPMT_ARG_URL_CLOSE]].location != NSNotFound) {
233251
[self dismiss:YES];
234252
if (queryComponents[@"result"]) {

0 commit comments

Comments
 (0)