WKWebView
发送请求时不会把HTTPCookieStorage
中的cookie写入请求中需要手动添加。
iOS11之前实现思路是在原有的URLRequest中注入cookie再load,这种做法只能在webView第一次请求的时候会生效,后续未跨域请求带上cookie需要在WKWebViewConfiguration
中添加WKUserScript
.
iOS11后通过WKWebsiteDataStore
管理
func injectCookie(request: URLRequest) -> URLRequest {
if #available(iOS 11.0, *) {
return request
}
guard let url = request.url else {
return request
}
var newRequest = URLRequest(url: url)
let cookies = HTTPCookieStorage.shared.cookies ?? []
var cookiesHeaders: [String] = []
for cookie in cookies {
if isNeedInjectCookie(url) {
cookiesHeaders.append("\(cookie.name)=\(cookie.value)")
}
}
let header = cookiesHeaders.joined(separator: ";")
newRequest.addValue(header, forHTTPHeaderField: "Cookie")
return newRequest
}
//
private func injectCookie(configuration: WKWebViewConfiguration) {
guard let url = self.request.url else { return }
let cookies = HTTPCookieStorage.shared.cookies ?? []
if #available(iOS 11.0, *) {
let dataStore = WKWebsiteDataStore.nonPersistent()
for cookie in cookies {
dataStore.httpCookieStore.setCookie(cookie, completionHandler: nil)
}
configuration.websiteDataStore = dataStore
} else {
var cookieList: [String] = []
for cookie in cookies {
// 不写“path=/” cookie设置不生效
cookieList.append("\(cookie.name)=\(cookie.value);path=/")
}
let cookieString = cookieList.joined(separator: ";")
let cookieSource = "document.cookie = '\(cookieString)';"
let cookieScript = WKUserScript(source: cookieSource, injectionTime: .atDocumentStart, forMainFrameOnly: false)
configuration.userContentController.addUserScript(cookieScript)
}
}
通过上述方案修改后的cookie,服务器无法再往请求中添加cookie,所以服务器返回的cookie需要本地记录,后续请求再继续添加.
实现WKNavigationDelegate
func webView(_ webView: WKWebView, decidePolicyFor navigationResponse: WKNavigationResponse, decisionHandler: @escaping (WKNavigationResponsePolicy) -> Void) {
if #available(iOS 11.0, *) {
let cookieStore = webView.configuration.websiteDataStore.httpCookieStore
cookieStore.getAllCookies { (cookies) in
for cookie in cookies {
HTTPCookieStorage.shared.setCookie(cookie)
}
}
} else {
let httpResponse = navigationResponse.response as? HTTPURLResponse
let headerFields = httpResponse?.allHeaderFields as? [String : String]
if let headerFields = headerFields, let url = httpResponse?.url {
let cookies = HTTPCookie.cookies(withResponseHeaderFields: headerFields, for: url)
for cookie in cookies {
HTTPCookieStorage.shared.setCookie(cookie)
}
}
}
decisionHandler(.allow)
}
网友评论