概要
WkWebViewを使ったWebViewアプリでSession情報を共有するための方法をメモ
WKWebView間でSessionの共有
WKWebView
間でSessionを共有するためには WKProcessPool
を使います
要注意なのはこの WKProcessPool
のインスタンスの共有の仕方で、 必ず WKProcessPool
を設定した WKWebViewConfiguration
のインスタンスを WKWebView
の初期化の際に渡すようにする必要があります
WKWebView
を初期化した後に、 WKWebViewConfiguration
のsetter経由で設定してもSessionは共有されないようです
◯ Sessionが共有される
let configuration = WKWebViewConfiguration()
let processPool = WKProcessPool()
configuration.processPool = processPool
let webView = WKWebView(frame: .zero, configuration: configuration)
×Sessionが共有されない
let configuration = WKWebViewConfiguration()
let processPool = WKProcessPool()
let webView = WKWebView(frame: .zero, configuration: configuration)
webView.configuration.processPool = processPool
WKProcessPool
のインスタンスはアプリケーション内で共有する必要があるため、staticにして保持することをおすすめします。
次回起動時もSessionを共有する
HTTPCookieStrage
と WKProcessPool
のセッション情報は非同期で共有されてしまうため、
同期的にSession情報を扱うためには、
- 初回リクエスト時のHTTP Response HeaderのSet-Cookieの値を保存する
- 次回起動時にSession情報を引き継ぐ
をする必要があります
1. 初回リクエスト時のHTTP Response HeaderのSet-Cookieの値を保存する
Set-Cookieで渡されるCookie情報を保存するには、webView(_:decidePolicyFor:decisionHandler:) の navigationResponse
にリクエストしたサーバーからCookieが渡された時に UserDefault
等に保存すればよいかと思います
func webView(_ webView: WKWebView, decidePolicyFor navigationResponse: WKNavigationResponse, decisionHandler: @escaping (WKNavigationResponsePolicy) -> Void) {
if let urlResponse = navigationResponse.response as? HTTPURLResponse,
let url = urlResponse.url,
let allHeaderFields = urlResponse.allHeaderFields as? [String : String] {
let cookies = HTTPCookie.cookies(withResponseHeaderFields: allHeaderFields, for: url)
for cookie in cookies {
if cookie.domain == "リクエストしたサーバーのドメイン" {
// UserDefaultにCookie情報を保存する
}
}
}
decisionHandler(.allow)
}
2.次回起動時にSession情報を引き継ぐ
アプリケーションを終了し、次回起動時にSession情報を引き継いでリクエストするためには、
a. WkWebView
の初期化時に document.cookie
に _session_id
を設定する
b. WkWebVie
の初回リクエスト時にCookie情報を設定する
をする必要があります
a. WkWebView
の初期化時に document.cookie
に _session_id
を設定する
WKUserScript
経由で document.cookie
に _session_id
を設定することで、初回リクエスト時以降もSession情報を保つことができます
let userContentController = WKUserContentController()
let script = "document.cookie='_session_id=セッションID; domain=サーバードメイン; path=Cookieパス;"
let cookieScript = WKUserScript(source: script, injectionTime: WKUserScriptInjectionTime.atDocumentStart, forMainFrameOnly: false)
userContentController.addUserScript(cookieScript)
let configuration = WKWebViewConfiguration()
configuration.userContentController = userContentController
セッションID、サーバードメイン、Cookieパスについては、[webView(_:decidePolicyFor:decisionHandler:)]の navigationResponse
で渡される HTTPCookie の値を確認してみてください
b. WkWebVie
の初回リクエスト時にCookie情報を設定する
初回リクエスト時にSession情報を設定してリクエストするためには、load メソッドに渡す URLRequest
のインスタンスにCookie情報を設定する必要があります
注意点として、 httpShouldHandleCookies
を falseに設定してリクエストする必要があります
trueにした場合、 HTTPCookieStrage
の値を共有してしまい、正しくSession情報が渡せない可能性があります
var request = URLRequest(url: url)
request.httpShouldHandleCookies = false
request.setValue("_session_id=セッションID", forHTTPHeaderField: "Cookie")
webview.load(request)