前言
在Hybrid項(xiàng)目不同容器間共享Cookie在UIWebview時(shí)代一直不是一個(gè)問題,但是在很多Hybrid框架迭代到WKWebview后就可以出現(xiàn)關(guān)于Cookie共享的一些問題,這些問題無外乎就兩點(diǎn):
- 原生請(qǐng)求(NSURLSessionDataTask、AFNetworking等和)WKWebview之間cookie的共享
- 不同WKWebview (包括webview內(nèi)的ajax請(qǐng)求) 之間Cookie的共享
解決以上兩個(gè)問題即可解決整個(gè)應(yīng)用內(nèi)絕大部分情況的Cookie共享問題。
產(chǎn)生這個(gè)問題的原因是什么?
關(guān)于Cookie的原理我不再做過多的解釋,但是這是這篇文章的前提,必須在了解清楚之后才能合理控制其共享機(jī)制。
對(duì)于干iOS開發(fā)的小伙伴們大家可能對(duì)NSHTTPCookieStorage比較熟悉,NSHTTPCookieStorage是一個(gè)單例,用來管理整個(gè)項(xiàng)目的Cookie,包括UIWebview的Cookie也是由其管理,因此在使用UIWebview的情況下是沒有任何問題的。但是WKWebview的Cookie信息并不存儲(chǔ)在NSHTTPCookieStorage中,其由WKProcessPool管理。
多WKWebview間Cookie的共享
先來看WKWebview之間Cookie的共享問題如何解決
方法一
默認(rèn)情況下,每一個(gè)WKWebview對(duì)象持有一個(gè)WKProcessPool對(duì)象,因此可以通過單例化WKProcessPool的方式解決WKWebview間Cookie共享的問題,但是存在的問題是WKProcessPool不會(huì)被持久化,應(yīng)用被殺死后會(huì)導(dǎo)致Cookie丟失,對(duì)于需要長(zhǎng)久保存的Cookie并不合適。方法二
使用NSHTTPCookieStorage對(duì)象去手動(dòng)存取Cookie信息并注入到WKWebview中
先來說怎么取,直接上代碼:
- (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler{
if (@available(iOS 12.0, *)) {
WKHTTPCookieStore *cookieStore = webView.configuration.websiteDataStore.httpCookieStore;
[cookieStore getAllCookies:^(NSArray* cookies) {
[self setCookie:cookies];
}];
}else {
NSHTTPURLResponse *response = (NSHTTPURLResponse *)navigationResponse.response;
NSArray *cookies =[NSHTTPCookie cookiesWithResponseHeaderFields:[response allHeaderFields] forURL:response.URL];
[self setCookie:cookies];
}
decisionHandler(WKNavigationResponsePolicyAllow);
}
- (void)setCookie:(NSArray *)cookies {
for (NSHTTPCookie *cookie in cookies) {
NSHTTPCookie *httpCookie = [self fixExpiresDateWithCookie:cookie];
[[NSHTTPCookieStorage sharedHTTPCookieStorage] setCookie:httpCookie];
}
}
- (NSHTTPCookie *)fixExpiresDateWithCookie:(NSHTTPCookie *)cookie{
NSMutableDictionary *propertiesDic = [[cookie properties] mutableCopy];
if (![propertiesDic valueForKey:@"expiresDate"]) {
propertiesDic[NSHTTPCookieExpires] = [NSDate dateWithTimeIntervalSinceNow:60*60*24*7];
propertiesDic[NSHTTPCookieDiscard] = 0;
}
NSHTTPCookie *newCookie = [NSHTTPCookie cookieWithProperties:propertiesDic];
return newCookie;
}
代碼比較簡(jiǎn)單,唯一需要注意的就是fixExpiresDateWithCookie這個(gè)方法的實(shí)現(xiàn)中修改了Cookie的過期時(shí)間NSHTTPCookieExpires與是否丟棄NSHTTPCookieDiscard字段,修改原因是因?yàn)楹蠖瞬辉敢飧拇a,喝喝,當(dāng)然也可以理解,B/S架構(gòu)中session-only=1這樣的設(shè)置較為安全,也是常態(tài)化操作,但是對(duì)于客戶端多個(gè)webview對(duì)象就很尷尬了。同時(shí)這個(gè)操作的確可能帶了信息泄露的安全問題,安全風(fēng)險(xiǎn)一定需要注意。
接下來說怎么注入到WKWebview中去,有兩種思路
第一種是通過WKUserScript去注入,但是注入時(shí)機(jī)會(huì)影響服務(wù)器可能拿不到Cookie。
第二種方法是在構(gòu)造NSURLRequest的時(shí)候去修改請(qǐng)求頭,也直接上代碼了:
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:20.0];
NSMutableString *cookiesString = [NSMutableString string];
NSArray *tmpCookies = [[NSHTTPCookieStorage sharedHTTPCookieStorage] cookiesForURL:url];
for (NSHTTPCookie * cookie in tmpCookies) {
NSString *cookieString = [NSString stringWithFormat:@"%@=%@;",cookie.name,cookie.value];
[cookiesString appendString:cookieString];
}
[request setValue:cookiesString forHTTPHeaderField:@"Cookie"];
[self loadRequest:request];
原生請(qǐng)求與WKWebview之間Cookie的共享
獲取和保存Cookie的方式與上面類似,再處理網(wǎng)絡(luò)請(qǐng)求response的地方調(diào)用如下類似代碼:
- (void)syncSwordCookies:(NSURLResponse *)response forURL:(NSURL *)url {
NSDictionary *respHeader = [(NSHTTPURLResponse *)response allHeaderFields];
NSArray *cookies = [NSHTTPCookie cookiesWithResponseHeaderFields:respHeader forURL:url];
NSHTTPCookieStorage *cookieStorage = [NSHTTPCookieStorage sharedHTTPCookieStorage];
for (NSHTTPCookie *cookie in cookies) {
[cookieStorage setCookie:[self fixExpiresDateWithCookie:cookie]];
}
}
Cookie都保存在NSHTTPCookieStorage中后,原生請(qǐng)求自動(dòng)共享Cookie,webview注入方式即與前面說的WKWebview一樣的,就不用贅述了,但是唯一要注意的地方就是NSHTTPCookieStorage保存有一個(gè)耗時(shí)時(shí)間,大概零點(diǎn)幾秒,不能在保存后立刻去同步到WKWebview中去,否則容易取不到Cookie(真坑...)
結(jié)語
WKWebview Cookie同步的坑我在全部踏完之后留下來上述結(jié)論,還有些低級(jí)或者麻煩的坑就沒有一一列舉,希望這篇文章可以給到大家?guī)椭绻惺裁匆蓡柨梢粤粞杂懻摗?/p>