Edited at

WKWebViewでのSessionの共有

More than 1 year has passed since last update.


概要

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を共有する

HTTPCookieStrageWKProcessPool のセッション情報は非同期で共有されてしまうため、

同期的にSession情報を扱うためには、


  1. 初回リクエスト時のHTTP Response HeaderのSet-Cookieの値を保存する

  2. 次回起動時に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)


参考