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
ねも
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
CDK対応したAWS DevOps Agentを試そう_20260201
masakiokuda
1
340
こんなところでも(地味に)活躍するImage Modeさんを知ってるかい?- Image Mode for OpenShift -
tsukaman
1
160
顧客の言葉を、そのまま信じない勇気
yamatai1212
1
360
広告の効果検証を題材にした因果推論の精度検証について
zozotech
PRO
0
190
[CV勉強会@関東 World Model 読み会] Orbis: Overcoming Challenges of Long-Horizon Prediction in Driving World Models (Mousakhan+, NeurIPS 2025)
abemii
0
140
OpenShiftでllm-dを動かそう!
jpishikawa
0
130
日本の85%が使う公共SaaSは、どう育ったのか
taketakekaho
1
230
Ruby版 JSXのRuxが気になる
sansantech
PRO
0
160
プロダクト成長を支える開発基盤とスケールに伴う課題
yuu26
4
1.3k
Embedded SREの終わりを設計する 「なんとなく」から計画的な自立支援へ
sansantech
PRO
3
2.5k
22nd ACRi Webinar - NTT Kawahara-san's slide
nao_sumikawa
0
100
30万人の同時アクセスに耐えたい!新サービスの盤石なリリースを支える負荷試験 / SRE Kaigi 2026
genda
4
1.3k
Featured
See All Featured
[RailsConf 2023] Rails as a piece of cake
palkan
59
6.3k
Skip the Path - Find Your Career Trail
mkilby
0
57
How to build an LLM SEO readiness audit: a practical framework
nmsamuel
1
650
AI Search: Where Are We & What Can We Do About It?
aleyda
0
7k
A Tale of Four Properties
chriscoyier
162
24k
How to Create Impact in a Changing Tech Landscape [PerfNow 2023]
tammyeverts
55
3.2k
Beyond borders and beyond the search box: How to win the global "messy middle" with AI-driven SEO
davidcarrasco
1
55
Leadership Guide Workshop - DevTernity 2021
reverentgeek
1
200
How to train your dragon (web standard)
notwaldorf
97
6.5k
Mobile First: as difficult as doing things right
swwweet
225
10k
Mozcon NYC 2025: Stop Losing SEO Traffic
samtorres
0
140
Money Talks: Using Revenue to Get Sh*t Done
nikkihalliwell
0
150
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