WKWebView 設定Cookie

weixin_34337265發表於2017-03-20

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列表>選擇想要檢視的頁面

1600595-07d7c08e161acbfd.png
WKUserScript 設定cookie的結果

看到這裡,可以看到,一條語句雖然設定兩個cookie,但只有一條生效,age=18找不到。算了,沒有就分開設定,一條一條設也是可以的。
正準備拍拍手,打完收工?且慢!後臺有『茬』要找了,後臺說,我根本沒有看到cookie啊!
你說,怎麼可能,蘋果爸爸做的東西怎麼會有問題,一定是你們的問題。
被後臺『找茬』多次後,我們來抓包看看吧,還是一樣的程式,還是一樣的程式碼,結果如下
1600595-3eae87e24b0e72ad.png
程式發出的請求中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吧。

相關文章