Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationEventAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
53
Help us understand the problem. What are the problem?

More than 3 years have passed since last update.

@nikadon

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)

参考

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
53
Help us understand the problem. What are the problem?