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
ブラウザアプリを自作してわかったWebViewの扱い方/iOS Meetup in 福岡
Search
Kyome (Takuto Nakamura)
March 24, 2023
Programming
4.7k
1
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
ブラウザアプリを自作してわかったWebViewの扱い方/iOS Meetup in 福岡
Kyome (Takuto Nakamura)
March 24, 2023
More Decks by Kyome (Takuto Nakamura)
See All by Kyome (Takuto Nakamura)
Swiftで高速フーリエ変換してオーディオビジュアライザーを作る / iOSDC Japan 2024 Day1 Track D
kyome22
3
1.5k
Accelerate.vDSPとSwift Chartsでぶち上がろう!/サイボウズモバイル Meetup 2023.04.20
kyome22
0
290
iOSのウィジェットでも猫走らせたい / iOSDC Japan 2022 Day2 Unconference
kyome22
3
1.4k
Hacking Xcode Behaviors / macOS native symposium #08
kyome22
2
1.9k
AppKitでお絵描きをしてみよう / macOS native symposium #06
kyome22
2
1.1k
Finder Sync Extension で Mac 向け便利ツールを作ろう / iOSDC Japan 2021
kyome22
6
6.3k
iOS Custom Keyboardsでできること/できないこと/やってはいけないこと / iOSDC Japan 2020 LT
kyome22
3
2.1k
Other Decks in Programming
See All in Programming
ローカルLLMでどこまでコードが書けるか -縮小版 / How much code can be written on a local LLM Shortened
kishida
2
170
Creating Composable Callables in Contemporary C++
rollbear
0
190
LaravelLive Japan の裏方のすべて — 第188回 PHP勉強会@東京 (2026-06-24)
suguruooki
2
150
「AIで開発し、AIを届ける」をEvalでつなぐ 〜AIネイティブに始めるプロダクト開発の実践〜 / Connecting "Develop with AI, deliver AI" with Eval
rkaga
4
5.7k
使用 Meilisearch 建立新聞搜尋工具
johnroyer
0
100
これからAgentCoreを触る方へトレンドはGatewayです
har1101
6
480
エンジニアにデザインハーネスを 〜デザインプロセスを規定するためのハーネス〜 / Design harness from an engineer's perspective
rkaga
2
910
分散システム、なんですぐ死んでしまうん?耐障害性を高めたいあなたのためのレジリエンスパターン入門
mshibuya
7
4.1k
AI がコードを書く時代における新卒エンジニアの仕事風景 (2026) / New Graduate Engineers in the Era of AI Coding (2026)
sushichan044
0
200
なぜ関数型プログラミングで「型」と「証明」が語られるのか #fp_matsuri
kajitack
3
550
Snowflake Summitでの新機能 CoCo / CoWork / snowflake-summit-2026-overall-what-new-coco
tatsuhiro
1
210
自作OSでスライド発表する
uyuki234
1
3.7k
Featured
See All Featured
Stewardship and Sustainability of Urban and Community Forests
pwiseman
0
250
CoffeeScript is Beautiful & I Never Want to Write Plain JavaScript Again
sstephenson
162
16k
Improving Core Web Vitals using Speculation Rules API
sergeychernyshev
21
1.5k
The #1 spot is gone: here's how to win anyway
tamaranovitovic
3
1.1k
Performance Is Good for Brains [We Love Speed 2024]
tammyeverts
12
1.7k
Winning Ecommerce Organic Search in an AI Era - #searchnstuff2025
aleyda
1
2.1k
Rebuilding a faster, lazier Slack
samanthasiow
85
9.6k
The agentic SEO stack - context over prompts
schlessera
0
840
The World Runs on Bad Software
bkeepers
PRO
72
12k
Applied NLP in the Age of Generative AI
inesmontani
PRO
4
2.4k
Color Theory Basics | Prateek | Gurzu
gurzu
0
380
Optimising Largest Contentful Paint
csswizardry
37
3.8k
Transcript
Kyome 2023/03/24 (ۚ) @LINE FukuokaΦϑΟε ϒϥβΞϓϦΛࣗ࡞ͯ͠Θ͔ͬͨ WebViewͷѻ͍ํ J04.FFUVQ JOԬ
ࣗݾհ IUUQTLZPNFJP ,ZPNF ,ZPNFTVLF CybozuͰkintoneϞόΠϧͷiOSΛ୲ ۀޮԽOSSϥΠϒϥϦͷ։ൃӡ༻ʹੵۃత झຯͰmacOS͚ͷϢʔςΟϦςΟΞϓϦ։ൃ
ࣗݾհ RunCat activity indicator HandyPalette color picker ScreenPointer presentation tool
QuickMIDI MIDI keyboard player
ͳͥϒϥβΞϓϦΛ ࣗ࡞͠Α͏ͱࢥ͔ͬͨ
ͳͥϒϥβΞϓϦΛࣗ࡞͠Α͏ͱࢥ͔ͬͨ kintoneʹʮJavaScriptΧελϚΠζʯͱ͍͏ϢʔβʔಠࣗͷػೳΛ ՃͰ͖ΔΈ͕͋Δ kintoneϞόΠϧWebViewϕʔεͷΞϓϦͱͳ͍ͬͯΔ WebViewϕʔεͷΞϓϦ։ൃΛ୲͢Δʹ͋ͨͬͯɺWebViewΛѻͬͨ ͜ͱ͕ͳ͔ͬͨͨΊɺϒϥβΞϓϦΛؙ͝ͱࣗ࡞͢Δ͜ͱʹͨ͠ MinBrowser https://github.com/kyome22/MinBrowserɹ AppStoreͰ৴த
ͳͥϒϥβΞϓϦΛࣗ࡞͠Α͏ͱࢥ͔ͬͨ ϒϥβΞϓϦΛؙ͝ͱࣗ࡞ֶͯ͠Μͩ͜ͱ WebViewͰͷΠϕϯτΛϑοΫͯ͠ωΠςΟϒಈ࡞Λͭͳ͛Δํ๏ WebView্Ͱ࣮ߦ͞ΕͨJavaScriptͷϩάΛरͬͯग़ྗ͢Δํ๏ WebViewΛབྷΊͨςετέʔεΛ҆ఆ࣮ͯ͠ߦ͢Δํ๏ etc. ࠓճͷͷൣғ֎
SwiftUIͰWKWebViewΛѻ͏
UIViewRepresentableͰWKWebViewΛϥοϓͯ͠Viewͱͯ͠͏ ݕࡧɺΔɺਐΉɺPull to refreshͳͲ͕ՄೳͳΠϯλϥΫςΟϒͳ WebViewΛ࡞Γ͍ͨ UIViewRepresentableͷ֎ͷViewͱͷ࿈ܞ͕ඞཁ SwiftUIͰWKWebViewΛѻ͏ UIViewRepresentable WKWebView SearchBar
ProgressView ϫʔυݕࡧ ϓϩάϨεͷߋ৽
GitHubΛړ͍ͬͯΔͱΑ͘ݟΔख๏ enumͷϓϩύςΟΛࢹͯ͠WKWebViewͷΞΫγϣϯΛ੍ޚ͢Δ UIViewRepresentableͷCoordinatorͰWKWebViewͷঢ়ଶΛࢹ͢Δ SwiftUIͰWKWebViewΛѻ͏
GitHubΛړ͍ͬͯΔͱΑ͘ݟΔख๏ enumͷϓϩύςΟΛࢹͯ͠WKWebViewͷΞΫγϣϯΛ੍ޚ͢Δ UIViewRepresentableͷCoordinatorͰWKWebViewͷঢ়ଶΛࢹ͢Δ SwiftUIͰWKWebViewΛѻ͏ struct WrappedWKWebView: UIViewRepresentable { enum Action
{ case none case search(String) } @Binding private var action: Action ϫʔυݕࡧ༻ͷaction
GitHubΛړ͍ͬͯΔͱΑ͘ݟΔख๏ enumͷϓϩύςΟΛࢹͯ͠WKWebViewͷΞΫγϣϯΛ੍ޚ͢Δ UIViewRepresentableͷCoordinatorͰWKWebViewͷঢ়ଶΛࢹ͢Δ SwiftUIͰWKWebViewΛѻ͏ func updateUIView(_ webView: WKWebView, context: Context)
{ switch action { case .none: break case .search(let searchText): context.coordinator.search(text: searchText) action = .none } } action͕searchʹͳͬͨΒcoordinatorΛհͯ͠ WKWebViewͷload(request:)Λୟ͘ actionΛ͍ऴΘͬͨΒ.noneʹ͢
GitHubΛړ͍ͬͯΔͱΑ͘ݟΔख๏ enumͷϓϩύςΟΛࢹͯ͠WKWebViewͷΞΫγϣϯΛ੍ޚ͢Δ UIViewRepresentableͷCoordinatorͰWKWebViewͷঢ়ଶΛࢹ͢Δ SwiftUIͰWKWebViewΛѻ͏ struct WrappedWKWebView: UIViewRepresentable { @Binding private
var progress: Double private let webView = WKWebView() func makeCoordinator() -> Coordinator { return Coordinator(webView: webView, progress: $progress) } coordinatorʹwebViewͱBinding͍ͨ͠ϓϩύςΟΛ͢
GitHubΛړ͍ͬͯΔͱΑ͘ݟΔख๏ enumͷϓϩύςΟΛࢹͯ͠WKWebViewͷΞΫγϣϯΛ੍ޚ͢Δ UIViewRepresentableͷCoordinatorͰWKWebViewͷঢ়ଶΛࢹ͢Δ SwiftUIͰWKWebViewΛѻ͏ class Coordinator { init(webView: WKWebView, progress:
Binding<Double>) { // ॳظԽলུ self.webView .publisher(for: \.estimatedProgress) .sink { [weak self] value in self?.progress = value } .store(in: &cancellables) } } WKWebViewͷঢ়ଶΛࢹͯ͠Bindingʹྲྀ͢
SwiftUIͰWKWebViewΛѻ͏ ൃੜ ϫʔυݕࡧͨ͠ޙϩʔυॲཧ͕ऴΘΒͣɺ Կϩʔυ͞ΕΔΑ͏ͳڍಈʹͳͬͨ ͔͠XcodeͰେྔͷܯࠂ͕ʂ 🤯 ѹతڍಈෆ৹
⚠ ܯࠂʹ͋Δ௨ΓɺViewͷߋ৽தʹBinding͍ͯ͠Δͷߋ৽Λ͍ͯ͠Δ͜ͱ WebView͕ViewͰ͋Δͷʹঢ়ଶΛ͓࣋ͬͯΓɺ View֎෦͔Βঢ়ଶΛมߋͨ͠Γࢹͨ͠Γ͢Δඞཁ͕͋Δ͜ͱ͕ݪҼ WebViewએݴతUIͱͷ૬ੑ͕ѱ͘ɺೃછΈͮΒ͍ SwiftUIͰWKWebViewΛѻ͏
💡ղܾࡦ UIViewRepresentableͷ֎ʹWKWebViewͷΠϯελϯεΛ࣋ͨͤɺ ͦͪΒͰঢ়ଶͷࢹͱ੍ޚΛߦ͏ SwiftUIͰWKWebViewΛѻ͏ UIViewRepresentable WKWebView SearchBar ProgressView ϫʔυݕࡧ ϓϩάϨεͷߋ৽
WebViewModel ϨϯμϦϯάػೳ͚ͩ WKWebView ঢ়ଶͷࢹͱ੍ޚ
💡ղܾࡦ UIViewRepresentableͷ֎ʹWKWebViewͷΠϯελϯεΛ࣋ͨͤɺ ͦͪΒͰঢ়ଶͷࢹͱ੍ޚΛߦ͏ SwiftUIͰWKWebViewΛѻ͏ struct WrappedWKWebView: UIViewRepresentable { let setWebViewHandler:
(WKWebView) -> Void func makeUIView(context: Context) -> some WKWebView { let webView = WKWebView() setWebViewHandler(webView) return webView } func updateUIView(_ uiView: UIViewType, context: Context) {} } WKWebViewΛ֎ʹ࣋ͪग़ͭ͢ Կ͠ͳ͍
💡ղܾࡦ UIViewRepresentableͷ֎ʹWKWebViewͷΠϯελϯεΛ࣋ͨͤɺ ͦͪΒͰঢ়ଶͷࢹͱ੍ޚΛߦ͏ SwiftUIͰWKWebViewΛѻ͏ class WebViewModel: ObservableObject { private weak
var webView: WKWebView? func setWebView(_ webView: WKWebView) { self.webView = webView // webViewͷঢ়ଶΛࢹ(ߪಡ)ͯ͠PublishedͳϓϩύςΟʹྲྀ͢ } func search() { // URLRequestΛ࡞ͬͯ webView?.load() Λୟ͘ } }
💡ղܾࡦ UIViewRepresentableͷ֎ʹWKWebViewͷΠϯελϯεΛ࣋ͨͤɺ ͦͪΒͰঢ়ଶͷࢹͱ੍ޚΛߦ͏ SwiftUIͰWKWebViewΛѻ͏ struct WebView: View { @StateObject private
var webViewModel = WebViewModel() var body: some View { VStack(spacing: 0) { SearchBar(inputText: $webViewModel.inputText) .onSubmit { webViewModel.search() } ProgressView(value: webViewModel.progress) WrappedWKWebView(setWebViewHandler: { webView in webViewModel.setWebView(webView) }) } } } Modelͷsearch()Λୟ͘ WKWebViewͷΠϯελϯεΛModelʹ͢
💡ղܾࡦ UIViewRepresentableͷ֎ʹWKWebViewͷΠϯελϯεΛ࣋ͨͤɺ ͦͪΒͰঢ়ଶͷࢹͱ੍ޚΛߦ͏ SwiftUIͰWKWebViewΛѻ͏ struct WebView: View { @StateObject private
var webViewModel = WebViewModel() var body: some View { VStack(spacing: 0) { SearchBar(inputText: $webViewModel.inputText) .onSubmit { webViewModel.search() } ProgressView(value: webViewModel.progress) WrappedWKWebView(setWebViewHandler: { webView in webViewModel.setWebView(webView) }) } } } Modelͷsearch()Λୟ͘ WKWebViewͷΠϯελϯεΛModelʹ͢ Q, Կݺͼग़͞Εͯ͠·͏ͷͰʁ A, UIViewRepresentableͷmakeUIView() Ұ͔͠ݺΕͳ͍ͷͰͳ͍
💡ղܾࡦ UIViewRepresentableͷ֎ʹWKWebViewͷΠϯελϯεΛ࣋ͨͤɺ ͦͪΒͰঢ়ଶͷࢹͱ੍ޚΛߦ͏ SwiftUIͰWKWebViewΛѻ͏ struct WebView: View { @StateObject private
var webViewModel = WebViewModel() var body: some View { VStack(spacing: 0) { SearchBar(inputText: $webViewModel.inputText) .onSubmit { webViewModel.search() } ProgressView(value: webViewModel.progress) WrappedWKWebView(setWebViewHandler: { webView in webViewModel.setWebView(webView) }) } } } Modelͷsearch()Λୟ͘ WKWebViewͷΠϯελϯεΛModelʹ͢ Q, Կݺͼग़͞Εͯ͠·͏ͷͰʁ A, UIViewRepresentableͷmakeUIView() Ұ͔͠ݺΕͳ͍ͷͰͳ͍
Thank you! WKWebViewʹ͍ͭͯ MinBrowserͷϦϦʔεʹۤઓͨ݅͠ ݸਓΞϓϦ։ൃʹ͍ͭͯ ࠙ձͰ͓͠͠·͠ΐ͏ʂ
খ
MinBrowserͷϦϦʔεʹۤઓͨ݅͠
ग़དྷ্͕ͬͨͷͰϦϦʔε͠Α͏ͱࢥͬͨΒɺ৹ࠪʹ6ϲ݄͔͔ͬͨ😵 ʢ2022/09/04 ৹ࠪఏग़ɺ2023/03/02 ৴։࢝ʣ WebϒϥβͳͷͰʮແ੍ݶͷWebΞΫηεؚ͕·ΕΔʯʹ ☑ ͕ඞཁ ྗతͳදݱɺΪϟϯϒϧɺաܹͳੑత༰ͳͲશͯͷྸ੍ݶ߲ ʹ͍ͭͯʮසൟ/ۃʯʹ ☑
͕ඞཁͩͱࢥ͍ࠐΜͰ͍ͨ ݁Ռతʹ৹ࠪʹ͔͔࣌ؒΔϧʔτʹೖͬͯ͠·ͬͨ MinBrowserͷϦϦʔεʹۤઓͨ͠
৹ࠪʹ͔͔࣌ؒΔ߹ɺεςʔλεRejectʹͳΓ ʮ͔͔࣌ؒΔ͚Ͳ٫ԼͰͳ͍͔ΒͬͯͯͶʯͱϝοηʔδ͕ಧ͘ ΞϓϦࣗମ͕ྸ੍ݶ߲ΛҙਤతʹؚΜͰ͍ͳ͚Ε ☑ ෆཁͩͬͨ ʮແ੍ݶͷWebΞΫηεؚ͕·ΕΔʯ͚ͩʹ ☑ ͨ͠ΒͰ৹ࠪ௨ͬͨ MinBrowserͷϦϦʔεʹۤઓͨ͠ ͱ΄΄…