起きた問題
WKWebView
を使ってウェブページを表示している箇所で、デフォルトのuserAgentの末尾に独自の文字列を付加したuserAgentを使ってリクエストを送る実装を採用していました。
しかし、この箇所をiOS 12.0で実行すると、ウェブページ側には独自の文字列が付加されていない、デフォルトのuserAgentが届いてしまっていました。
修正前の実装
// `WKWebView`型のwebViewというメンバー変数が宣言されているものとする
func load(url: URL) {
guard let request = URLRequest(url: url) else {
return
}
webView.evaluateJavaScript("navigator.userAgent") { (userAgent, error) in
if let defaultUserAgent = userAgent {
self.webView.customUserAgent = "\(defaultUserAgent) SomeCustomUserAgent"
}
self.webView.load(request)
}
}
修正後の実装
デフォルトのuserAgentの取得元を別のWKWebViewインスタンスにすれば、問題なくuserAgentが上書きされました。
// `WKWebView`型のwebViewというメンバー変数が宣言されているものとする
func load(url: URL) {
guard let request = URLRequest(url: url) else {
return
}
var dummyWebView: WKWebView? = WKWebView() // デフォルトのUserAgentを取得するための別インスタンスを作る
dummyWebView.evaluateJavaScript("navigator.userAgent") { (userAgent, error) in
dummyWebView = nil // evaluateJavaScript()が完了するまでdummyWebViewが開放されないよう、クロージャ内で参照しておく
if let defaultUserAgent = userAgent {
self.webView.customUserAgent = "\(defaultUserAgent) SomeCustomUserAgent"
}
self.webView.load(request)
}
}
上記の実装にした理由
推測の域を出ないのですが、iOS 12からWKWebViewの仕様が変わって一度userAgentのフィールドを参照すると(= WKWebView#evaluateJavaScript()
で navigator.userAgent
フィールドにアクセスすると)、直近のリクエストが終了するまでの間userAgentの値をキャッシュする仕組みが入ったのでは無いかと予想しました。
その仮設を基に、 navigator.userAgent
にアクセスしないままcustomUserAgentに値を設定する方法を探った結果、上記のように WKWebView#load()
を実行したいインスタンスとは別のインスタンスで WKWebView#evaluateJavaScript()
を実行する方法を見つけました。
参考リンク
iOS 12 WKWebview set customUserAgent not work? - Stack Overflow