iOS开发踩坑

WKWebView的网络拦截问题

2018-05-10  本文已影响0人  mrChan1234

利用NSURLProtocol拦截WKWebView的请求
我们知道 ,ios 8.0以后,apple给出了一个WKWebView来替换 UIWebView,前者比后者在加载速度方面优化了很多,但是也有不少坑点,比如在拦截wkwebView的请求上,apple始终没有给出明确的API供开发者使用,正常情况下,我们自定义一个NSURLProtocol类,然后在AppDelegate里面register一波,就可以拦截到app内部所有的网络请求,但是你会发现,wkwebView并不吃这一套,what the fuck!,这一点在网上有人说wkwebView的请求是在单独的进程里面,为了性能方面的考虑,所以不走NSURLProtocol,但是通过打断点会发现,它会走一下+ (BOOL)canInitWithRequest:(NSURLRequest *)request,然而这就尴尬了,为啥他会走一下,然后就一直不走了呢?于是我开始去研究了一波技术讨论,请教了一些大牛,找到了解决方案:写一个单独的NSURLProtocol类的分类方法,这里要提醒一下:由于这是私有方法,可能导致上线被拒!!!
.h文件:

+ (void)wk_registerScheme:(NSString*)scheme;

+ (void)wk_unregisterScheme:(NSString*)scheme;

.m文件:

FOUNDATION_STATIC_INLINE Class ContextControllerClass() {
    static Class cls;
    if (!cls) {
        cls = [[[WKWebView new] valueForKey:@"browsingContextController"] class];
    }
    return cls;
}

FOUNDATION_STATIC_INLINE SEL RegisterSchemeSelector() {
    return NSSelectorFromString(@"registerSchemeForCustomProtocol:");
}

FOUNDATION_STATIC_INLINE SEL UnregisterSchemeSelector() {
    return NSSelectorFromString(@"unregisterSchemeForCustomProtocol:");
}

@implementation NSURLProtocol (WebKitSupport)

+ (void)wk_registerScheme:(NSString *)scheme {
    Class cls = ContextControllerClass();
    SEL sel = RegisterSchemeSelector();
    if ([(id)cls respondsToSelector:sel]) {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
        [(id)cls performSelector:sel withObject:scheme];
#pragma clang diagnostic pop
    }
}

+ (void)wk_unregisterScheme:(NSString *)scheme {
    Class cls = ContextControllerClass();
    SEL sel = UnregisterSchemeSelector();
    if ([(id)cls respondsToSelector:sel]) {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
        [(id)cls performSelector:sel withObject:scheme];
#pragma clang diagnostic pop
    }
}

然后在AppDelegate里面去注册一波scheme,一般是注册http和https,然后打一波断点你就会发现,可以拦截了,可以为所欲为了,一般对wkwebView的拦截的原因一般是要加一些特定的请求头或者拦截广告(接触的项目里面是这样干的)
+ (BOOL)canInitWithRequest:(NSURLRequest *)request在这里进行过滤判断,
+ (NSURLRequest *)canonicalRequestForRequest:(NSURLRequest *)request这里面可以拿到被拦截的请求,可以在这里面对这个request进行二次处理,然后在startLoading方法里面自己进行自定义的处理!

上一篇下一篇

猜你喜欢

热点阅读