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.6k
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
Lessons from Spec-Driven Development
simas
PRO
0
220
Lemonade + Foundry Toolkit でお手軽アプリ開発
seosoft
1
370
その問い、本当に正しいですか?AI時代のエンジニアに必要な哲学と認知科学 / ai-philosophy-cognitive-science
minodriven
13
6.2k
TypeScript+Orvalで実現する型安全かつ堅牢でスケーラブルなマルチチャネル通知基盤 / TSKaigi Night talks ~after conference~
d0riven
0
360
軽量Java基盤の設計 DIコンテナに頼らない、長期保守と1秒起動の実現 JJUG CCC 2026 Spring
macha64
0
570
過去最大のMCPアップデート! 2026-07-28 RC版の謎に迫る
licux
6
390
Skillsは効率化、Agentsは"自分の拡張"——Builder時代のエージェント編成(CC Night 2026)
wemra
1
160
作って学ぶ、 JSX (TSX) ランタイムの基本
syumai
7
1.7k
jQueryをバージョンアップする前に使いたいjQuery Migrate
matsuo_atsushi
0
580
技術的負債解消で開発者の未来を開く- AIの力でコード刷新
kmd2kmd
0
120
さぁV100、メモリをお食べ・・・
nilpe
0
150
A2UI という光を覗いてみる
satohjohn
1
150
Featured
See All Featured
The Success of Rails: Ensuring Growth for the Next 100 Years
eileencodes
47
8.2k
AI in Enterprises - Java and Open Source to the Rescue
ivargrimstad
0
1.3k
The Mindset for Success: Future Career Progression
greggifford
PRO
0
370
Measuring Dark Social's Impact On Conversion and Attribution
stephenakadiri
2
220
brightonSEO & MeasureFest 2025 - Christian Goodrich - Winning strategies for Black Friday CRO & PPC
cargoodrich
3
740
Mind Mapping
helmedeiros
PRO
1
260
Lightning talk: Run Django tests with GitHub Actions
sabderemane
0
200
Avoiding the “Bad Training, Faster” Trap in the Age of AI
tmiket
0
180
Building a A Zero-Code AI SEO Workflow
portentint
PRO
0
610
Beyond borders and beyond the search box: How to win the global "messy middle" with AI-driven SEO
davidcarrasco
3
170
How STYLIGHT went responsive
nonsquared
100
6.2k
Amusing Abliteration
ianozsvald
1
210
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ͷϦϦʔεʹۤઓͨ͠ ͱ΄΄…