新規ウィンドウ要求をナビゲーションに変換して iframe リンクをハンドル
iOS の Hotwire Native が、iframe 内のリンクで新しいウィンドウを要求された場合に自動的に Navigator を使って訪問(visit)を開始するようになりました。これにより、サブクラスで WKUIDelegate を実装していた従来の回避策が不要になり、外部アプリへの遷移や内部ルーティングがシームレスに行えるようになります。
背景
従来、WKUIDelegate の webView(_:createWebViewWith:for:windowFeatures:) が呼び出されても iOS クライアントは何もせずにウィンドウ作成を放棄していました。結果として、YouTube 埋め込みなど iframe 内のリンクがタップされても機能しないか、開発者が独自にサブクラス化してハンドリングしなければなりませんでした。Android 側では HotwireWebChromeClient が同様のケースを Navigator 経由で処理しており、機能差がユーザー体験に影響していました。今回の PR は iOS でも同等の挙動を実装し、プラットフォーム間の一貫性を確保することを目的としています。
技術的な変更
WKUIController.swift に新たに webView(_:createWebViewWith:for:windowFeatures:) の実装が追加され、リクエストが有効かつメインフレームでない場合に webView.load(navigationAction.request) を呼び出して同一 WebView でページ遷移させ、nil を返すことでウィンドウ生成を抑制します。
open func webView(
_ webView: WKWebView,
createWebViewWith configuration: WKWebViewConfiguration,
for navigationAction: WKNavigationAction,
windowFeatures: WKWindowFeatures
) -> WKWebView? {
guard navigationAction.request.url != nil else { return nil }
if let targetFrame = navigationAction.targetFrame, targetFrame.isMainFrame { return nil }
webView.load(navigationAction.request)
return nil
}
ExternalNavigationWebViewPolicyDecisionHandler.swift では、無効な URL スキーム(about, data, file, javascript)を除外するロジックが追加され、該当スキームは単に .cancel されてルーティングが行われません。デフォルト引数で invalidSchemes を初期化し、既存コードへの影響を最小限に抑えています。
public let invalidSchemes: Set<String>
public init(invalidSchemes: Set<String> = ["about", "data", "file", "javascript"]) {
self.invalidSchemes = invalidSchemes
}
public func handle(... ) -> WebViewPolicyManager.Decision {
if let scheme = navigationAction.request.url?.scheme,
invalidSchemes.contains(scheme) {
return .cancel
}
if let url = navigationAction.request.url { navigator.route(url) }
return .cancel
}
テストスイートも大幅にリファクタリングされ、WebViewPolicyNavigationSimulator が新たに導入されました。シミュレータはクリックとフォーム送信のシナリオを列挙し、HTML コンテンツをロードして WKNavigationAction を取得できるようになり、既存テストはすべて新しいシミュレータに置き換えられました。これにより、about: や data: スキームのリンクが正しく除外されることや、target="_blank" リンクが Navigator 経由で処理されることが検証されています。
設計判断
非破壊的拡張 を第一原則とし、既存の WKUIDelegate メソッドシグネチャは変更せずに内部ロジックだけを追加しました。Navigator が使用されていない環境ではデフォルト実装が何もしないため、従来の動作と互換性が保たれます。また、無効スキームの除外はハンドラレベルで行い、全体のポリシー決定フローに影響を与えないシンプルなガードとして実装されています。これにより、開発者は新たな設定やサブクラス化を行うことなく、iframe 内リンクの新規ウィンドウ要求を自然に処理できるようになりました。
まとめ
本 PR は iOS の Hotwire Native が iframe 内のリンクで新しいウィンドウ要求を受けた際に自動的に Navigator を使って訪問を開始する機能を追加し、Android と同等のユーザー体験を実現しました。実装は既存 API の拡張に留め、無効スキームの除外やテストインフラの刷新により安全性と可搬性を確保しています。