WKWebView 设置Cookie

WKWebView本来是有设置cookie的api的,具体做法如下

// 创建一个WKUserScript,设置好cookie
WKUserScript *cookieScript = [[WKUserScript alloc] initWithSource:@"document.cookie='name=Zhang;age=28;'" injectionTime:WKUserScriptInjectionTimeAtDocumentStart forMainFrameOnly:YES];
// webView 执行这个Script
[webView.configuration.userContentController addUserScript:cookieScript];

结果如何呢?等网页加载出来后,在web检查器中看一下存储空间
不知道怎么打开web检查器的:首先保证你的手机开了web检查器选项,设置>Safari>高级>web检查器,然后手机连上电脑,在电脑端的Safari选择开发>你的手机名>右边就是webView列表>选择想要查看的页面

WKWebView 设置Cookie_第1张图片
WKUserScript 设置cookie的结果

看到这里,可以看到,一条语句虽然设置两个cookie,但只有一条生效,age=18找不到。算了,没有就分开设置,一条一条设也是可以的。
正准备拍拍手,打完收工?且慢!后台有『茬』要找了,后台说,我根本没有看到cookie啊!
你说,怎么可能,苹果爸爸做的东西怎么会有问题,一定是你们的问题。
被后台『找茬』多次后,我们来抓包看看吧,还是一样的程序,还是一样的代码,结果如下
WKWebView 设置Cookie_第2张图片
程序发出的请求中cookie列表

阿勒!仔细对比下,除了自己设置的cookie一条没有,其他的cookie一条不少。
这是为什么呢?踩了一年 WKWebView的坑,我想我可以解释下,WKUserScript,从名字来看,这根本就不是专门设置cookie的啊,它是用来注入本地js脚本的,不只是cookie,其他的js方法啊什么的都可以用它来注入。
而这个类的初始化方法中有个时间参数 WKUserScriptInjectionTime,这是个枚举有两个值 .......AtDocumentStart...end,从名字中可以看出,这分别是在html的Document文档 开始加载加载结束时注入js。也就是说,这个方法设置cookie的过程是在数据已经下载完成,在本地解析过程中设置的,后台完全看不到啊。是的,后台找你那么多『茬』真的是你的错。

当初完全没想到这其中的原因,我也不知道怎么解决。那时,我也就听从了我们后台的方案:

  1. 在发起的request请求头里面,手动设置所有的cookie,包括自己要加的、NSHTTPCookieStorage里面本来有的,这是为了后台能拿到cookie。
  2. 发起request请求。
  3. 在收到网页数据时,把之前发送的那些cookie字符串,手动的在webview里面再执行一次,这是为了web本地能拿到cookie。

具体的代码如下

// 1. 先添加cookie到String
NSMutableString *cookieString = [NSMutableString stringWithFormat:@"name=zhang;(这里面的分号千万不要忘记)"]; 

// 2. 把网页本来有的cookie接上
NSArray *cookies = [[NSHTTPCookieStorage sharedHTTPCookieStorage] cookiesForURL:[NSURL URLWithString:URL_HOME]];
for (NSHTTPCookie *cookie in cookies) {
    [cookieString appendString:[NSString stringWithFormat:@"%@=%@;(这个分号同样不能忘)", cookie.name, cookie.value]];
}
   
// 3. 在request里面添加上cookie
NSURL *url = [NSURL URLWithString:urlString];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
[request setValue:cookieString forHTTPHeaderField:@"Cookie"];

// 4. webView 发起request请求
[_webView loadRequest:request];

// 5. 在WKWebView的代理方法didCommitNavigation里面设置cookie
- (void)webView:(WKWebView *)webView didCommitNavigation:(WKNavigation *)navigation {
//    [webView setAllCookie];
    [webView evaluateJavaScript:@"document.cookie = 'name=zhang';" completionHandler:nil];
}

后续的问题:这个方案执行过程中可能会遇到一些问题

  1. 后台只能收到部分cookie,有的cookie收不到
    有次,后台问我:那个啥啥cookie你没有设置吧!其他cookie都有,就这个收不到。我:不可能吧,我看我代码里把所有cookie都设了啊,我不管了。于是后台去排查了半天,发现,一串cookie字符串的末尾,少了个分号;。。。
    没错,是我的问题,在步骤1里我的cookieString大概是这样的@"c1=v1;c2=v2;......;name=aaa",aaa后面的;呢??大概被我吃了吧。

  2. 后台没有收到任何cookie,也就是这个方法似乎无效
    这个问题有个读者也问过我,我也不知道什么情况,也没给他解决。
    而那天我似乎遇到了同样的情况,大概是这样的,在一个列表里选择item>item选择完毕,表示待会要设置新cookie> 回到webView的页面>webView刷新>结果,抓包显示后台没有收到cookie。
    仔细看看这个流程,webView加载数据的过程中只做了一个操作,刷新。那么就真相大白了,刷新操作并不经过重新拼接cookie,不经过生成新的request请求过程,因此也就根本没有发送cookie。
    正确的做法,凡是要设置新的cookie,从后台拿新数据,那么,不要刷新,重新拼接cookie字符串,重新loadRequest吧。

你可能感兴趣的:(WKWebView 设置Cookie)