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
Sponsored
·
Your Podcast. Everywhere. Effortlessly.
Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.
→
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
PHPだって関数型したい 〜できること、できないこと〜 / fp-in-php
jsoizo
0
210
コーディングルールの鮮度を保ちたい for SRE NEXT 2026 / keep-fresh-go-internal-conventions-sre-next-2026
handlename
0
140
Apache Hive: そしてCloud Native Lakehouseへ
okumin
1
140
act2-costs.pdf
sumedhbala
0
110
Laravel Boostに学ぶ、AIにPHPを書かせる技術 〜OSSの実装から蒸留するエージェント制御の王道〜
kentaroutakeda
3
460
えっ!!コードを読まずに開発を!?
hananouchi
0
220
継続モナドとリアクティブプログラミング
yukikurage
3
610
分散システム、なんですぐ死んでしまうん?耐障害性を高めたいあなたのためのレジリエンスパターン入門
mshibuya
7
6.3k
ローカルLLMでどこまでコードが書けるか -縮小版 / How much code can be written on a local LLM Shortened
kishida
2
190
20260623_Loop Engineeringで自分の分身の問い合わせBotを作る
ryugen04
0
220
型も通る、synthも通る、それでも危ない 〜AIのCDKの権限とコストを機械で検証する〜 / It Passes Type Checks, It Passes Synth Checks, but It’s Still Risky — Automatically Verifying Permissions and Costs in AI’s CDK —
seike460
PRO
1
350
霧の中の代数的エフェクト
funnyycat
1
400
Featured
See All Featured
ピンチをチャンスに:未来をつくるプロダクトロードマップ #pmconf2020
aki_iinuma
128
56k
Game over? The fight for quality and originality in the time of robots
wayneb77
1
220
We Have a Design System, Now What?
morganepeng
55
8.2k
From Legacy to Launchpad: Building Startup-Ready Communities
dugsong
0
260
The Anti-SEO Checklist Checklist. Pubcon Cyber Week
ryanjones
0
180
Improving Core Web Vitals using Speculation Rules API
sergeychernyshev
21
1.5k
Bridging the Design Gap: How Collaborative Modelling removes blockers to flow between stakeholders and teams @FastFlow conf
baasie
0
610
Performance Is Good for Brains [We Love Speed 2024]
tammyeverts
12
1.7k
Measuring Dark Social's Impact On Conversion and Attribution
stephenakadiri
2
240
Conquering PDFs: document understanding beyond plain text
inesmontani
PRO
4
2.9k
Skip the Path - Find Your Career Trail
mkilby
1
170
Navigating Weather and Climate Data
rabernat
0
370
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ͷϦϦʔεʹۤઓͨ͠ ͱ΄΄…