Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
WebKit::WebView Essentials / Sapporo.swift #1
Search
Yutaro Muta
July 25, 2026
Technology
340
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
WebKit::WebView Essentials / Sapporo.swift #1
Yutaro Muta
July 25, 2026
More Decks by Yutaro Muta
See All by Yutaro Muta
`t*(42&t>>10)`だけで音楽が鳴る、Swiftで実装するBytebeat / iOSDC Japan 2026
yutailang0119
0
190
SwiftUI Inspectorが難しすぎる / Mobile Act OSAKA 18
yutailang0119
0
170
Google Nest CamとApple Vision frameworkと猫🐈🐈⬛ / onishi50
yutailang0119
0
450
Swift Concurrencyでのスケジュール処理を考える / Mobile Act OSAKA 17
yutailang0119
0
170
猫と暮らすネットワークカメラ生活🐈 ~Vision frameworkでペットを愛でよう~ / iOSDC Japan 2025
yutailang0119
0
510
猫と暮らす Google Nest Cam生活🐈 / WebRTC with Google Nest Cam
yutailang0119
0
360
Swiftの “private” を テストする / Testing Swift "private"
yutailang0119
0
370
Apple Vision Pro購入RTA 1泊3日弾丸ハワイツアー / RTA: Purchase Apple Vision Pro in Hawaii
yutailang0119
0
1.6k
個人開発のたのしみ / Enjoying personal development
yutailang0119
0
1.2k
Other Decks in Technology
See All in Technology
分析AIエージェントを育てる、動く環境を育てる
codatum
1
1.1k
Persisting Massive Data with Rails ~Designing for 60 billion rows, and fighting the bottlenecks~ Railsで挑む大量データ永続化 〜600億件を永続化するための設計とボトルネックとの戦い〜
occhi
0
730
エンタメ企業のM&Aを支えるデータ基盤 ― 統合から店舗のリアルタイム分析まで / Data Engineering Summit 2026
genda
0
180
継続的なAIコスト最適化
bgpat
1
340
Rustuna: Rustによる高速なOptuna実装
pfn
PRO
0
190
Conditional PED-ANOVA: Hyperparameter Importance in Hierarchical & Dynamic Search Spaces
pfn
PRO
0
130
大型犬好きによるPugの紹介
yamanoku
1
160
実践!Cloud Run ハンズオン!! / Cloud Run handson
y0hgi
2
280
re:Invent初参加で変わったこと、2回目にやってみたいこと(JAWS-UG彩の国埼玉 #12)
mhrtech
2
230
AI時代のPRレビューにどう向き合うか?
kairim0
1
240
NDIでApple Vision Proにリアルタイム映像送信
jyouryuusui
0
120
サブエージェントと Claude Mods で作る独自 Advisor ツールの話
kenichiodo
2
160
Featured
See All Featured
Designing Experiences People Love
moore
143
24k
Designing for humans not robots
tammielis
254
26k
Optimising Largest Contentful Paint
csswizardry
37
4k
What's in a price? How to price your products and services
michaelherold
247
13k
A Modern Web Designer's Workflow
chriscoyier
699
190k
Claude Code どこまでも/ Claude Code Everywhere
nwiizo
68
59k
Thoughts on Productivity
jonyablonski
76
5.4k
Keith and Marios Guide to Fast Websites
keithpitt
413
23k
jQuery: Nuts, Bolts and Bling
dougneiner
66
8.6k
The agentic SEO stack - context over prompts
schlessera
0
970
Automating Front-end Workflow
addyosmani
1369
210k
Fantastic passwords and where to find them - at NoRuKo
philnash
53
4k
Transcript
WebKit::WebView Essentials id:yutailang0119 2026/7/25 Sapporo.swift #1 1
yutailang0119 • 株式会社はてな ◦ ◦ ◦ • • • @京都オフィス
アプリケーションエンジニア サービスプラットフォーム try! Swift Tokyo Organizer AVP座談会🥽 🐈 2
https://fortee.jp/iosdc-japan-2026/proposal/62b52f01-f999-418b-ab65-a561b49f5202 3
Agenda • WebKit::WebViewを知る・潜る・拡げる • WebViewBackportを作る・拡げる • バックポートからの学び 4
Agenda • Meet / Dive into / Enhance WebKit::WebView •
Meet / Enhance WebViewBackport ◦ @WebViewBackport • Result 5
Meet WebKit::WebView 6
Meet WebKit::WebView • SwiftUI::View実装のWebView ◦ iOS / iPadOS / Mac
Catalyst / macOS / visionOS 26.0+ • 制御状態はWebPageが担当 ◦ @Observable • Meet WebKit for SwiftUI ◦ WWDC25 Session 231 7
Meet WebKit::WebView @available(iOS 26.0, *) struct ContentWebView: View { @State
private var webPage = WebPage() var body: some View { WebView(webPage) .onAppear { webPage.load(URL(string: "https://apple.com")) } } } 8
Dive into WebKit::WebView 9
Dive into WebKit::WebView • Representableを介し、WKWebViewを表示 ◦ class WebPageWebView: WKWebView •
値型で再設計された設定 ◦ WebPage.Configuration <- WKWebViewConfiguration • 抽象化したWKWebView関連Delegateを提供 ◦ WebPage.DialogPresenting <- WKUIDelegateAdapter ◦ WebPage.NavigationDeciding <- WKNavigationDelegateAdapter 10
Dive into WebKit::WebView • WebKitに実装されている • Open Source Software ◦
https://github.com/WebKit/WebKit • SwiftUI APIはSwift overlayに配置 ◦ Source/WebKit/UIProcess/API/Swift/ ▪ UIProcess = アプリ本体のプロセス ▪ 公開APIとUIが置かれる 11
Enhance WebKit::WebView 12
Enhance WebKit::WebView • WebKitを参考にバックポートできそう • 大まかに3つを実装できれば達成可能 ◦ WebViewBackport: SwiftUI::View ◦
WebViewRepresentableBackport: UIViewRepresentable ◦ @Observable class WebPageBackport • ⚠ 回避必要な箇所がある 13
Enhance WebKit::WebView • Appleのoverlayは非公開APIに依存 ◦ internal import WebKit_Internal ◦ import
WebKit_Private ◦ @_spi(...) import SwiftUI • third-partyのバックポートは公開APIだけで 再構築する 14
Enhance WebKit::WebView • ① 公開APIで代替可能 -> 置換・ラップ • ② 内部処理を観測
-> 近似 • ③ 等価なし-> 挙動差・縮小 ◦ SPI、version 15
① 公開APIで代替可能な 置換、ラップ 16
① 公開APIで代替可能な置換、ラップ • Delegateをasyncプロトコルに変換 ◦ WKNavigationDelegate -> NavigationDeciding ◦ WKUIDelegate
-> DialogPresenting • WK* をラップ ◦ FrameInfo・NavigationAction・BackForwardList • NavigationEvent -> some AsyncSequence 17
② 内部処理を 観測して近似 18
② 内部処理を観測して近似 • @ObservableをKVOから再現 ◦ title / url はWKWebView由来のcomputed ◦
読取: getter で access(keyPath:) 登録 ◦ 変更: KVO(.prior) の前/後 -> willSet/didSet ◦ .prior = 変更前通知(willSet 相当) 19
③ 等価なし -> 挙動差・縮小 20
③ 等価なし -> 挙動差 • NavigationEvent.finishedのタイミング差 ◦ WebKit: 描画反映を待つ(SPI) ▪
_do(afterNextPresentationUpdate:) ◦ Backport: didFinish から同期 ◦ 期待挙動と相違 ▪ 完了時にまだ未描画のことがある 21
③ 等価なし -> 挙動差 • BackForwardListをprivateデリゲートで取得 ◦ 履歴変化を知る公開手段がない ▪ @objc(_webView:backForwardListItemAdded:removed:)
◦ privateデリゲート ◦ 未公開のため保証なし -> 将来壊れうる 22
③ 等価なし -> 縮小 • バージョンで欠ける(下位OSに無い) ◦ 提供できない / 上位限定
• バージョンで変わる(型がOSで違う) ◦ 統一シグネチャで包めない 23
③ 等価なし -> 縮小 • 設定もすべては移せない ◦ Configurationは一部プロパティのみ対応 ◦ 未対応の設定は使えない
24
WebViewの Backport達成 25
Meet WebViewBackport 26
Meet WebViewBackport struct ContentWebViewBackport: View { @State private var webPage
= WebPageBackport() var body: some View { WebViewBackport(webPage) .onAppear { webPage.load(URL(string: "https://apple.com")) } } } 27
Meet WebViewBackport • 使用側のインターフェースは同じ • 設定、Delegateもサポート ◦ WebPageBackport.Configuration ◦ any
WebPageBackport.NavigationDeciding ◦ any WebPageBackport.DialogPresenting 28
Enhance WebViewBackport 29
Enhance WebViewBackport @WebViewBackport @available(iOS 26.0, *) struct ContentWebView: View {
@State private var webPage = WebPage() var body: some View { WebView(webPage) .onAppear { webPage.load(URL(string: "https://apple.com")) } } } 30
Enhance WebViewBackport @WebViewBackport @available(iOS 26.0, *) struct ContentWebView: View {
@State private var webPage = WebPage() var body: some View { WebView(webPage) .onAppear { webPage.load(URL(string: "https://apple.com")) } } } 31
@WebViewBackport • macro WebViewBackport ◦ @attached(peer, names: suffixed(Backport)) ◦ これ自身はWebViewバックポートの実装ではない
• マクロを付与したスコープ内の特定文字列を 置換した実装を生成 ◦ WebView -> WebViewBackport ◦ WebPage -> WebPageBackport 32
@WebViewBackport struct ContentWebView: View { ... } ↓Expand Macro struct
ContentWebViewBackport: View { @State private var webPage = WebPageBackport() var body: some View { WebViewBackport(webPage) .onAppear { webPage.load(URL(string: "https://apple.com")) } } 33
@WebViewBackport struct ContentView: View { var body: some View {
if #available(iOS 26.0, *) { ContentWebView() } else { ContentWebViewBackport() } } } 34
Fix WebKit, but… 35
Fix WebKit, but… • WebKitにバグ報告、修正可能 ◦ WebKit Bugzilla • Bug
311485 ▪ <input type="file"> にファイル選択が反応しない • ⚠ OSにバンドルされるまで直らない ◦ OSバックポートされない 36
37
Pitfall of @WebViewBackport 38
Pitfall of @WebViewBackport @WebViewBackport @available(iOS 26.0, *) struct ContentWebView: View
{ @State private var configuration = WebPage.Configuration() @State private var webPage = WebPage() var body: some View { WebView(webPage) .task { let cookies: [HTTPCookie] = ... await configuration.websiteDataStore .httpCookieStore.setCookies(cookies) } 39
Pitfall of @WebViewBackport struct ContentWebView: View { ... } ↓Expand
Macro struct ContentWebViewBackport: View { @State private var configuration = WebPageBackport.Configuration() @State private var webPage = WebPageBackport() var body: some View { WebViewBackport(webPage) .task { let cookies: [HTTPCookie] = ... await configuration.websiteDataStore .httpCookieStore.setCookies(cookies) } 40
Pitfall of @WebViewBackport struct ContentWebView: View { ... } 💥
struct ContentWebViewBackport: View { @State private var configuration = WebPageBackport.Configuration() unrecognized selector @State private var webPage = WebPageBackport() -[WKHTTPCookieStore var body: some View { WebViewBackport(webPage) setCookies:completionHandler:] .task { let cookies: [HTTPCookie] = ... await configuration.websiteDataStore .httpCookieStore.setCookies(cookies) } 41
Pitfall of @WebViewBackport • WKHTTPCookieStore.setCookies(_:) ▪ setCookies(_:completionHandler:) ◦ iOS /
iPadOS / Mac Catalyst / macOS / visionOS 26.0+ • マクロは呼び出し先を検証しない ◦ 実行時エラーが起きうる • iOS 18以下では unrecognized selector 42
Pitfall of @WebViewBackport @WebViewBackport @available(iOS 26.0, *) struct ContentWebView: View
{ var body: some View { WebView(webPage) .task { let cookies: [HTTPCookie] = ... let store = configuration.websiteDataStore.httpCookieStore for cookie in cookies { await store.setCookie(cookie) } } 43
Result 44
Result • 公開APIで“ほぼ”作れる • APIレイヤーとエンジンの境界が限界になる • OSにバンドルされるまでは届かない • WebKit::WebView を「歩いて」読み解いた
45
References 46
References • WebKit/WebKit ◦ • iOS 18向けバックポートから学ぶWebKit::WebViewの歩き方 ◦ • https://github.com/WebKit/WebKit
https://fortee.jp/iosdc-japan-2026/proposal/62b52f01-f999-418b-ab65-a561b49f5202 WKHTTPCookieStore.setCookies(_:) async ◦ https://developer.apple.com/documentation/webkit/wkhttpcookiestore/setcookies(_:completio nhandler:) • WebKit Bugzilla Bug 311485 ◦ • https://bugs.webkit.org/show_bug.cgi?id=311485 SwiftUIにおけるWebViewの実装 - cockscomblog? ◦ https://cockscomb.hatenablog.com/entry/2025/06/04/093418 47
WebKit::WebView利用企業 48 48