概要
iOS 26.3 端末でのみ、アプリ内 WKWebView で開く特定のページが文字化けするというバグ報告を受けた。
調査の結果、iOS 26.3 で加わった WKWebView の挙動変更が原因だった。
調査
再現条件の絞り込み
- iOS 26.2 以前 → 正常
- iOS 26.3 → 文字化け
- iOS 26.4 → 正常(後述)
- 文字化けするのは一部のページのみ
端末や OS バージョンに依存し、かつ特定ページだけというのがヒントになった。
レスポンスヘッダーを確認
正常なページと文字化けするページのレスポンスヘッダーを curl で比較したところ、文字化けするページのレスポンスにだけ以下のヘッダーが含まれていた。
Content-Security-Policy: frame-ancestors 'self' https://hogehoge.com
Content-Security-Policy と frame-ancestors とは
Content-Security-Policy(CSP) は、Web サーバーがブラウザや WebView
に対して「このページをどう扱っていいか」を指示する HTTP レスポンスヘッダー。
その中の frame-ancestors ディレクティブは、「このページを別のページ(今回はWebView)などの中に埋め込んでいいのはどのオリジン(ドメイン)か」を制限するもの。
frame-ancestors 'self' https://hogehoge.com
↓ 意味
「このページを iframe で表示できるのは自分自身と hogehoge.com だけ」
これをブラウザ(や WKWebView)が受け取ったとき、表示元のオリジンが許可リストに含まれていなければ、コンテンツの表示をブロックする。
iOS 26.3 での変化
iOS 26.2 以前は frame-ancestors の値を WKWebView
が厳密に見ておらず、事実上スルーしていた。ところが iOS 26.3
からこれを厳密にチェックするようになり、許可リストに含まれていない
レスポンスをブロックするようになった。これが文字化けの原因だった。
iOS 26.4 での状況
iOS 26.4 では文字化けが発生しなくなった。
Apple からの公式なアナウンスは確認できていないが、この挙動変更による影響が想定より大きかったため、26.4 で一時的に戻した可能性がある(あくまで憶測)。
今回の詳細
今回の環境では、一部のレスポンスのみframe-ancestors ヘッダーが付与されていた。
本番と開発でドメインが異なるため、開発環境のレスポンスが返す frame-ancestorsの許可リストに開発 URL が含まれておらず、iOS 26.3 の WKWebViewにブロックされていた。対応方針については別途相談中。
まとめ
| OS |
frame-ancestors の扱い |
|---|---|
| iOS 26.2 以前 | WKWebView では事実上無視 |
| iOS 26.3 | 厳密にチェック・null 非許可ならブロック |
| iOS 26.4 | 26.2 以前の挙動に戻った(憶測) |
今回の教訓: 開発環境と本番環境でレスポンスヘッダーに差異がある場合、OS
アップデートのタイミングで予期せず問題が顕在化することがある。
↑て感じの記事を書いてって言ったら、ジェバンニもといClaudeくんが39秒でやってくれました。やったね。