iOS开发-打通UIWebView和WKWebView的Cookie

文档更新说明:

•   2016年04月06日 v1.0  初稿
•   2016年05月04日 v2.0 添加demo

一、前言

  如今,HTML5的迅速发展,使得越来越多的app在网这个方向发展,将网页内嵌到app中,在电商app中尤为常见。而在iOS中,我们在app中内嵌网页无非两种方式,一是使用UIWebView,二是使用WKWebView。两者对比如下:

1、UIWebView

  • 这个控件应该是是在iOS2就开始有的了,历史比较悠久了,也正由于诞生了很多年了,所以在iOS版本之中兼容性比较好。

  • 据说,UIWebView存在很多不足,比如说内存泄露等等。

  • UIWebView会将NSHttpRequest的所有请求产生的cookie自动保存,并且,在同一个app内多个UIWebView之间共享,不需要我们做任何操作。

  • 由上面的特点可以知道,使用AFNetWorking的请求,也会自动保存cookie,并且和UIWebView共享。

2、WKWebView

  • WKWebView是在iOS8才诞生的空间,不属于UIKit框架,属于WKWebKit框架,对于要兼容老版本的app不能使用。

  • WKWebView修复了很多UIWebView的不足,并且采用了和Safari一样的JS引擎,据说,性能提升了百分之二三十,内存占用反而降低了百分之二三十。

  • WKWebView不会和NSHttpRequest共享cookie,因此,如果登录接口用AFN,那么WKWebView是读取不到登录之后的cookie的。


二、关于iOS开发中的cookie

        由NSHttpRequest所产生的请求都会将cookie自动保存,并且多个UIWebView中共享。因此,假设我们在UIWebView-1中登录了某个账号,那么在UIWebView-2中,也是可以读取到这个登录状态的。
        那么,这个cookie是保存的哪里的呢?事实上,在iOS中,有两个类是和HTTP的cookie相关的,一个是NSHTTPCookieStorage,一个是NSHTTPCookie。他们的关系就是:NSHTTPCookieStorage中保存了很多的NSHTTPCookie。

三、怎么共享cookie

  回到正题,我们怎么才能在UIWebView和WKWebView中共享cookie数据呢?

1、思路

  思路是这样子的,我们可以通过NSHTTPCookieStorage的一个单例,拿到app中所有的UIWebView的cookie,拿到之后再通过让WKWebView执行一段js代码,把这些cookie设置到WKWebView中,这样就可以实现WKWebView获取UIWebView的cookie了。

2、代码

1、新建一个单例

+ (instancetype)sharedWKCookieSyncManager {
    static WKCookieSyncManager *sharedWKCookieSyncManagerInstance = nil;
    static dispatch_once_t predicate;
    dispatch_once(&predicate, ^{
        sharedWKCookieSyncManagerInstance = [[self alloc] init];
    });
    return sharedWKCookieSyncManagerInstance;
}

2、在单例中,新建一个WKProcessPool对象,并且,需要保持这个对象为单例,因为在WKWebView中,只有使用了同一个WKProcessPool的WKWebView,才会共享cookie。

- (WKProcessPool *)processPool {
    if (!_processPool) {
        static dispatch_once_t predicate;
        dispatch_once(&predicate, ^{
            _processPool = [[WKProcessPool alloc] init];
        });
    }
    
    return _processPool;
}

3、新建一个setCookie方法,在方法中,请求一个不存在的url,并且在回调中,设置cookie。

- (void)setCookie {
    //判断系统是否支持wkWebView
    Class wkWebView = NSClassFromString(@"WKWebView");
    if (!wkWebView) {
        return;
    }
    WKWebViewConfiguration *config = [[WKWebViewConfiguration alloc] init];
    config.processPool = self.processPool;
    self.webView = [[WKWebView alloc] initWithFrame:CGRectZero configuration:config];
    NSURLRequest *request = [[NSURLRequest alloc] initWithURL:self.testUrl];
    self.webView.navigationDelegate = self;
    [self.webView loadRequest:request];
}

4、在回调中,设置cookie

#pragma mark - WKNavigationDelegate
- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation {
    //取出cookie
    NSHTTPCookieStorage *cookieStorage = [NSHTTPCookieStorage sharedHTTPCookieStorage];
    //js函数
    NSString *JSFuncString = @"function setCookie(name,value,expires)\
    {\
        var oDate=new Date();\
        oDate.setDate(oDate.getDate()+expires);\
        document.cookie=name+'='+value+';expires='+oDate;\
    }";
    
    //拼凑js字符串
    NSMutableString *JSCookieString = JSFuncString.mutableCopy;
    for (NSHTTPCookie *cookie in cookieStorage.cookies) {
        NSString *excuteJSString = [NSString stringWithFormat:@"setCookie('%@', '%@', 1);", cookie.name, cookie.value];
        [JSCookieString appendString:excuteJSString];
    }
    //执行js
    [webView evaluateJavaScript:JSCookieString completionHandler:nil];
}

四、补充

  在后面的开发中,需要设置所有的WKWebView都使用前面那个单例processPool,否则,cookie是不会在WKWebView之间共享的。
还有就是那段js代码可能写的不好,大家指正,谢谢!

五、代码demo

  前几周就说要上demo了,无奈最近比较忙,所以拖到今天才写了