swiftui-webkit について
SwiftUI WebKitは、iOS 26などのプラットフォームでネイティブWebKit APIを使い、SwiftUIにウェブコンテンツを組み込む開発者向けガイドです。ページ状態、ナビゲーションポリシー、JavaScript連携、アプリ独自のローカルコンテンツを扱います。
主な機能
- 01SwiftUIネイティブのWebViewとWebPage
- 02ページ読み込みと状態監視
- 03ナビゲーションポリシー制御
- 04引数付きJavaScript呼び出し
- 05カスタムURLスキームでのローカルコンテンツ
活用シーン
- 01アプリ内でのウェブコンテンツ表示
- 02ページ読み込みとナビゲーション状態の監視
- 03外部ドメインへのリンク転送
- 04オフラインHTMLドキュメントの表示
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ dpearson2699/ swift-ios-skills --skill swiftui-webkitインストール後、Claude Code で/swiftui-webkitを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
evals/evals.jsonreferences/loading-and-observation.mdlocal-content-and-custom-schemes.mdmigration-and-fallbacks.mdnavigation-and-javascript.md詳細
SwiftUI WebKit
iOS 26、iPadOS 26、macOS 26、visionOS 26 向けに導入されたネイティブの WebKit-for-SwiftUI API を使用して、SwiftUI に Web コンテンツを埋め込み、管理します。アプリに統合された Web 表示領域、アプリが所有する HTML コンテンツ、JavaScript を利用したページ操作、またはカスタムナビゲーションポリシーの制御が必要な場合に、このスキルを使用してください。
目次
- 適切な Web コンテナーを選ぶ
- Web コンテンツを表示する
- WebPage を使用した読み込みと監視
- ナビゲーションポリシー
- JavaScript 連携
- ローカルコンテンツとカスタム URL スキーム
- WebView のカスタマイズ
- よくある間違い
- レビュー用チェックリスト
- 参考資料
適切な Web コンテナーを選ぶ
用途に合った、最も限定的なツールを使用してください。
| 必要な用途 | 標準の選択肢 |
|---|---|
| SwiftUI でアプリが所有する Web コンテンツを埋め込む | WebView + WebPage |
| iOS/iPadOS で Safari の動作を伴うモーダルブラウジング | SFSafariViewController |
| macOS または visionOS でブラウザーに遷移する | openURL / デフォルトブラウザー |
| OAuth またはサードパーティーのサインイン | ASWebAuthenticationSession |
| iOS 26 未満へのバックデプロイ、または従来の WebKit にしかない機能の使用 | WKWebView フォールバック |
新しい API で機能を実現できる場合、iOS 26 以降を対象とする最新の SwiftUI アプリでは WebView と WebPage を優先してください。Apple の WWDC25 のガイダンスでは、SwiftUI アプリ内の既存の UIKit/AppKit WebKit ラッパーは、すべてのフォールバックを一律に削除するのではなく、移行を試すのに適した候補として扱われています。
OAuth に埋め込み Web ビューを使用しないでください。OAuth には引き続き ASWebAuthenticationSession のフローを使用します。
Web コンテンツを表示する
URL の表示だけが必要で、SwiftUI の状態がナビゲーションを制御する場合は、シンプルな WebView(url:) 形式を使用してください。
import SwiftUI
import WebKit
struct ArticleView: View {
let url: URL
var body: some View {
WebView(url: url)
}
}
リクエストの直接読み込み、状態の監視、JavaScript の呼び出し、またはナビゲーション動作のカスタマイズが必要な場合は、WebPage を作成してください。
WebPage を関連付けられる WebView は、一度に 1 つだけです。複数の Web ビューを同時に表示する場合は、個別の WebPage インスタンスを作成してください。
@Observable
@MainActor
final class ArticleModel {
let page = WebPage()
func load(_ url: URL) async throws {
for try await _ in page.load(URLRequest(url: url)) {
}
}
}
struct ArticleDetailView: View {
@State private var model = ArticleModel()
let url: URL
var body: some View {
WebView(model.page)
.task {
try? await model.load(url)
}
}
}
詳しい例については、references/loading-and-observation.md を参照してください。
WebPage を使用した読み込みと監視
WebPage は @MainActor の監視可能な型です。SwiftUI でページの状態が必要な場合に使用してください。
一般的な読み込みの入り口:
load(URLRequest)load(URL)load(html:baseURL:)load(_:mimeType:characterEncoding:baseURL:)
一般的な監視可能プロパティ:
titleurlisLoadingestimatedProgresscurrentNavigationEventbackForwardList
struct ReaderView: View {
@State private var page = WebPage()
var body: some View {
WebView(page)
.navigationTitle(page.title ?? "Loading")
.overlay {
if page.isLoading {
ProgressView(value: page.estimatedProgress)
}
}
.task {
do {
for try await _ in page.load(URLRequest(url: URL(string: "https://example.com")!)) {
}
} catch {
// Handle load failure.
}
}
}
}
すべてのナビゲーションに反応する必要がある場合は、単一のプロパティを確認するだけでなく、ナビゲーションのシーケンスを監視してください。
Task {
do {
for try await event in page.navigations {
// Handle started, redirect, committed, or finished events.
}
} catch {
// Handle WebPage.NavigationError or cancellation.
}
}
より堅牢なパターンや読み込みシーケンスの例については、references/loading-and-observation.md を参照してください。
ナビゲーションポリシー
WebPage.NavigationDeciding を使用すると、リクエストまたはレスポンスに基づいてナビゲーションを許可、キャンセル、またはカスタマイズできます。
一般的な用途:
- アプリが所有するドメインを埋め込み Web ビュー内にとどめる
- 外部ドメインをキャンセルし、
openURLで引き渡す - 特別なコールバック URL をインターセプトする
NavigationPreferencesを調整する
@MainActor
final class ArticleNavigationDecider: WebPage.NavigationDeciding {
var urlToOpenExternally: URL?
func decidePolicy(
for action: WebPage.NavigationAction,
preferences: inout WebPage.NavigationPreferences
) async -> WKNavigationActionPolicy {
guard let url = action.request.url else { return .allow }
if url.host == "example.com" {
return .allow
}
urlToOpenExternally = url
return .cancel
}
}
アプリレベルのディープリンクルーティングは、ナビゲーションのスキルで扱ってください。このスキルでは、埋め込み Web コンテンツ内で発生するナビゲーションを扱います。
詳しいパターンについては、references/navigation-and-javascript.md を参照してください。
JavaScript 連携
callJavaScript(_:arguments:in:contentWorld:) を使用して、ページ上で JavaScript 関数を評価します。
ラップされた関数宣言や呼び出し式ではなく、JavaScript 関数の本体を渡してください。信頼できない文字列をスクリプトに埋め込むのではなく、Swift から渡す値には arguments を使用してください。
let script = """
const headings = [...document.querySelectorAll('h1, h2')];
return headings.map(node => ({
id: node.id,
text: node.textContent?.trim()
}));
"""
let result = try await page.callJavaScript(script)
let headings = result as? [[String: Any]] ?? []
arguments ディクショナリを介して値を渡し、返された Any を必要な Swift の型にキャストできます。
let result = try await page.callJavaScript(
"return document.getElementById(sectionID)?.getBoundingClientRect().top ?? null;",
arguments: ["sectionID": selectedSectionID]
)
空の結果と JavaScript の null の結果は、意図的に処理してください。明示的な return がない場合は nil が返され、明示的な JavaScript の null は NSNull を返します。
重要な境界として、ネイティブの SwiftUI WebKit API は Swift から JavaScript への呼び出しを明確にサポートしていますが、WKScriptMessageHandler に直接置き換えられる明白な手段は提供していません。大まかな JS からネイティブへの通知が必要な場合は、カスタムのナビゲーションやコールバック URL のパターンが使えますが、1 対 1 の置き換えが保証されたものではなく、回避策のパターンとして説明してください。
references/navigation-and-javascript.md を参照してください。
ローカルコンテンツとカスタム URL スキーム
アプリにバンドルされた HTML、オフラインのドキュメント、またはカスタムスキームで提供するアプリのリソースが必要な場合は、WebPage.Configuration と URLSchemeHandler を使用してください。
var configuration = WebPage.Configuration()
configuration.urlSchemeHandlers[URLScheme("docs")!] = DocsSchemeHandler(bundle: .main)
let page = WebPage(configuration: configuration)
for try await _ in page.load(URL(string: "docs://article/welcome")!) {
}
次の用途で使用します。
- バンドルされたドキュメントや記事コンテンツ
- オフラインの HTML/CSS/JS アセット
- カスタムスキームを使用した、アプリ所有のリソース読み込み
通常のリモートコンテンツにカスタムスキームを過剰に使用しないでください。サーバーでホストされるページには、標準の HTTPS を優先してください。
references/local-content-and-custom-schemes.md を参照してください。
WebView のカスタマイズ
WebView の修飾子を使用して、意図するブラウジング体験に合わせます。
便利な修飾子と関連 API:
webViewBackForwardNavigationGestures(_:)findNavigator(isPresented:)webViewScrollPosition(_:)webViewOnScrollGeometryChange(...)
ユーザー体験に必要な場合にのみ適用してください。
- 複数のページを訪れる可能性が高い場合は、戻る/進むジェスチャを有効にします。
- コンテンツがドキュメント形式の場合は、「ページ内を検索」を追加します。
- アプリにサイドバー、目次、またはその他の明示的なナビゲーション手段がある場合にのみ、スクロール位置を同期します。
ここでも Apple の HIG が適用されます。適切な場合は戻る/進むナビゲーションをサポートしますが、アプリの Web ビューを汎用ブラウザーにしないでください。
よくある間違い
- iOS 26 以降の SwiftUI アプリで、まず
WebViewとWebPageを使うのではなく、デフォルトでWKWebViewラッパーを使用する ASWebAuthenticationSessionではなく、埋め込み Web ビューを OAuth に使用する- 状態、JS、またはナビゲーションの制御が必要になってから
WebPageを導入する。つまり、最初に単純なWebView(url:)の経路を構築してしまう callJavaScriptをWKScriptMessageHandlerの直接の置き換えとして扱う- 関数本体だけではなく、呼び出し可能な JavaScript ラッパーを
callJavaScriptに渡す - ナビゲーションの失敗によってシーケンスが throw して終了するにもかかわらず、
try/catchを使わずにpage.navigationsを反復処理する - 同じ
WebPageを、表示中の複数のWebView値にバインドする - 外部ドメインを埋め込み領域の外で開くべき場合にも、すべてのリンクをアプリ内にとどめる
- macOS や visionOS で
SFSafariViewControllerをプラットフォーム共通の外部ブラウジング手段として扱い、デフォルトブラウザーやopenURLの動作を使用しない - WebView を中心にブラウザー風のアプリシェルを構築し、目的を絞った埋め込み体験にしない
- HTTPS で読み込めばよいコンテンツにカスタム URL スキームを使用する
WebPageがメインアクターに分離されていることを忘れる
レビューチェックリスト
- iOS 26 以降の SwiftUI の Web コンテンツでは、
WebViewとWebPageをデフォルトの方法として使用している - 認証フローでは、埋め込み Web ビューではなく
ASWebAuthenticationSessionを使用している - アプリで状態の監視、JS の呼び出し、またはポリシー制御が必要な場合は、
WebPageを使用している - ナビゲーションポリシーでは、アプリが実際に所有する URL、またはリダイレクトが必要な URL のみをインターセプトしている
- 適切な場合は、外部ドメインを外部で開いている
- JavaScript の戻り値は、具体的な Swift 型に安全にキャストしている
-
callJavaScriptでは関数本体を使用し、Swift の値をarguments経由で渡している -
page.navigationsのループではfor try awaitを使用し、スローされたナビゲーションエラーを処理している - 表示される各
WebView(page)が、それぞれ異なるWebPageを所有している - カスタム URL スキームは、実際にアプリが所有するリソースにのみ使用している
- 複数ページのブラウジングが想定される場合、戻る/進むジェスチャーまたはコントロールを有効にしている
-
SFSafariViewControllerは iOS/iPadOS の Safari スタイルのモーダルブラウジングに限定し、macOS および visionOS のブラウザーで開く操作ではプラットフォームのデフォルトのブラウザー動作を使用している - Web エクスペリエンスは、薄いブラウザーシェルのように振る舞うのではなく、的を絞ったネイティブの価値を提供している
-
WKWebViewへのフォールバックは、デプロイメントターゲットまたは必要な API が利用できないことを理由として正当化されている
参考資料
- 読み込みと監視:references/loading-and-observation.md
- ナビゲーションと JavaScript:references/navigation-and-javascript.md
- ローカルコンテンツとカスタムスキーム:references/local-content-and-custom-schemes.md
- 移行とフォールバック:references/migration-and-fallbacks.md