しめ鯖日記

swift, iPhoneアプリ開発, ruby on rails等のTipsや入門記事書いてます

WKProcessPoolが違ってもWKWebView同士のcookieを同期されていた

複数WKWebViewがある時の挙動を調べてみました。

まずは下のようにWKWebViewを2つ並べます。

import UIKit
import WebKit

class ViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        
        let rect1 = CGRect(x: 0, y: 0, width: view.frame.width, height: view.frame.height / 2 - 10)
        let webView1 = WKWebView(frame: rect1)
        webView1.load(URLRequest(url: URL(string: "https://google.co.jp")!))
        view.addSubview(webView1)
        
        let rect2 = CGRect(x: 0, y: view.frame.height / 2 + 10, width: view.frame.width, height: view.frame.height / 2 - 10)
        let webView2 = WKWebView(frame: rect2)
        webView2.load(URLRequest(url: URL(string: "https://google.co.jp")!))
        view.addSubview(webView2)
    }
}

実行すると下のようにWebViewが2つ並んでいる事が分かります。

f:id:llcc:20180426120832p:plain

この状態で片方でTwitterにログインするともう一方でもログイン状態になります。
以前「一緒のWKProcessPoolを使えばcookieも同期される」と聞いてたので、同じWKProcessPoolを使ってないのに共通化されてたのは予想外でした。

f:id:llcc:20180426121622p:plain

念の為2つのWKProcessPoolを比較したんですが別のインスタンスでした。

print(webView1.configuration.processPool === webView2.configuration.processPool) // → false

公式ドキュメントを読んだ所、process poolが一緒なら同じprocessを使うとあるので、これはcookieの共通化に関わっていそうです。

The process pool associated with a web view is specified by its web view configuration. Each web view is given its own Web Content process until an implementation-defined process limit is reached; after that, web views with the same process pool end up sharing Web Content processes.

WKProcessPool - WebKit | Apple Developer Documentation

その後調べていたら、cookie共通化にはWKProcessPoolではなくWKWebsiteDataStoreを使うという記事を見つけました。

stackoverflow.com

もしかすると「cookieが共通化されているのは同じWKWebsiteDataStoreを使っているからでは?」と思い実験してみました。
試しに下のようなコードを書いたらたしかに同じWKWebsiteDataStoreを使っていました。

print(webView1.configuration.websiteDataStore === webView2.configuration.websiteDataStore) // → true

どうやらWKWebViewはデフォルトでWKWebsiteDataStore.defaultを使っているようです。

webView1.configuration.websiteDataStore === WKWebsiteDataStore.default()

違うWKWebsiteDataStoreを使ったらどうなるか確認する為、下のように片方のwebsiteDataStoreにWKWebsiteDataStore.nonPersistent()をセットしました。

class ViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        
        let conf1 = WKWebViewConfiguration()
        conf1.websiteDataStore = WKWebsiteDataStore.nonPersistent()
        let rect1 = CGRect(x: 0, y: 0, width: view.frame.width, height: view.frame.height / 2 - 10)
        let webView1 = WKWebView(frame: rect1, configuration: conf1)
        webView1.load(URLRequest(url: URL(string: "https://google.co.jp")!))
        view.addSubview(webView1)
        
        let conf2 = WKWebViewConfiguration()
        let rect2 = CGRect(x: 0, y: view.frame.height / 2 + 10, width: view.frame.width, height: view.frame.height / 2 - 10)
        let webView2 = WKWebView(frame: rect2, configuration: conf2)
        webView2.load(URLRequest(url: URL(string: "https://google.co.jp")!))
        view.addSubview(webView2)
    }
}

実行すると、cookieが共通化されていない事が分かります。

f:id:llcc:20180426123244p:plain

その後WKWebsiteDataStoreは別、WKProcessPoolは同じものを使っているという状態も試したんですが、cookieは共通化されませんでした。
そのため、cookieの共通化はWKWebsiteDataStoreに任せるのが良さそうです。

class ViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        
        let processPool = WKProcessPool()
        
        let conf1 = WKWebViewConfiguration()
        conf1.websiteDataStore = WKWebsiteDataStore.nonPersistent()
        conf1.processPool = processPool
        let rect1 = CGRect(x: 0, y: 0, width: view.frame.width, height: view.frame.height / 2 - 10)
        let webView1 = WKWebView(frame: rect1, configuration: conf1)
        webView1.load(URLRequest(url: URL(string: "https://google.co.jp")!))
        view.addSubview(webView1)
        
        let conf2 = WKWebViewConfiguration()
        conf2.processPool = processPool
        let rect2 = CGRect(x: 0, y: view.frame.height / 2 + 10, width: view.frame.width, height: view.frame.height / 2 - 10)
        let webView2 = WKWebView(frame: rect2, configuration: conf2)
        webView2.load(URLRequest(url: URL(string: "https://google.co.jp")!))
        view.addSubview(webView2)
    }
}