美文网首页Mac开发
WKWebview共享Cookie

WKWebview共享Cookie

作者: Ev0 | 来源:发表于2019-02-19 09:30 被阅读0次

    前言

    在Hybrid项目不同容器间共享Cookie在UIWebview时代一直不是一个问题,但是在很多Hybrid框架迭代到WKWebview后就可以出现关于Cookie共享的一些问题,这些问题无外乎就两点:

    1. 原生请求(NSURLSessionDataTask、AFNetworking等和)WKWebview之间cookie的共享
    2. 不同WKWebview (包括webview内的ajax请求) 之间Cookie的共享

    解决以上两个问题即可解决整个应用内绝大部分情况的Cookie共享问题。

    产生这个问题的原因是什么?

    关于Cookie的原理我不再做过多的解释,但是这是这篇文章的前提,必须在了解清楚之后才能合理控制其共享机制。
    对于干iOS开发的小伙伴们大家可能对NSHTTPCookieStorage比较熟悉,NSHTTPCookieStorage是一个单例,用来管理整个项目的Cookie,包括UIWebview的Cookie也是由其管理,因此在使用UIWebview的情况下是没有任何问题的。但是WKWebview的Cookie信息并不存储在NSHTTPCookieStorage中,其由WKProcessPool管理。

    多WKWebview间Cookie的共享

    先来看WKWebview之间Cookie的共享问题如何解决

    • 方法一
      默认情况下,每一个WKWebview对象持有一个WKProcessPool对象,因此可以通过单例化WKProcessPool的方式解决WKWebview间Cookie共享的问题,但是存在的问题是WKProcessPool不会被持久化,应用被杀死后会导致Cookie丢失,对于需要长久保存的Cookie并不合适。

    • 方法二
      使用NSHTTPCookieStorage对象去手动存取Cookie信息并注入到WKWebview中
      先来说怎么取,直接上代码:

    - (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler{
        if (@available(iOS 12.0, *)) {
            WKHTTPCookieStore *cookieStore = webView.configuration.websiteDataStore.httpCookieStore;
            [cookieStore getAllCookies:^(NSArray* cookies) {
                [self setCookie:cookies];
            }];
        }else {
            NSHTTPURLResponse *response = (NSHTTPURLResponse *)navigationResponse.response;
            NSArray *cookies =[NSHTTPCookie cookiesWithResponseHeaderFields:[response allHeaderFields] forURL:response.URL];
            [self setCookie:cookies];
        }
        decisionHandler(WKNavigationResponsePolicyAllow);
    }
    - (void)setCookie:(NSArray *)cookies {
        for (NSHTTPCookie *cookie in cookies) {
            NSHTTPCookie *httpCookie = [self fixExpiresDateWithCookie:cookie];
            [[NSHTTPCookieStorage sharedHTTPCookieStorage] setCookie:httpCookie];
        }
    }
    - (NSHTTPCookie *)fixExpiresDateWithCookie:(NSHTTPCookie *)cookie{
        NSMutableDictionary *propertiesDic = [[cookie properties] mutableCopy];
        if (![propertiesDic valueForKey:@"expiresDate"]) {
            propertiesDic[NSHTTPCookieExpires] = [NSDate dateWithTimeIntervalSinceNow:60*60*24*7];
            propertiesDic[NSHTTPCookieDiscard] = 0;
        }
        NSHTTPCookie *newCookie = [NSHTTPCookie cookieWithProperties:propertiesDic];
        return newCookie;
    }
    

    代码比较简单,唯一需要注意的就是fixExpiresDateWithCookie这个方法的实现中修改了Cookie的过期时间NSHTTPCookieExpires与是否丢弃NSHTTPCookieDiscard字段,修改原因是因为后端不愿意改代码,喝喝,当然也可以理解,B/S架构中session-only=1这样的设置较为安全,也是常态化操作,但是对于客户端多个webview对象就很尴尬了。同时这个操作的确可能带了信息泄露的安全问题,安全风险一定需要注意。
    接下来说怎么注入到WKWebview中去,有两种思路
    第一种是通过WKUserScript去注入,但是注入时机会影响服务器可能拿不到Cookie。
    第二种方法是在构造NSURLRequest的时候去修改请求头,也直接上代码了:

        NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:20.0];
        NSMutableString *cookiesString = [NSMutableString string];
        NSArray *tmpCookies = [[NSHTTPCookieStorage sharedHTTPCookieStorage] cookiesForURL:url];
        for (NSHTTPCookie * cookie in tmpCookies) {
            NSString *cookieString = [NSString stringWithFormat:@"%@=%@;",cookie.name,cookie.value];
            [cookiesString appendString:cookieString];
        }
        [request setValue:cookiesString forHTTPHeaderField:@"Cookie"];
        [self loadRequest:request];
    

    原生请求与WKWebview之间Cookie的共享

    获取和保存Cookie的方式与上面类似,再处理网络请求response的地方调用如下类似代码:

    - (void)syncSwordCookies:(NSURLResponse *)response forURL:(NSURL *)url {
        NSDictionary *respHeader = [(NSHTTPURLResponse *)response allHeaderFields];
        NSArray *cookies = [NSHTTPCookie cookiesWithResponseHeaderFields:respHeader forURL:url];
        NSHTTPCookieStorage *cookieStorage = [NSHTTPCookieStorage sharedHTTPCookieStorage];
        for (NSHTTPCookie *cookie in cookies) {
            [cookieStorage setCookie:[self fixExpiresDateWithCookie:cookie]];
        }
    }
    

    Cookie都保存在NSHTTPCookieStorage中后,原生请求自动共享Cookie,webview注入方式即与前面说的WKWebview一样的,就不用赘述了,但是唯一要注意的地方就是NSHTTPCookieStorage保存有一个耗时时间,大概零点几秒,不能在保存后立刻去同步到WKWebview中去,否则容易取不到Cookie(真坑...)

    结语

    WKWebview Cookie同步的坑我在全部踏完之后留下来上述结论,还有些低级或者麻烦的坑就没有一一列举,希望这篇文章可以给到大家帮助,如果有什么疑问可以留言讨论。

    相关文章

      网友评论

        本文标题:WKWebview共享Cookie

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