很多公司為了盈利,往往會在應用或網站中開放一些廣告位以實現盈利的目的,廣告鏈接內容往往是不可控,例如有些網頁頂部會有個提示條“下載APP”,這樣的問題在微信中他們也會攔截掉,那我們如何讓用戶點擊“下載APP”按鈕無法跳轉App Store中去下載呢?
一、網頁如何實現跳轉App Store
跳轉App Store協議:
(https)|(itms-apps)://itunes.apple.com/app/id{appID}
js應用:
下面方法最終也會轉為itms-appss://協議
window.location.;
或者直接使用應用跳轉協議
window.location.href = "itms-apps://itunes.apple.com/app/id{appID}";
iOS 實現跳轉:
itms-apps://協議是不能直接跳轉的,需要借助openURL:方法才能跳轉到應用商店,我們在下面方法可以實現跳轉App Store、撥打電話、調用第三方應用等功能
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler {
NSURLRequest *request = navigationAction.request;
NSString *scheme = [request.URL scheme];
if (![scheme isEqualToString:@"https"] && ![scheme isEqualToString:@"http"]) {
decisionHandler(WKNavigationActionPolicyCancel);
[[UIApplication sharedApplication] openURL:request.URL options:@{UIApplicationOpenURLOptionUniversalLinksOnly:@NO} completionHandler:^(BOOL success) {
}];
return;
}
decisionHandler(WKNavigationActionPolicyAllow);
}
二、如何攔截
都知道它是怎么跳轉的,攔截感覺很簡單了
方法一
不實現- (void)webView:decidePolicyForNavigationAction:decisionHandler:代理方法
方法二
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler {
NSURLRequest *request = navigationAction.request;
NSString *scheme = [request.URL scheme];
if (![scheme isEqualToString:@"https"] && ![scheme isEqualToString:@"http"]) {
decisionHandler(WKNavigationActionPolicyCancel);
if ([scheme hasPrefix:@"itms-apps://"] || [scheme hasPrefix:@"itms-appss://"]) return;
[[UIApplication sharedApplication] openURL:request.URL options:@{UIApplicationOpenURLOptionUniversalLinksOnly:@NO} completionHandler:^(BOOL success) {
}];
return;
}
decisionHandler(WKNavigationActionPolicyAllow);
}
上面這種做法會攔截所有的跳轉App Store請求,但是我們想要某些可以跳轉,這個時候我們需要一個白名單,如果appId在跳轉白名單內就可以跳轉。
方法三
有的時候我們能會有多個WebView來展示網頁,在每個網頁處理起來就會有很多重復的代碼。另外一種方法就是使用MethodSizzling來實現攔截
#import "UIApplication+OpenUrlBlock.h"
@implementation UIApplication (OpenUrlBlock)
+ (void)load {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
SEL originalSelector = @selector(openURL:options:completionHandler:);
SEL swizzledSelector = @selector(swiz_openURL:options:completionHandler:);
[self swizzlingInClass:[self class] originalSelector:originalSelector swizzledSelector:swizzledSelector];
SEL originalSelector2 = @selector(openURL:);
SEL swizzledSelector2 = @selector(swiz_openURL:);
[self swizzlingInClass:[self class] originalSelector:originalSelector2 swizzledSelector:swizzledSelector2];
});
}
+ (void)swizzlingInClass:(Class)cls originalSelector:(SEL)originalSelector swizzledSelector:(SEL)swizzledSelector {
Class class = cls;
Method originalMethod = class_getInstanceMethod(class, originalSelector);
Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector);
BOOL didAddMethod =
class_addMethod(class,
originalSelector,
method_getImplementation(swizzledMethod),
method_getTypeEncoding(swizzledMethod));
if (didAddMethod) {
class_replaceMethod(class,
swizzledSelector,
method_getImplementation(originalMethod),
method_getTypeEncoding(originalMethod));
} else {
method_exchangeImplementations(originalMethod, swizzledMethod);
}
}
- (void)swiz_openURL:(NSURL*)url options:(NSDictionary<UIApplicationOpenExternalURLOptionsKey, id> *)options completionHandler:(void (^)(BOOL success))completion {
NSLog(@"調用openURL:options:completionHandler方法打開:%@", url.absoluteString);
NSURL *filtrateUrl = [self filtrateDowloadWithUrl:url];
[self swiz_openURL:filtrateUrl options:options completionHandler:completion];
}
- (BOOL)swiz_openURL:(NSURL*)url {
NSLog(@"調用openURL方法打開:%@", url.absoluteString);
NSURL *filtrateUrl = [self filtrateDowloadWithUrl:url];
return [self swiz_openURL:filtrateUrl];
}
// 過濾非白名單應用,不讓去跳轉下載
- (NSURL *)filtrateDowloadWithUrl:(NSURL *)url {
NSURL *filtrateUrl = url;
if ([url.absoluteString hasPrefix:@"itms-apps://"] || [url.absoluteString hasPrefix:@"itms-appss://"]) {
if (![self isAppDowloadWithUrl:url]) {
filtrateUrl = [NSURL URLWithString:@""];
}
}
return filtrateUrl;
}
// 攔截openUrl判斷應用是否可以下載
- (BOOL)isAppDowloadWithUrl:(NSURL *)url {
NSArray *whiteList = [self appDowloadWhiteList];
__block BOOL isAppDowload = NO;
[whiteList enumerateObjectsUsingBlock:^(NSDictionary *obj, NSUInteger idx, BOOL *stop) {
NSString *appId = obj[@"appId"];
if ([url.absoluteString containsString:appId]) {
isAppDowload = YES;
*stop = YES;
return;
}
}];
return isAppDowload;
}
- (NSArray *)appDowloadWhiteList {
NSString *filePath = [[NSBundle mainBundle] pathForResource:@"AppDowload" ofType:@"plist"];
NSArray *ary = [NSArray arrayWithContentsOfFile:filePath];
return ary;
}
@end
應用白名單plist文件
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<array>
<dict>
<key>appName</key>
<string>應用名稱</string>
<key>appId</key>
<string>應用id</string>
</dict>
</array>
</plist>
總結
- 如果提供給外部網頁加載WebView很少,還是建議使用第二種在代理方法內攔截
- 使用MethodSizzling雖然在WebView中不用寫任何代碼,但是同樣存在出現問題難排查情況