40- WKWebView项目实践分享(五)- WKWebView如何加Cookie

强烈建议如果你把下边的参考文章也快速看下,作为拓展和补充。

Cookie对webView的重要性不言而喻,也就是Cookie很大成都的影响我们是否使用WKWebView。iOS8.0-iOS11.0的时候,苹果并没有向WKWebView提类似UIWebView+NSHttpCookieStorage这样便利的方案。
关于为什么在长达三年的时间里,苹果没有理会开发者的抱怨推出客户端管理Cookie的类。CSDN作者请叫我马老师的一篇文章中,提出了猜想,苹果是想让服务端完全控制Cookie,毕竟客户端操作Cookie是有一定安全风险的。WKWebView设计出来,对安全性就有比较高的要求,比如说对跨域的限制。
那么客户端不传Cookie了,服务端怎么确认用户的身份信息呢?其中的一种方式,我们可以在首次请求的时候,将用户信息身份信息通过POST请求的方式放到requst中。服务端接收到首次请求,判断用户身份信息,如果身份信息有效,则在之后的请求中,有服务器主动设置Cookie保证后续的请求身份。如果身份信息无效,则跳转到登录页面。 这种方式Cookie就完全交给服务器管理了。

但是,实际开发中,我们还是免不了客户端设置Cookie。

WKWebView的Cookie方案。

在UIWebView中,可以通过NSHttpCookieStorage来管理Cookie。
在UIWebView中,如果添加Cookie到NSHttpCookieStorage中。这个Cookie在发起请求的时候自动添加到request Header中。并且是零延迟的,也就是说,你第一行代码添加Cookie到NSHttpCookieStorage中,第二行代码loadRequest:,发起的请求中是带有你设置的Cookie的。
关于零延迟这一点非常重要,因为你设置了Cookie,但是请求的时候,带不到服务器,这不是白设置嘛。

NSHttpCookieStorage对WKWebView而言,只能管理Cookie,但是没有了零延迟自动同步到request Header这一关键的特性。所以我们只能另找出路,下边需要版本适配,也是因为这个原因

截至置顶的iOS版本,需要适配iOS的三个版本,分别是iOS8iOS11.0、iOS11.0iOS11.2、iOS11.3。 下边看具体的方案:

Cookie版本适配方案

下边就针对每个适配版本来说一下具体操作方案。

适配iOS8~iOS11.0

首先很明确的说明下,这这里需要关注Cookie设置的地方有两处。
第一处是我们每次调用loadRequest:方法的时候。
另一处就是loadRequest:成功之后,在这个webView的进行操作,后续页面跳转的时候。

关于Cookie管理,我们还是使用NSHttpCookieStorage。

在每次调用loadRequest:方法的时候

我们把Cookie手动写入到request Header中。具体代码和步骤如下:

// 1. 清除NSHTTPCookieStorage中存储的Cookies,避免重复Cookie
NSHTTPCookieStorage *cookieJar = [NSHTTPCookieStorage sharedHTTPCookieStorage];
for (NSHTTPCookie *cookie in cookieJar.cookies) {
    if ([cookie.comment isEqualToString:WebCookieComment]) {
        [cookieJar deleteCookie:cookie];
    }
}

// 2. 重新设置Cookies
[[NSHTTPCookieStorage sharedHTTPCookieStorage] setCookie:cookie];
[[NSUserDefaults standardUserDefaults] synchronize];

// 3. 向Http Header中设置Cookie    
 NSDictionary *dict = [NSHTTPCookie requestHeaderFieldsWithCookies:[NSHTTPCookieStorage sharedHTTPCookieStorage].cookies];
 request.allHTTPHeaderFields = dict.copy;

// 4. 加载请求
[self.wkwebView loadRequest: request];

后续页面跳转

后续跳转,我们把Cookie添加到document.Cookie的方案。

//1. 添加自定义的cookie,后续请求Ajax页面用到
WKUserScript *newCookieScript = [[WKUserScript alloc] initWithSource:[WebViewCookieTool cookieJavaScriptString] injectionTime:WKUserScriptInjectionTimeAtDocumentStart forMainFrameOnly:NO];
[contentController addUserScript:newCookieScript];
webConfiguration.userContentController = contentController;


//2. 获取Cookie的JS代码
+ (NSString *)cookieJavaScriptString
    NSMutableString *script = [NSMutableString string];
    for (NSHTTPCookie *cookie in [[NSHTTPCookieStorage sharedHTTPCookieStorage] cookies]) {
    if ([cookie.value rangeOfString:@"'"].location != NSNotFound) {
         continue;
    }
    [script appendFormat:@"document.cookie='%@'; \n", [self getCookieJSFromatString:cookie]];
}
    
    
+ (NSString *)getCookieJSFromatString:(NSHTTPCookie *)cookie
{
    NSString *cookieStr = [NSString stringWithFormat:@"%@=%@;domain=%@;path=%@",
                           cookie.name,
                           cookie.value,
                           cookie.domain,
                           cookie.path ?: @“/"];
    return cookieStr;
}

这种方案出现的问题

这种方案基本解决了适配版本中的Cookie问题,但是在实测中,发现将Cookie添加到request Header中会导致另一个问题出现。那就是服务器如果设置一些Cookie到header中,是不能正常设置的,导致网页无法正常显示。又是一个坑。针对这个问题,想到了两个解决方案:

解决服务器无法在Header中正常设置Cookie

所以,我项目里有一个区分是不是本公司请求的静态方法:

static inline BOOL checkURLIsNeedCookies(NSURL *url) {
    if ([url.host hasSuffix:@".myCompany.com") {
        return YES;
    }
    return NO;
}

适配iOS11.0~iOS11.2

iOS11.0之后的适配就爽啦,可能苹果了解到开发者的实际情况并且做出了妥协。在iOS11.0推出了WKHTTPCookieStore,这个类对WKWebView的作用和NSHttpCookieStorage对UIWebView的效果一样,并且也是零延迟。所以,只需要在你请求的时候,将Cookie设置到WKHTTPCookieStore就可以了。代码:

// 1. 设置Cookie
WKWebsiteDataStore *store = [WKWebsiteDataStore defaultDataStore];
[store.httpCookieStore setCookie:cookie completionHandler:^{
NSLog(@“cookie添加成功”);
}];

// 2. 加载请求
[self.wkwebView loadRequest: request];

适配iOS11.3

前几天升级iOS11.3之后发现需要Cookie的页面,第一次设置的时候,WKHTTPCookieStore中Cookie不同步到request请求中。然后,重新请求页面,WKHTTPCookieStore的作用才会恢复正常,有序请求其他的webView也不会出现问题。

解决方式是,我们在执行loadRequest之前主动设置一次Cookie。我这里是在didFinishLaunchOption:中设置的。设置完之后,其它的就和在iOS11.0~iOS11.2中一样了。

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 
{
   WKWebsiteDataStore *store = [WKWebsiteDataStore defaultDataStore];
    [store.httpCookieStore setCookie:cookie completionHandler:^{
        NSLog(@“cookie添加成功”);
    }];
}

好了,关于WKWebView的Cookie设置就到此为止。

共享Web Content Process

我们之前说过,一个WKWebView创建出来之后,对应一个Web Content Process。这样就保证每个WKWebView的缓存、Cookie等信息是隔离的。但是这样会导致一个问题就是,当网页中出现a标签和target=_blank的时候,会好像浏览器那样新开一个tab页面,此时新开的webView不共享不到之前webView的Cookie的,导致新开的webView不能正常显示。 处理的方式是,设置WKWebView对应的processPool是唯一的。如下两种方式:

 1’:   
self.processPool = [[WKProcessPool alloc] init];
WKWebViewConfiguration *configuration1 = [[WKWebViewConfiguration alloc] init];
configuration1.processPool = self.processPool;
WKWebView *webView = [[WKWebView alloc] initWithFrame:CGRectZero configuration:configuration1];


2’:
- (WKProcessPool *)wkProcessPool
{
    static dispatch_once_t once;
    static WKProcessPool * __singleton__;
    dispatch_once( &once, ^{
        __singleton__ = [[WKProcessPool alloc] init];
        
    });
    return __singleton__;
}

 webConfiguration.processPool = self.wkProcessPool; 
 WKWebView *webView = [[WKWebView alloc] initWithFrame:CGRectZero configuration:configuration1];

参考

交流


希望能和大家交流技术
Blog:http://www.lilongcnc.cc


最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,686评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,668评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,160评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,736评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,847评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,043评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,129评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,872评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,318评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,645评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,777评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,470评论 4 333
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,126评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,861评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,095评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,589评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,687评论 2 351

推荐阅读更多精彩内容