iOS
Swift
WKWebView

WKWebViewでのSessionの共有

概要

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)

参考