iOS WKWebview秒开方案的一些建议

·  阅读 1158

最近看到很多朋友做一些拦截来秒开,这里有几个方案产生问题以及解决方向

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起来并且成功拦截了,你会发现一个问题.


预知后事如何...

请有需要的同学留言联系我...

欢迎打赏.



分类:
iOS
标签:
分类:
iOS
标签: