在项目中,往往有这样的要求,用 API 进行登录之后在某个 WKWebView
的页面需要用 cookie
去验证身份(虽然我更喜欢用 accesstoken
去验证🙃)。WKWebView
是苹果官方建议的控件来替代老旧的 UIWebView
。但是 WKWebView
的 cookie
无法共享 NSHTTPCookieStorage
,所以这时候就需要我们自己去管理 cookie
。(iOS 11 上新增了 WKHTTPCookieStore
来管理)
首先我们先解析获取到的 cookie
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| private func analysisCookie(response: HTTPURLResponse) { if let fields = response.allHeaderFields as? [String: String], let url = response.url { let cookies = HTTPCookie.cookies(withResponseHeaderFields: fields, for: url) let storage = HTTPCookieStorage.shared for cookie in cookies { storage.setCookie(cookie) } } }
|
在 WKWebView
中注入 cookie
有两种方式,第一种,通过请求带过去
1 2 3 4 5 6
| if let url = URL(string: "") { let reqURL = URLRequest(url: url) let cookie = (HTTPCookieStorage.shared.cookies ?? []).strCookie reqURL.addValue(cookie, forHTTPHeaderField: "cookie") webView.load(reqURL) }
|
第二种方式,js
注入
1 2 3 4 5 6 7 8 9 10 11 12 13
| private func createWeb() { let config = WKWebViewConfiguration() let cookie = (HTTPCookieStorage.shared.cookies ?? []).userScript let user = WKUserContentController() let cookieScript = WKUserScript(source: cookie, injectionTime: .atDocumentStart, forMainFrameOnly: false) user.addUserScript(cookieScript) config.userContentController = user webView = WKWebView(frame: self.view.bounds, configuration: config) self.view.addSubview(webView) webView.load(requestURL) }
|
moya 的用法
1 2 3 4 5 6 7 8
| var headers: [String : String]? { switch self { case .login, .checkUpdate, .idCodeImg: return nil default: return (HTTPCookieStorage.shared.cookies ?? []).moya } }
|
这里我们需要将 HTTPCookie
类型转换一下,我们给 Array
添加几个扩展
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| extension Array where Element: HTTPCookie { public var moya: [String: String] { var cookie: [String: String] = [:] cookie["Cookie"] = self.map { "\($0.name)=\($0.value)" }.joined(separator: ";") return cookie } public var userScript: String { return self.map { "document.cookie='\($0.name)=\($0.value)'" }.joined(separator: ";") } public var strCookie: String { return self.map { "\($0.name)=\($0.value)" }.joined(separator: ";") } }
|
在我的项目中通过第二种方式实现了验证成功。