美文网首页工作生活
iOS 拦截第三网页下载应用

iOS 拦截第三网页下载应用

作者: Wynter_Wang | 来源:发表于2019-07-04 19:21 被阅读0次

很多公司为了盈利,往往会在应用或网站中开放一些广告位以实现盈利的目的,广告链接内容往往是不可控,例如有些网页顶部会有个提示条“下载APP”,这样的问题在微信中他们也会拦截掉,那我们如何让用户点击“下载APP”按钮无法跳转App Store中去下载呢?

一、网页如何实现跳转App Store

跳转App Store协议:


(https)|(itms-apps)://itunes.apple.com/app/id{appID}

js应用:

下面方法最终也会转为itms-appss://协议


window.location.href = "https://itunes.apple.com/us/app/appName/id{appID}"?mt=8";

或者直接使用应用跳转协议

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中不用写任何代码,但是同样存在出现问题难排查情况

相关文章

网友评论

    本文标题:iOS 拦截第三网页下载应用

    本文链接:https://www.haomeiwen.com/subject/feqrhctx.html