WebView 中的 Cookie 处理业务场景“IP直连”方案说明
概述
本文将讨论下类似这样的问题:
- WKWebView 对于 Cookie 的管理一直是它的短板,那么 iOS11 是否有改进,如果有,如何利用这样的改进?采用 IP 直连方案后,服务端返回的 Cookie 里的 Domain 字段也会使用 IP 。如果 IP 是动态的,就有可能导致一些问题:由于许多 H5 业务都依赖于 Cookie 作登录态校验,而 WKWebView 上请求不会自动携带 Cookie。
WKWebView 使用 NSURLProtocol 拦截请求无法获取 Cookie 信息
iOS11推出了新的 API WKHTTPCookieStore 可以用来拦截 WKWebView 的 Cookie 信息
用法示例如下:
- WKHTTPCookieStore *cookieStroe = self.webView.configuration.websiteDataStore.httpCookieStore;
- //get cookies
- [cookieStroe getAllCookies:^(NSArray<NSHTTPCookie *> * _Nonnull cookies) {
- NSLog(@"All cookies %@",cookies);
- }];
- //set cookie
- NSMutableDictionary *dict = [NSMutableDictionary dictionary];
- dict[NSHTTPCookieName] = @"userid";
- dict[NSHTTPCookieValue] = @"123";
- dict[NSHTTPCookieDomain] = @"xxxx.com";
- dict[NSHTTPCookiePath] = @"/";
- NSHTTPCookie *cookie = [NSHTTPCookie cookieWithProperties:dict];
- [cookieStroe setCookie:cookie completionHandler:^{
- NSLog(@"set cookie");
- }];
- //delete cookie
- [cookieStroe deleteCookie:cookie completionHandler:^{
- NSLog(@"delete cookie");
- }];
利用 iOS11 API WKHTTPCookieStore 解决 WKWebView 首次请求不携带 Cookie 的问题
问题说明:由于许多 H5 业务都依赖于 Cookie 作登录态校验,而 WKWebView 上请求不会自动携带 Cookie。比如,如果你在Native层面做了登陆操作,获取了Cookie信息,也使用 NSHTTPCookieStorage 存到了本地,但是使用 WKWebView 打开对应网页时,网页依然处于未登陆状态。如果是登陆也在 WebView 里做的,就不会有这个问题。
iOS11 的 API 可以解决该问题,只要是存在 WKHTTPCookieStore 里的 cookie,WKWebView 每次请求都会携带,存在 NSHTTPCookieStorage 的cookie,并不会每次都携带。于是会发生首次 WKWebView 请求不携带 Cookie 的问题。
解决方法:
在执行 -[WKWebView loadReques:] 前将 NSHTTPCookieStorage 中的内容复制到 WKHTTPCookieStore中,以此来达到 WKWebView Cookie 注入的目的。示例代码如下:
- [self copyNSHTTPCookieStorageToWKHTTPCookieStoreWithCompletionHandler:^{
- NSURL *url = [NSURL URLWithString:@"https://www.v2ex.com"];
- NSURLRequest *request = [NSURLRequest requestWithURL:url];
- [_webView loadRequest:request];
- }];
- - (void)copyNSHTTPCookieStorageToWKHTTPCookieStoreWithCompletionHandler:(nullable void (^)())theCompletionHandler; {
- NSArray *cookies = [[NSHTTPCookieStorage sharedHTTPCookieStorage] cookies];
- WKHTTPCookieStore *cookieStroe = self.webView.configuration.websiteDataStore.httpCookieStore;
- if (cookies.count == 0) {
- !theCompletionHandler ?: theCompletionHandler();
- return;
- }
- for (NSHTTPCookie *cookie in cookies) {
- [cookieStroe setCookie:cookie completionHandler:^{
- if ([[cookies lastObject] isEqual:cookie]) {
- !theCompletionHandler ?: theCompletionHandler();
- return;
- }
- }];
- }
- }
这个是 iOS11 的API,针对iOS11之前的系统,需要另外处理。