最近看到很多朋友做一些拦截来秒开,这里有几个方案产生问题以及解决方向
NSURLProtocol
这种方案可以解决拦截请求
+ (BOOL)canInitWithRequest:(NSURLRequest*)request在以上方法中拦截资源
- (void)startLoading此方法中替换.
涉及的问题
问题1
+ (BOOL)canInitWithRequest:(NSURLRequest*)request 拦截所有的请求无差别拦截,所以造成的未知因素较多
解决: 可以自己维护一个拦截列表,在需要的时候注册拦截链接,顺便注意下多线程问题,可以参考以下代码+ (void)registerPrefix:(NSString *)prefixUrlKey prefixUrl:(NSString *)prefixUrl{ NSCParameterAssert(prefixUrlKey); NSCParameterAssert(prefixUrl); if (BUisEmptyString(prefixUrlKey) || BUisEmptyString(prefixUrl)) { return; } [self doInitialize]; @synchronized(prefixDict) { [prefixDict setObject:prefixUrl forKey:prefixUrlKey];
}}问题2.WKWebview的请求被拦截,造成body丢失
遇到此问题的同学很头疼,但是如果你是app的话解决方案很多
方法1:使用 HTTPBodyStream 获取 body,并赋值到 body 中
- (NSMutableURLRequest *)getMutablePostRequestIncludeBody { NSMutableURLRequest * req = [self mutableCopy]; if ([self.HTTPMethod isEqualToString:@"POST"]) { if (!self.HTTPBody) { NSInteger maxLength = 1024; uint8_t d[maxLength]; NSInputStream *stream = self.HTTPBodyStream; NSMutableData *data = [[NSMutableData alloc] init]; [stream open]; BOOL endOfStreamReached = NO; //不能用 [stream hasBytesAvailable]) 判断,处理图片文件的时候这里的[stream hasBytesAvailable]会始终返回YES,导致在while里面死循环。 while (!endOfStreamReached) { NSInteger bytesRead = [stream read:d maxLength:maxLength]; if (bytesRead == 0) { //文件读取到最后 endOfStreamReached = YES; } else if (bytesRead == -1) { //文件读取错误 endOfStreamReached = YES; } else if (stream.streamError == nil) { [data appendBytes:(void *)d length:bytesRead]; } } req.HTTPBody = [data copy]; [stream close]; } } return req;}方法2: 注入拦截的js代码在WK容器中,使对应请求被拦截由客户端发出
hookAjax
hookFetch方法3: 前端的请求scheme自定义,由客户端转发
[NSURLProtocol registerClass:[XXURLProtocol class]];[NSURLProtocol wk_registerScheme:@"xxscheme"];WKURLSchemeTask
此方案只支持iOS11以上,但是可以解决body丢失的问题
- (void)webView:(WKWebView *)webView startURLSchemeTask:(id<WKURLSchemeTask>)urlSchemeTask
以上方法开始拦截,内部填充数据
但是使用这个方案的同学发现一个问题,这他喵的只能拦截自定义scheme,对于http和https的拦截就会crash,如下图

好不容易找到个官方api 还不能用...
没关系,解决方案如下:
方法1. 前端同学修改scheme,所有请求的schme都改成自定义的,这样的话你就可以自定义拦截了.
前端OS: 人家安卓没事你让我改... 怎么适配...
em,这样的话撕不过,所以...
方法2.我们hook对应的拦截方法,修改拦截规则就好了.
上代码
+ (void)_hookHandlesURLScheme { xx_WebViewClassMethodSwizzle(self, @selector(handlesURLScheme:), @selector(xx_handlesURLScheme:));}+ (BOOL)xx_handlesURLScheme:(NSString *)name {
if ([name isEqualToString:@"http"] || [name isEqualToString:@"https"]) { return NO; } return [self xx_handlesURLScheme:name];}懂了么...以上hook后就可以为所欲为了
当然... 当你所有方法都实现,你发现你的功能以及能run起来并且成功拦截了,你会发现一个问题.

预知后事如何...
请有需要的同学留言联系我...
欢迎打赏.
