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
81
ノンデザイナーズ・デザインブックを読んだので名刺作ってみた
kohei_inoue
0
91
Compose Multiplatform for iOSで音声再生しようぜ!!
kohei_inoue
0
300
夏 × Jetpack Compose
kohei_inoue
0
85
Compose for iOS for ZOZOTOWN
kohei_inoue
0
1.6k
Other Decks in Technology
See All in Technology
JAZUG 15周年記念 × JAT「AI Agent開発者必見:"今"のOracle技術で拡張するAzure × OCIの共存アーキテクチャ」
shisyu_gaku
1
160
20251007: What happens when multi-agent systems become larger? (CyberAgent, Inc)
ornew
1
180
AWS Top Engineer、浮いてませんか? / As an AWS Top Engineer, Are You Out of Place?
yuj1osm
2
210
Trust as Infrastructure
bcantrill
1
370
AWS 잘하는 개발자 되기 - AWS 시작하기: 클라우드 개념부터 IAM까지
kimjaewook
0
130
英語は話せません!それでも海外チームと信頼関係を作るため、対話を重ねた2ヶ月間のまなび
niioka_97
0
130
ユーザーの声とAI検証で進める、プロダクトディスカバリー
sansantech
PRO
1
130
セキュアな認可付きリモートMCPサーバーをAWSマネージドサービスでつくろう! / Let's build an OAuth protected remote MCP server based on AWS managed services
kaminashi
3
290
「AI駆動PO」を考えてみる - 作る速さから価値のスループットへ:検査・適応で未来を開発 / AI-driven product owner. scrummat2025
yosuke_nagai
3
810
Shirankedo NOCで見えてきたeduroam/OpenRoaming運用ノウハウと課題 - BAKUCHIKU BANBAN #2
marokiki
0
180
Geospatialの世界最前線を探る [2025年版]
dayjournal
1
200
2025-10-09_プロジェクトマネージャーAIチャンス
taukami
0
110
Featured
See All Featured
The Illustrated Children's Guide to Kubernetes
chrisshort
49
51k
"I'm Feeling Lucky" - Building Great Search Experiences for Today's Users (#IAC19)
danielanewman
229
22k
VelocityConf: Rendering Performance Case Studies
addyosmani
332
24k
StorybookのUI Testing Handbookを読んだ
zakiyama
31
6.2k
Into the Great Unknown - MozCon
thekraken
40
2.1k
JavaScript: Past, Present, and Future - NDC Porto 2020
reverentgeek
52
5.6k
A designer walks into a library…
pauljervisheath
209
24k
jQuery: Nuts, Bolts and Bling
dougneiner
65
7.9k
How to Ace a Technical Interview
jacobian
280
24k
個人開発の失敗を避けるイケてる考え方 / tips for indie hackers
panda_program
114
20k
GitHub's CSS Performance
jonrohan
1032
470k
Designing Dashboards & Data Visualisations in Web Apps
destraynor
231
53k
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