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
350
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
180
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
520
猫と暮らす 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
『SAR衛星データ解析入門』のご紹介とその応用
syuchimu
0
140
React改造してみた
tsukina_7mochi
0
150
Codex を使った障害対応机上演習の実際
orgachem
PRO
0
230
コンテナ運用におけるネットワーク・コンテナコストの削減方法/How to Reduce Network and Container Costs in Container Operations
masakiokuda
2
370
Rustuna: Rustによる高速なOptuna実装
pfn
PRO
0
210
AWSセキュリティで活用するAI機能
cmusudakeisuke
1
160
Tofu-Controller lightning talk @ Containerday 2026
gionn
0
160
野蛮なアジャイル [サイボウズ発!]組織の常識を覆した反骨のスクラム実践記 / Barbaric Agile - Enterprise Agile Study Group
ama_ch
0
120
データエンジニアの次の戦場は "プロセスエンジニアリング"
sansantech
PRO
1
150
古い指輪から広がった JAVA コミュニティ とのつながり
yamad
0
130
Kiro Crewで「みのるん式」仕事術やってみた
minorun365
PRO
3
990
[EMNLP26] RIGEL: Self-Distilled Score Adaptation for Image and Video Captioning Evaluation
keio_smilab
PRO
0
110
Featured
See All Featured
Crafting Experiences
bethany
1
390
Rebuilding a faster, lazier Slack
samanthasiow
85
9.7k
Everyday Curiosity
cassininazir
0
360
The untapped power of vector embeddings
frankvandijk
2
1.9k
Product Roadmaps are Hard
iamctodd
55
13k
New Earth Scene 8
popppiees
4
2.7k
Agile Leadership in an Agile Organization
kimpetersen
PRO
0
290
Lightning Talk: Beautiful Slides for Beginners
inesmontani
PRO
2
740
BBQ
matthewcrist
90
10k
Imperfection Machines: The Place of Print at Facebook
scottboms
270
14k
Speed Design
sergeychernyshev
33
2.2k
Deep Space Network (abreviated)
tonyrice
0
380
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