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
SwiftUI + Kotlin Multiplatform 開発で見えた長所と短所
Search
swiftty
September 02, 2023
Technology
2
5.6k
SwiftUI + Kotlin Multiplatform 開発で見えた長所と短所
swiftty
September 02, 2023
Tweet
Share
More Decks by swiftty
See All by swiftty
Wantedly Visit での SKIE の導入と振り返り
swiftty
0
55
iOS 18 から追加された SwiftUI の傾向について調べてみる
swiftty
3
820
Flutter アプリのリリースフローを考える
swiftty
0
330
Meet BrowserEngineKit
swiftty
0
1.8k
Cloud-managed certificates へ移行した話
swiftty
0
610
同じアプリを Flutter と SwiftUI で書いてみる
swiftty
0
590
Swift Package Manager へ移行した話
swiftty
0
700
SwiftLint にコントリビュートする
swiftty
1
4.6k
SwiftUI でリスト要素のインプレッションを計測する
swiftty
0
600
Other Decks in Technology
See All in Technology
Flaky Testへの現実解をGoのプロポーザルから考える | Go Conference 2025
upamune
1
420
社内お問い合わせBotの仕組みと学び
nish01
0
120
自作LLM Native GORM Pluginで実現する AI Agentバックテスト基盤構築
po3rin
2
250
extension 現場で使えるXcodeショートカット一覧
ktombow
0
210
AI駆動開発を推進するためにサービス開発チームで 取り組んでいること
noayaoshiro
0
160
許しとアジャイル
jnuank
1
120
ZOZOのAI活用実践〜社内基盤からサービス応用まで〜
zozotech
PRO
0
170
非エンジニアのあなたもできる&もうやってる!コンテキストエンジニアリング
findy_eventslides
3
910
実装で解き明かす並行処理の歴史
zozotech
PRO
1
320
Pure Goで体験するWasmの未来
askua
1
180
Shirankedo NOCで見えてきたeduroam/OpenRoaming運用ノウハウと課題 - BAKUCHIKU BANBAN #2
marokiki
0
130
SwiftUIのGeometryReaderとScrollViewを基礎から応用まで学び直す:設計と活用事例
fumiyasac0921
0
140
Featured
See All Featured
Measuring & Analyzing Core Web Vitals
bluesmoon
9
610
Designing for humans not robots
tammielis
254
25k
Fight the Zombie Pattern Library - RWD Summit 2016
marcelosomers
234
17k
Faster Mobile Websites
deanohume
310
31k
The Cost Of JavaScript in 2023
addyosmani
53
9k
Being A Developer After 40
akosma
91
590k
Rails Girls Zürich Keynote
gr2m
95
14k
Building Flexible Design Systems
yeseniaperezcruz
329
39k
StorybookのUI Testing Handbookを読んだ
zakiyama
31
6.2k
GitHub's CSS Performance
jonrohan
1032
460k
Keith and Marios Guide to Fast Websites
keithpitt
411
22k
Chrome DevTools: State of the Union 2024 - Debugging React & Beyond
addyosmani
7
890
Transcript
© 2023 Wantedly, Inc. SwiftUI + Kotlin Multiplatform 開発で 見えた長所と短所
iOSDC Japan 2023 スポンサーセッション Sep. 2 2023 - ウォンテッドリー株式会社 / 林達也
自己紹介 id/tatsuya_hayashi_ar swiftty © 2023 Wantedly, Inc. ウォンテッドリー株式会社 2023 年
3 月〜 Wantedly Visit の iOS アプリの開発
今日話すこと 前提 • iOS エンジニアで Kotlin Multiplatform (KMP) には触れたことがない •
過去のプロダクトは基本 UIKit で SwiftUI は部分的な導入程度 話すこと • KMP や SwiftUI での開発の際にどのような取り組みがあったかを紹介 ◦ プロフィールリニューアルについて ◦ SwiftUI 事例 ◦ KMP と Swift/SwiftUI の組み合わせ © 2023 Wantedly, Inc.
はじめに © 2023 Wantedly, Inc.
プロフィールリニューアル プロジェクト • 各プラットフォームでのプロフィール体験を 揃える • ウォンテッドリーではもともと KMP を採用し てマルチプラットフォームでの開発を行って
いた ◦ Android が先行していたため KMP 側の実装は完了していた 🎉 • SwiftUI の採用 🎉 © 2023 Wantedly, Inc. 引用: https://www.wantedly.com/companies/wantedly/post_articles/489565
SwiftUI の採用 • 今までも設定画面など部分的な導入はあっ た • 今回のリニューアルでは SwiftUI で 実現できるのかの検証も含めて始まった
© 2023 Wantedly, Inc.
KMP とは • Kotlin Multiplatform • ビジネスロジックを共通化 • UI は各プラットフォームで実装
© 2023 Wantedly, Inc. 引用: https://kotlinlang.org/lp/multiplatform/
KMP とは • Kotlin Multiplatform • ビジネスロジックを共通化 • UI は各プラットフォームで実装
© 2023 Wantedly, Inc.
ビジネスロジックの共通化 Reactor • 単方向データフローアーキテクチャを採用 ◦ View → Action → (Mutation)
→ State → View → … ◦ アプリケーション全体でひとつの状態管理ではなく集約されたビュー単位で状態管理 • Kotlin で定義されたクラスなので ObservableObject に適合していない ◦ 後付けで ObservableObject が要求する objectWillChange を 実装するのは大変 © 2023 Wantedly, Inc.
ビジネスロジックの共通化 Reactor • 単方向データフローアーキテクチャを採用 ◦ View → Action → (Mutation)
→ State → View → … ◦ アプリケーション全体でひとつの状態管理ではなく集約されたビュー単位で状態管理 • Kotlin で定義されたクラスなので ObservableObject に適合していない ◦ 後付けで ObservableObject が要求する objectWillChange を 実装するのは大変 © 2023 Wantedly, Inc. → Swift 側で Reactor をラップする
SwiftUI とReactor © 2023 Wantedly, Inc.
SwiftUI とReactor © 2023 Wantedly, Inc.
SwiftUI とReactor © 2023 Wantedly, Inc. → 以降は通常の SwiftUI と同じ
SwiftUI とReactor © 2023 Wantedly, Inc. → 以降は通常の SwiftUI と同じ
SwiftUI とReactor © 2023 Wantedly, Inc. → 以降は通常の SwiftUI と同じ
SwiftUI 事例 プロフィールヘッダー © 2023 Wantedly, Inc.
プロフィールヘッダー © 2023 Wantedly, Inc. UIKit でもよくある UI • コンテンツをスクロールするとヘッダーが縮む
• タブを切り替えたらヘッダーはそれに追従する
プロフィールヘッダー SwiftUI ではどうする? • ScrollView のスクロールを起点にレイアウトの制御を行いたい • SwiftUI の ScrollView
の問題 ◦ contentInset が調整できない ◦ オフセットを監視できない ◦ オフセットを変更できない © 2023 Wantedly, Inc.
プロフィールヘッダー SwiftUI ではどうする? • contentInset が調整できない → 空のビューでヘッダー分コンテンツの開始位置をずらす? • オフセットを監視できない
→ 子要素を GeometryReader で監視? • オフセットを変更できない → ScrollViewReader を使って scroll ならできる? • 最終的にオフセットをもとにヘッダービューの高さを変更すれば 当初のレイアウトを実現できそう 💭 © 2023 Wantedly, Inc.
プロフィールヘッダー © 2023 Wantedly, Inc.
プロフィールヘッダー © 2023 Wantedly, Inc. TabView を page スタイルで表示
プロフィールヘッダー © 2023 Wantedly, Inc. 各 content 内の ScrollView に高さ
0 で設置した ビューの位置をコンテンツの開始位置として anchorPreference で監視
プロフィールヘッダー © 2023 Wantedly, Inc. 各 content 内の ScrollView に高さ
0 で設置した ビューの位置をコンテンツの開始位置として anchorPreference で監視 overlayPreferenceValue でその位置をもとに ヘッダーの高さを算出しオーバーレイで重ねる
プロフィールヘッダー © 2023 Wantedly, Inc. オフセットが変化するたびに選択されたタブ以外の スクロール位置を scrollTo で同期させる
プロフィールヘッダー © 2023 Wantedly, Inc.
プロフィールヘッダー © 2023 Wantedly, Inc. → 思ったより素直なコードで実現できた 🎉
プロフィールヘッダー 良かった点 • 複雑なレイアウトを SwiftUI でシンプルに実現 ◦ UIKit なら数百行↑ 悪かった点
• ScrollView と List で挙動が変わる ◦ scrollTo の対象(ビュー単位、セル単位) • OS バージョンでの挙動の違いやパフォーマンスの観点でリリース間際まで格闘 ◦ 検証時は GeometryReader/onPreferenceChange を利用 ◦ safeAreaInset なども試したがその領域の奥へのインタラクションが反応しないなど問 題あり © 2023 Wantedly, Inc.
Xcode Previews © 2023 Wantedly, Inc.
Xcode Previews Wantedly Visit アプリ • Preview を積極的に活用して開発 ◦ 動作確認しやすいのでチームで自然とそうなった
• Feature Modules + KMP 構成(に移行中) ◦ ビジネスロジック(KMP)がビルド済みの XCFramework ◦ 依存の少ない新規 Profile モジュール • Preview 時は AnySwiftUIReactor に任意の State を設定してパターンを用意 © 2023 Wantedly, Inc.
Xcode Previews © 2023 Wantedly, Inc.
Xcode Previews © 2023 Wantedly, Inc.
Xcode Previews © 2023 Wantedly, Inc.
Xcode Previews 良かった点 • ビルド時間がほぼなく快適な体験 • 任意の State の注入によるパターンの確認しやすさ 悪かった点
• 任意の State を注入できるため、コンポーネントの適切な設計は 要検討 ◦ State のバケツリレー ▪ どこまでまとまったデータで扱うか、どこでプリミティブな値で扱うか © 2023 Wantedly, Inc.
KMP を Swift で扱う際の短所 © 2023 Wantedly, Inc.
KMP を Swift で扱う際の短所 • ネストされた型の階層の制限 • sealed class の網羅性チェック
© 2023 Wantedly, Inc.
KMP を Swift で扱う際の短所 • ネストされた型の階層の制限 • sealed class の網羅性チェック
© 2023 Wantedly, Inc.
ネストされた型の階層の制限 © 2023 Wantedly, Inc. KMP は Objective-C のモジュールを生成する
ネストされた型の階層の制限 © 2023 Wantedly, Inc. KMP は Objective-C のモジュールを生成する →
swift_name が複数階層をサポートしていない
ネストされた型の階層の制限 © 2023 Wantedly, Inc. Swift で見ると3階層以降はまとめられてしまう Swift だと型推論を活かして `.`
の左側は省略する ことが多い 階層が定義通りなら KMP の場合でも省略できるが …
KMP を Swift で扱う際の短所 • ネストされた型の階層の制限 • sealed class の網羅性チェック
© 2023 Wantedly, Inc.
sealed class の網羅性チェック © 2023 Wantedly, Inc. Swift では default
が必要になる
sealed class の網羅性チェック © 2023 Wantedly, Inc. Enum を再定義しコンパイルタイムで検知できるよう にインターフェースを用意
sealed class の網羅性チェック © 2023 Wantedly, Inc. Enum を再定義しコンパイルタイムで検知できるよう にインターフェースを用意
※ ライブラリ管理の移行が落ち着いたら自動生成などを検討 https://github.com/icerockdev/moko-kswift → 利用するときは網羅性チェックが効くように 🎉
まとめ KMP と SwiftUI • 100% SwiftUI でリニューアルを実現 🎉 •
KMP も SwiftUI の組み合わせも(癖はありつつ)体験は 👍 • Android も含めたモバイル開発チームの連携で大きくつまづくこともなかった 🤝 © 2023 Wantedly, Inc.
ご清聴ありがとうございました © 2023 Wantedly, Inc.
© 2023 Wantedly, Inc.