开发中遇到的 WKWebView cookie 问题,查了好多资料,勉强找到下面两种适合我的解决方案,分享给大家,大家有更好的方案还望不吝赐教~~
场景一:原生登录之后立马跳转到 H5 页面
原因分析:NSHTTPCookieStorage 中的 cookie 不会立马(主动?)同步到 WKWebView,会导致进入 H5 页面后 cookie 没带上。
解决方案:初始化 WKWebView 的时候将 NSHTTPCookieStorage 中的 cookie 注入其中。
示例代码:
- (void)setupWebView {
WKUserContentController *userContentController = [WKUserContentController new];
NSString *cookieJS = [self updateCookieJSString];
WKUserScript *cookieScript = [[WKUserScript alloc] initWithSource:cookieJS injectionTime:WKUserScriptInjectionTimeAtDocumentStart forMainFrameOnly:NO];
[userContentController addUserScript:cookieScript];
WKWebViewConfiguration *configuration = [WKWebViewConfiguration new];
configuration.processPool = [WKProcessPool new];
configuration.userContentController = userContentController;
self.webView = [[WKWebView alloc] initWithFrame:CGRectZero configuration:configuration];
}
- (NSString *)updateCookieJSString {
NSMutableString *script = [NSMutableString string];
[script appendString:@"var cookieNames = document.cookie.split('; ').map(function(cookie) { return cookie.split('=')[0] } );\n"];
NSArray *cookies = [[NSHTTPCookieStorage sharedHTTPCookieStorage] cookies];
for (NSHTTPCookie *cookie in cookies) {
if ([cookie.value rangeOfString:@"'"].location != NSNotFound) {
continue;
}
[script appendFormat:@"if (cookieNames.indexOf('%@') == -1) { document.cookie='%@'; };\n", cookie.name, [self cookieString:cookie]];
}
return script;
}
- (NSString *)cookieString:(NSHTTPCookie *)cookie {
NSString *string = [NSString stringWithFormat:@"%@=%@;domain=%@;path=%@",
cookie.name,
cookie.value,
cookie.domain,
cookie.path ?: @"/"];
if (cookie.secure) {
string = [string stringByAppendingString:@";secure=true"];
}
return string;
}
场景二:在 H5 页面内调起原生登录,登录成功后 webView 带不上 cookie
原因分析:同场景一。
解决方案:在登录成功的回调方法里面,通过原生调 JS 的方式运行一段 JS 代码,把 NSHTTPCookieStorage 中的 cookie 通过 “document.cookie = ” 的方式注入到 webView 中。但是有一个弊端:运行完这段 JS 代码后 cookie 可能不会立即生效,大概会延迟一秒左右。
示例代码:
- (void)loginSuccess {
[webView evaluateJavaScript:[self updateCookieJSString] completionHandler:^(id _Nullable result, NSError * _Nullable error) {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 1 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
// 需要在登录成功后立马执行的操作。。。
}];
}];
}