HTTPCookieStorageの共有インスタンスの暗黙的な振る舞いの調査メモ

iOS における Cookie ストレージ [HTTPCookieStorage](https://developer.apple.com/documentation/foundation/httpcookiestorage) にはシングルトンな [shared](https://developer.apple.com/documentation/foundation/httpcookiestorage/1416095-shared) 共有インスタンスが提供されています。これは、アプリの各所で暗黙的に使用されるため、普段意識して利用することはあまりありません。ただ、保存されている Cookie をコントロールする必要が出てきた時に、その暗黙的な動作を把握していないとうまくコントロールできません。このあたりについて調査した結果をメモします。

以下の調査結果は、2019年3月末時点での公式ドキュメントや、Xcode10.1, iOS12 で動作レベルで確認した結果となります。

## どこで使用されているのか？

### UIWebView

iOS 12 で Deprecated になったレガシーなウェブビュー・コンポーネント [UIWebView] (https://developer.apple.com/documentation/uikit/uiwebview) では Cookie のストレージとして HTTPCookieStorage の共有インスタンス shared が使用されます。これは [HTTPCookieStorage](https://developer.apple.com/documentation/foundation/httpcookiestorage) のリファレンスに下記の通り明記されています。

> UIWebView instances within an app inherit the parent app's shared cookie storage.

なお UIWebView で使用する HTTPCookieStorage を変更する手段は提供されていないようです。

### URLSession

iOS でネットワークデータ転送を行う [URLSession](https://developer.apple.com/documentation/foundation/urlsession) にはシングルトンな [shared](https://developer.apple.com/documentation/foundation/urlsession/1409000-shared) インスタンスが提供されています。このインスタンスには、データ転送時の振る舞いやポリシーを定義する [URLSessionConfiguration](https://developer.apple.com/documentation/foundation/urlsessionconfiguration) としてデフォルトの [default](https://developer.apple.com/documentation/foundation/urlsessionconfiguration/1411560-default) インスタンスが設定されていますが、このデフォルトインスタンスのプロパティ [httpCookieStorage](https://developer.apple.com/documentation/foundation/urlsessionconfiguration/1411599-httpcookiestorage) が HTTPCookieStorage の共有インスタンスになっています。つまり、

- URLSession の共有インスタンス shared
- URLSessionConfiguration のデフォルト default を指定した URLSession インスタンス

は、HTTPCookieStorage の共有インスタンスを使用することになります。

### NSURLConnection

iOS 9 で Deprecated になっているレガシーなネットワークデータ転送機能 [NSURLConnection](https://developer.apple.com/documentation/foundation/nsurlconnection) も HTTPCookieStorage の共有インスタンスが使用されているようです（が、すでに廃止されたようなものなので詳しく調べていません）。

## 他の気になる点

### 永続化されるのか？

永続化されているようです。iOS 12 シミュレーターで確認した限りでは、アプリ Sandbox 内の `Library/Cookies` ディレクトリに保存されているようでした。

### 変更を検知するには？

[NotificationCenter](https://developer.apple.com/documentation/foundation/notificationcenter) で [NSHTTPCookieManagerCookiesChanged](https://developer.apple.com/documentation/foundation/nsnotification/name/1409500-nshttpcookiemanagercookieschange) の通知を監視することで HTTPCookieStorage の共有インスタンスに Cookie が追加された等の変更を検知することができます。

### WKWebView の Cookie は？

[WKWebView](https://developer.apple.com/documentation/webkit/wkwebview) では Cookie の管理は、インスタンス生成時に設定された [WKWebViewConfiguration](https://developer.apple.com/documentation/webkit/wkwebviewconfiguration) の [WKWebsiteDataStore](https://developer.apple.com/documentation/webkit/wkwebsitedatastore) (が持つ [WKHTTPCookieStore](https://developer.apple.com/documentation/webkit/wkhttpcookiestore))によって管理されます。特に設定しなかった場合は [WKWebsiteDataStore.default()](https://developer.apple.com/documentation/webkit/wkwebsitedatastore/1532937-default) で得られるデフォルトの共有インスタンスが使用され、Cookie は永続化されるようです。Cookie 等が永続化されないプライベートブラウジング用の [WKWebsiteDataStore.nonPersistent()](https://developer.apple.com/documentation/webkit/wkwebsitedatastore/1532934-nonpersistent) も用意されています。

HTTPCookieStorage の共有インスタンスと WKWebsiteDataStore のデフォルトの共有インスタンスの間では、不定期に Cookie の同期のようなものが行われているように見えますが、正確な挙動は把握できませんでした。私の印象レベルでは下記のようでした。

- HTTPCookieStorage -> WKWebsiteDataStore は比較的即座に同期される
- WKWebsiteDataStore -> HTTPCookieStorage は同期に時間がかかる

WKWebsiteDataStore のデフォルトの共有インスタンスを使用している WKWebView 同士では Cookie が共有されているようです。しかし、有効期限がデフォルト（ブラウザのセッションが終わるまで）になっている場合、その Cookie はその WKWebView インスタンスがいなくなった時点で無効になってしまうようでした。その後にインスタンス化される WKWebView にその Cookie を引き継ぎたい場合は、その二つの WKWebView が同じブラウザのセッションであるように明示してあげる必要があります。それぞれの WKWebView の WKWebViewConfiguration に設定されている [WKProcessPool](https://developer.apple.com/documentation/webkit/wkprocesspool) を同じインスタンスを設定してあげることでそれが可能となるようです。


**WKWebViewとその設定に関するプロパティ等の構成**

- **WKWebView**
    - configuration: **WKWebViewConfiguration**
        - processPool: **WKProcessPool**
        - websiteDataStore: **WKWebsiteDataStore**
            - httpCookieStore: **WKHTTPCookieStore**