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
Compose Multiplatform for iOS開発でぶつかった壁
Search
Sponsored
·
SiteGround - Reliable hosting with speed, security, and support you can count on.
→
ねも
January 24, 2024
Technology
0
1.7k
Compose Multiplatform for iOS開発でぶつかった壁
2024/1/23に行われたZOZO Tech Meetup -Android-における発表資料です。
ねも
January 24, 2024
Tweet
Share
More Decks by ねも
See All by ねも
ノンプログラマのための ~アルゴリズムパズル プログラマのための数学パズル入門~
kohei_inoue
0
84
ノンデザイナーズ・デザインブックを読んだので名刺作ってみた
kohei_inoue
0
93
Compose Multiplatform for iOSで音声再生しようぜ!!
kohei_inoue
0
340
夏 × Jetpack Compose
kohei_inoue
0
87
Compose for iOS for ZOZOTOWN
kohei_inoue
0
1.7k
Other Decks in Technology
See All in Technology
AzureでのIaC - Bicep? Terraform? それ早く言ってよ会議
torumakabe
1
580
[CV勉強会@関東 World Model 読み会] Orbis: Overcoming Challenges of Long-Horizon Prediction in Driving World Models (Mousakhan+, NeurIPS 2025)
abemii
0
140
データの整合性を保ちたいだけなんだ
shoheimitani
8
3.2k
顧客の言葉を、そのまま信じない勇気
yamatai1212
1
360
AWS Network Firewall Proxyを触ってみた
nagisa53
1
240
Digitization部 紹介資料
sansan33
PRO
1
6.8k
30万人の同時アクセスに耐えたい!新サービスの盤石なリリースを支える負荷試験 / SRE Kaigi 2026
genda
4
1.3k
Webhook best practices for rock solid and resilient deployments
glaforge
2
300
10Xにおける品質保証活動の全体像と改善 #no_more_wait_for_test
nihonbuson
PRO
2
310
コスト削減から「セキュリティと利便性」を担うプラットフォームへ
sansantech
PRO
3
1.5k
Embedded SREの終わりを設計する 「なんとなく」から計画的な自立支援へ
sansantech
PRO
3
2.5k
Introduction to Bill One Development Engineer
sansan33
PRO
0
360
Featured
See All Featured
The agentic SEO stack - context over prompts
schlessera
0
640
How To Stay Up To Date on Web Technology
chriscoyier
791
250k
Build The Right Thing And Hit Your Dates
maggiecrowley
39
3k
The Art of Programming - Codeland 2020
erikaheidi
57
14k
エンジニアに許された特別な時間の終わり
watany
106
230k
[Rails World 2023 - Day 1 Closing Keynote] - The Magic of Rails
eileencodes
38
2.7k
Jess Joyce - The Pitfalls of Following Frameworks
techseoconnect
PRO
1
66
jQuery: Nuts, Bolts and Bling
dougneiner
65
8.4k
brightonSEO & MeasureFest 2025 - Christian Goodrich - Winning strategies for Black Friday CRO & PPC
cargoodrich
3
100
Beyond borders and beyond the search box: How to win the global "messy middle" with AI-driven SEO
davidcarrasco
1
55
Noah Learner - AI + Me: how we built a GSC Bulk Export data pipeline
techseoconnect
PRO
0
110
Imperfection Machines: The Place of Print at Facebook
scottboms
269
14k
Transcript
Compose Multiplatform for iOS ։ൃͰͿ͔ͭͬͨน XʢچTwitterʣ: https://twitter.com/nemo_855 GitHub: https://github.com/nemo-855 Qiita:
https://qiita.com/nemo-855 Android ΤϯδχΞ Ҫ্ ߊฏ / Ͷ 1
Ҫ্ߊฏ @nemo_855 XͰϑΥϩʔ͓ئ͍͠·͢🙏 • ZOZOTOWN։ൃຊ෦ ZOZOTOWN։ൃ1෦ Android2ϒϩοΫ • Α͏͘VIVANTΛݟ࢝Ί·ͨ͠ 2
ݸਓͰiOSͱAndroidΞϓϦΛ࡞͠·ͨ͠ʂ 3 iOS൛ Android൛
Jetpack Composeͱಉ͡ॻ͖ຯͰ iOSΞϓϦΛ࡞ΕΔͷ͍͢͝ʂʂ 4 iOS൛ Android൛
͚ͩͲɺɺɺ 5 iOS൛ Android൛
🍎 ࣍ 6 🍋 TextFieldΛλοϓͨ࣌͠ͷڍಈ 🍋 Android Context 🍋 ݖݶϦΫΤετͷਏΈ
🍍 TextFieldΛλοϓͨ࣌͠ͷڍಈ ͦͷ1 TextFieldΛλοϓͨ࣌͠ʹɺ ը໘֎ʹεΫϩʔϧͯ͠͠·͏ɻ 7
ComposeUiViewControllerͷconfigureҾʹ onFocusBehavior.DoNothingΛࢦఆ͢Εྑ͍ 🍍 TextFieldΛλοϓͨ࣌͠ͷڍಈ ͦͷ2 fun PostViewController( viewModel: PostViewModel, closePage:
() -> Unit, ): UIViewController { return ComposeUIViewController( configure = { onFocusBehavior = OnFocusBehavior.DoNothing }, ) { PostPage( context = IosKmpContext, viewModel = viewModel, closePage = closePage ) } } 8
໌֬ʹ͜ͷόάʹ͍ͭͯͷ GitHub issue͕ແ͔ͬͨ ↓ #3128, #3537, #3856ͳͲͷ ؔ࿈͢Δissue͔Βਪଌͯ͠ࢼߦࡨޡ͢ Δ͔͠ͳ͍ 🍍
TextFieldΛλοϓͨ࣌͠ͷڍಈ ͦͷ3 9
🍐 Android Context ͦͷ1 Compose Multiplatformͷڞ༗ϞδϡʔϧͰɺ ը૾Λѻ͏ࡍʹͲ͏ͯ͠ Android Context͕ඞཁʹͳΔ 10
🍐 Android Context ͦͷ2 11 actual fun Uri.getImageFlow(context: KmpContext): Flow<ImageBitmap>
{ return flow { val bitmap = this.getBitmapOrNull(context.contentResolver) if (bitmap != null) { emit(bitmap) } } } private fun Uri.getBitmapOrNull(contentResolver: ContentResolver): ImageBitmap? { return kotlin.runCatching { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { val source = ImageDecoder.createSource(contentResolver, this) ImageDecoder.decodeBitmap(source) } else { MediaStore.Images.Media.getBitmap(contentResolver, this) } }.getOrNull()?.asImageBitmap() }
🍐 Android Context ͦͷ3 // commonMain expect abstract class KmpContext
// androidMain actual typealias KmpContext = android.content.Context // iosMain actual abstract class KmpContext object IosContext : KmpContext() kotlinlang SlackνϟϯωϧͰ հ͞Ε͍ͯͨख๏ ӈਤͷΑ͏ͳKmpContextΛ࡞͢Δ 12
🍐 Android Context ͦͷ3 // commonMain expect abstract class KmpContext
// androidMain actual typealias KmpContext = android.content.Context // iosMain actual abstract class KmpContext object IosContext : KmpContext() AndroidଆͰAndroidͷContextɺ iOSଆͰμϛʔͷContextΛ༻͢Δ 13
🍐 Android Context ͦͷ4 AndroidଆͷࣄΛڞ௨Ϟδϡʔϧʹແཧཧ ࣋ͪࠐΜͰ͍ΔͷͰෳࡶͳॲཧʹͳ͍ͬͯΔ Compose MultiplatformಠࣗͷਏΈ 14
ը૾ͷΞΫηεͷࡍʹͦΕͧΕͷOSͰݖݶ ΛϦΫΤετ͠ͳ͍ͱ͍͚ͳ͍͕ɺ ͦΕΒͷॲཧΛڞ௨Խ͢Δ͜ͱ͕͍͠ ↓ ίϯϙʔωϯτͷߏΛ͢Δ 🥭 ݖݶϦΫΤετͷਏΈ ͦͷ1 15
🥭 ݖݶϦΫΤετͷਏΈ ͦͷ3 val launcher = rememberLauncherForActivityResult(contract = ActivityResultContracts.RequestPermission()) {
// ͜͜ͰݖݶͷεςʔλεʹԠͯ͡ذॲཧ } val permission = if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.TIRAMISU) { READ_EXTERNAL_STORAGE } else { READ_MEDIA_IMAGES } launcher.launch(permission) PHPhotoLibrary.requestAuthorization { status in // ίίͰݖݶͷεςʔλεʹԠͯ͡ذॲཧ } Android iOS 16
🥭 ݖݶϦΫΤετͷਏΈ ͦͷ3 val launcher = rememberLauncherForActivityResult(contract = ActivityResultContracts.RequestPermission()) {
// ͜͜ͰݖݶͷεςʔλεʹԠͯ͡ذॲཧ } val permission = if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.TIRAMISU) { READ_EXTERNAL_STORAGE } else { READ_MEDIA_IMAGES } launcher.launch(permission) PHPhotoLibrary.requestAuthorization { status in // ίίͰݖݶͷεςʔλεʹԠͯ͡ذॲཧ } Android iOS ݖݶϦΫΤετͷॲཧ & ݖݶεςʔλεͷछྨ͕ҟͳΔͷͰɺ expect / actualͰڞ௨Խ͕͠ਏ͍ 17
commonMain 🥭 ݖݶϦΫΤετͷਏΈ ͦͷ4 androidMain iosApp Template Page View View
ը໘ભҠॲཧ ʢCompose Navigationʣ View ը໘ભҠॲཧ (SwiftUI) 18
commonMain 🥭 ݖݶϦΫΤετͷਏΈ ͦͷ5 androidMain iosApp Template Page View View
ը໘ભҠॲཧ ʢCompose Navigationʣ View ը໘ભҠॲཧ (SwiftUI) ɾը໘ͷঢ়ଶͷཧ ɾViewModelͷอ࣋ expect / actualͰڞ௨ԽͰ͖ͳ͍ॲཧ ྫʣ ݖݶϦΫΤετॲཧ 19
🥭 ݖݶϦΫΤετͷਏΈ ͦͷ6 @Composable fun PostView(closeView: () -> Unit) {
// ViewModelऔಘॲཧ val launcher = rememberLauncherForActivityResult(contract = ActivityResultContracts.RequestPermission()) { // no-op } LaunchedEffect(Unit) { if (!PermissionChecker(context).isGallaryPermissionGranted()) { PermissionRequester().requestGallaryPermission(launcher) } } PostPage( context = context, viewModel = viewModel, closePage = closeView, ) } 20
🥭 ݖݶϦΫΤετͷਏΈ ͦͷ7 private struct PostView: UIViewControllerRepresentable { // লུ:
ϓϩύςΟͷॳظԽॲཧ func makeUIViewController(context: Context) -> UIViewController { if (!isGallaryPermissionGranted()) { requestGallaryPermission(completion: { isGranted in // no-op }) } return MainKt.PostViewController( viewModel: viewModel, closePage: closeView ) } // লུ: updateUIViewController, dismantleUIViewController } 21
͕ࣗͿ͔ͭͬͨนΛհ͢Δ͜ͱͰɺ ผͷਓ͕ಉ͡༰ͰࠔΒͳ͍Α͏ʹͳͬͯཉ͍͠ʂʂ 22
🍇 ࢀߟ ✓ https://github.com/JetBrains/compose-multiplatform/issues/3128 ✓ https://github.com/JetBrains/compose-multiplatform/issues/3537 ✓ https://github.com/JetBrains/compose-multiplatform/issues/3856 ✓ https://kotlinlang.org/community/
23
24