[Swift]Cookieの削除

ざっくりまとめ。

  • WKWebsiteDataStore.removeData(ofTypes:modifiedSince:completionHandler:) でざっくり削除できる
  • ドメイン単位でやるなら、 WKWebsiteDataStore.removeData(ofTypes:for:completionHandler:) を利用して削除する
  • さらに詳細に条件を指定したいなら WKHTTPCookieStore.delete(_:completionHandler:) を利用して削除する

です。

意外とめんどかった...

環境

  • Xcode v10.1
  • Swift v4.2
  • iOS 11+

ざっくり全部削除する

これはすごくシンプルにかけます。

WKWebsiteDataStore.default().removeData(ofTypes: [WKWebsiteDataTypeCookies], modifiedSince: Date(timeIntervalSince1970: 0)) {
    print("removed")
}

modifiedSince をめっちゃ前にすることで、実質全削除っていう感じです。👍

ドメイン単位で削除する

一気に全部削除すると困る場合は結構あるかと、で、その縛りでドメインがくるのも想像に難くないところです。
この場合、先に紹介したものの他に removeData(ofTypes:for:completionHandler:) があるのでそちらを使います。
for: に対象の WKWebsiteDataRecord を指定して削除することになるので、一旦取得します。そのときに、対象となる WKWebsiteDataRecord をドメインで限定したら出来るというわけ。

let dataStore = WKWebsiteDataStore.default()
dataStore.fetchDataRecords(ofTypes: [WKWebsiteDataTypeCookies]) { (records) in
    
    let targetRecords = records.filter { (record) -> Bool in
        // 対象のドメインで限定
        return record.displayName == "example.com"
    }
    
    dataStore.removeData(ofTypes: [WKWebsiteDataTypeCookies], for: targetRecords) {
        print("removed")
    }
}

これで、ドメイン単位での削除が可能になります💪
この方法だと、sub.example.com などのサブドメインも対象になります。
ただ...いや、そこは分けたい。厳格にドメインを指定したい場合などは困ります。。

もっと詳細に削除する対象を限定したい場合

上記2つで紹介したものをは少し変わって、WKHTTPCookieStore.delete(_:completionHandler:)というのを使います。
これは削除する HTTPCookie を直接指定するタイプなので、こちらも一旦 HTTPCookie を取得する必要があります。
HTTPCookieWKWebsiteDataRecord と違い、もっと詳細なデータが取れるので、そこで必要な条件で限定したいくという流れになります。

let cookieStore = WKWebsiteDataStore.default().httpCookieStore
cookieStore.getAllCookies { (cookies) in
    
    for cookie in cookies where cookie.domain = "sub.example.com" {
        cookieStore.delete(cookie) {
            print("deleted")
        }
    }
}

これでサブドメインのみを対象にできます。
HTTPCookie はドメイン以外にもいろいろ取れるので必要なもので限定していけば!✨

ただし...

cookieStore.getAllCookies(_:) は一度ロードした cookie を取得してくるものなので、 WKWebView で一度も load していなかった場合など(アプリ起動直後とか)は空で返ってきます。
なので、WKWebsiteDataStore.fetchDataRecords(ofTypes:completionHandler:) を呼んでからやったほうが安全です。
(かならず WebView ロード等処理されたあとで扱うというのであれば不要ですが)

let dataStore = WKWebsiteDataStore.default()
// 一度fetchさせる
dataStore.fetchDataRecords(ofTypes: [WKWebsiteDataTypeCookies]) { _ in
    
    // で、先に紹介した方法で削除する
    let cookieStore = dataStore.httpCookieStore
    cookieStore.getAllCookies { (cookies) in
        
        for cookie in cookies where cookie.domain = "example.com" {
            cookieStore.delete(cookie) {
                print("deleted")
            }
        }
    }
}

ネストが深い!😇
こうしておくと、getAllCookiesが空になるのを防げます。

補足

サンプルコードをみてわかるとおもいますが、Cookie 以外にもキャッシュデータなんかも扱えます。

  • WKWebsiteDataTypeCookies
  • WKWebsiteDataTypeMemoryCache
  • WKWebsiteDataTypeDiskCache
  • WKWebsiteDataTypeSessionStorage

などなど...いろいろあるので。

WKProcessPool

WKProcessPool を使って複数 WKWebView の共有をしている場合は、上記の方法で cookie を削除しつつ、WKProcessPool も初期化する必要があるみたいなので、
利用している場合は注意が必要です。

参考