SwiftのURLSessionでCookieを取得しWebViewに渡す方法
この記事は2023/01/30に作成されました。
いろいろな言語のプロジェクトに携わっていることもあり、たまに言語の違いで混乱することがあるSekiguchiです。なんで、このメソッドが使えないんじゃ~~!?とか思っていたら違う言語の機能だったり。
皆さまはどうやって複数言語を使い分けてますか??
さて、SwiftでのiOS開発で、どうしたものかと思ったところに触れたので、備忘録を兼ねつつご紹介。
Swiftでサーバーとの通信は、URLSessionを使って取得するのが定番かと思いますが、今回携わったプロジェクトでは、認証時のみNativeのコードでURLSessionを利用し、以降はWKWebViewを使う、という構成でした。この場合、WKWebViewでは認証したときの情報がセッション情報として必要になり、これは認証時にCookieデータとして送られてきます。
つまり、Nativeで受け取ったCookieのデータをWKWebViewでも使いたい、と言うことになるのですが、現状のSwiftでは自動的にCookieデータを共有する機能はありません。
なので、URLSessionで何とかする必要があるのですが、イマイチ明確な情報が無かったので、まとめておきます。Swiftは5.3を利用しています。
Cookieは通常、HTTPヘッダー内にSet-Cookieというヘッダーとともに送られてくるので、この値を取りだしてあげればOKなのですが、URLSessionの場合、レスポンスとして送られてくるデータにこのデータは含まれていません。
request.httpMethod = "POST" request.timeoutInterval = 10 request.httpBody = postString.data(using: .utf8) let task = session.dataTask(with: request, completionHandler: {(data,response,error) in のときにresponseに入ってこない
となると、Cookieはどこにいったのか、となりますが、どうもURLSessionはCookieが含まれていた場合、自動的に格納して処理するようになっているようです。そのため、Cookieデータを参照することが容易にできないようになってしまっています。
CookieはHTTPCookieStorageに格納される
CookieはHTTPCookieStorage.sharedに格納されるため、このオブジェクトを参照し、Cookieデータを取り出します。
let cookieStorage = HTTPCookieStorage.shared
let cookies = cookieStorage.cookies as! [HTTPCookie]//Cookieデータを取得
cookiesの中にCookieのデータが入ってくるのですが、必要なデータだけを取り出します。
for cookie in cookies {
if(cookie.domain == domain){//ドメインが指定したものだった場合
UserDefaults.standard.set(cookie.name,forKey:"cookiename")
UserDefaults.standard.set(cookie.value,forKey:"cookievalue")
}
}
今回は、nameプロパティとvalueプロパティの値を取得し、cookiename、cookievalueという名前でそれぞれUserDefaultsに保存しています。
これで、URLSessionからCookieデータを取り出すことができました。
WKWebViewに対してCookieを適用
あとはWKWebViewに対して、取得したCookieを適用します。
var config:WKWebViewConfiguration!
var mainwebview:WKWebView!
config = WKWebViewConfiguration()
mainwebview = WKWebView(frame: view.frame,configuration: config)
view.addSubview(mainwebview)
デフォルトのWKWebViewConfiguration()を通してcongigをWKWebViewに適用します。
これだと、Cookieデータが適用されていない状態のWKWebViewになるので、先ほど取得したCookieデータを適用します。
let cookie = HTTPCookie(properties: [
HTTPCookiePropertyKey.name:UserDefaults.standard.string(forKey: "cookiename")!,
HTTPCookiePropertyKey.value:UserDefaults.standard.string(forKey: "cookievalue")!,
HTTPCookiePropertyKey.domain:domain,
HTTPCookiePropertyKey.path:"/"
])!
let url = URL(string:"http://example.com")
config.websiteDataStore.httpCookieStore.setCookie(cookie){
[weak self] in
guard let self = self else { return }
self.mainwebview.load(URLRequest(url: self.url!))
}
UserDefaultsに格納したCookieデータを取り出します。最低限、cookie名と値があればOKですが、利用するドメインを指定する必要があるため、Cookieを送出してきたサーバーのドメイン名をdomain(もしhttp://example.comのサーバーから送られてきているなら、example.comがドメイン)として適用します(ここではdomainという変数にドメイン名を格納していて、それを適用しています。)
pathは"/"で、問題無いと思いますが、状況によって変更します。これで最低限のCookieデータが作成できたので、WKWebviewが外部サイトを参照するときに作成したCookieを適用します。
一度CookieデータをWKWebViewに適用すれば、WKWebViewを破壊するまでは生き続けます。
これで、NativeからWKWebViewに対してCookieデータを渡すことができました。
URLSessionはCookieなどを意識せずに処理してくれるので、便利なのですが、ちょっと変わったことをするときは工夫が必要ですね。
CTO/sekiguchi