結論として、WKUserScriptInjectionTimeにatDocumentEnd
を設定していたことが原因だった。
事象
WKWebView生成時にWebViewのLocalStorageへ値を設定したあと、URLRequestでWebページを読み込む処理において、Web側でLocalStorageが読み取れない事象が発生した。
悩んだ原因
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!)
内でLocalStorageKeyの値を出力したときには値が確認できていたため「アプリ側では値はちゃんと設定できているな」と判断してしまった結果、事象の解決まで長引くことに・・・。
// webViewのローカルストレージにキーを設定
webView.configuration.userContentController.addUserScript(WKUserScript(
source: "localStorage.setItem('\(localStorageKey)', '\(key)');",
injectionTime: .atDocumentEnd,
forMainFrameOnly: true
))
/// WebViewの読み込み完了時に呼び出される
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
webView.evaluateJavaScript("localStorage.getItem('key')") { result, error in
if let error = error {
print(error)
return
}
print("LocalStorageKey: \(result ?? "nil")") // resultが出力される
}
}
試したこと
-
アプリ側でLocalStorageに値を設定したあと、Sleep()で数秒ディレイをかけてからURLRequestする。
→効果なし。変わらず。 -
サーバー側でリクエストを受けた後、数秒ディレイをかけてからLocalStorageを読み込む。
→効果あり。
ここでLocalStorageのセット or 読み込みのタイミングに問題があると把握。 -
〜数週間放置〜
-
いい加減に対応しないといけなくなり、printデバッグしつつコードを見直していたところ
atDocumentEnd
が目について「ん?」となる。-
atDocumentStart
:Web ページのドキュメント要素の作成後、他のコンテンツをロードする前にスクリプトを挿入する定数。 -
atDocumentEnd
:ドキュメントの読み込みが完了した後、他のサブリソースを読み込む前にスクリプトを挿入する定数。
-
-
「ほ〜ん・・・」
結論
WKUserScript
では指定したタイミングでJavaScriptをWebViewに注入することができる。
injectionTime
のパラメータを指定すると「WebViewのドキュメントの読み込みが完了した後」に注入するか「ドキュメントの読み込みが完了する前」に注入するか選択できる。
今回は「WebViewのドキュメントの読み込みが完了した後」にJavaScriptをWebViewに注入していたため、サーバー側でのLocalStorage読み取りタイミングの段階ではLocalStorageに値が設定されていなかったことで発生していた。
原因
WKUserScript
のコードをネット(ChatGPT)から拾ってきて深く考えずに使ったこと。
printデバッグで値が設定されていることを確認できていたため、アプリ側に問題があると真剣に考えていなかったこと。
修正後のコード
injectionTime
のパラメータを.atDocumentStart
に変更
// webViewのローカルストレージにキーを設定
webView.configuration.userContentController.addUserScript(WKUserScript(
source: "localStorage.setItem('\(localStorageKey)', '\(key)');",
injectionTime: .atDocumentStart,
forMainFrameOnly: true
))