概要
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)