Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
WebKit::WebView Essentials / Sapporo.swift #1
Search
Sponsored
·
Ship Features Fearlessly
Turn features on and off without deploys. Used by thousands of Ruby developers.
→
Yutaro Muta
July 25, 2026
Technology
190
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
Google Nest CamとApple Vision frameworkと猫🐈🐈⬛ / onishi50
yutailang0119
0
360
SwiftUI Inspectorが難しすぎる / Mobile Act OSAKA 18
yutailang0119
0
140
Swift Concurrencyでのスケジュール処理を考える / Mobile Act OSAKA 17
yutailang0119
0
170
猫と暮らすネットワークカメラ生活🐈 ~Vision frameworkでペットを愛でよう~ / iOSDC Japan 2025
yutailang0119
0
460
猫と暮らす Google Nest Cam生活🐈 / WebRTC with Google Nest Cam
yutailang0119
0
340
Swiftの “private” を テストする / Testing Swift "private"
yutailang0119
0
360
Apple Vision Pro購入RTA 1泊3日弾丸ハワイツアー / RTA: Purchase Apple Vision Pro in Hawaii
yutailang0119
0
1.6k
個人開発のたのしみ / Enjoying personal development
yutailang0119
0
1.1k
バックポートして学ぶ新APIの仕組み
yutailang0119
0
3.4k
Other Decks in Technology
See All in Technology
AIのためのEthernet技術動向 (SerDes)
markunet
1
220
Webアクセシビリティ入門 2026
recruitengineers
PRO
3
660
トヨタ⽣産⽅式(TPS)⼊⾨
recruitengineers
PRO
3
1k
関東Kaggler会発表資料
takoi
1
260
Eight Engineering Unit 紹介資料
sansan33
PRO
3
8.2k
JavaScript 研修 (2026)
recruitengineers
PRO
2
630
2026-08-15 JAWS-UG 茨城 #16 Secrets ManagerにおけるSecret値の管理(Terraformの場合) / Secrets Manager Secrets
masasuzu
0
280
え?フロントエンドエンジニアの ワイがインフラも!?
puku0x
1
760
SmartHR Engineering Team Deck
smarthr
1
2.8k
コーチングの奥義 何もしないテクニック
jinwatanabe
0
110
Digitization部 紹介資料
sansan33
PRO
2
7.7k
モダンフロントエンド 開発研修
recruitengineers
PRO
4
790
Featured
See All Featured
First, design no harm
axbom
PRO
2
1.3k
Intergalactic Javascript Robots from Outer Space
tanoku
273
27k
Speed Design
sergeychernyshev
33
2k
Documentation Writing (for coders)
carmenintech
77
5.5k
SEOcharity - Dark patterns in SEO and UX: How to avoid them and build a more ethical web
sarafernandez
0
250
Principles of Awesome APIs and How to Build Them.
keavy
128
18k
Impact Scores and Hybrid Strategies: The future of link building
tamaranovitovic
0
410
The Success of Rails: Ensuring Growth for the Next 100 Years
eileencodes
47
8.3k
Hiding What from Whom? A Critical Review of the History of Programming languages for Music
tomoyanonymous
3
1.1k
Organizational Design Perspectives: An Ontology of Organizational Design Elements
kimpetersen
PRO
1
800
The Pragmatic Product Professional
lauravandoore
37
7.4k
The SEO identity crisis: Don't let AI make you average
varn
0
530
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