Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Compose Multiplatform for iOS でiOSアプリを作る - DMM....

Kaoru Tsutsumishita
March 28, 2024
350

Compose Multiplatform for iOS でiOSアプリを作る - DMM.swift#2

Kaoru Tsutsumishita

March 28, 2024
Tweet

Transcript

  1. © DMM © DMM Compose Multiplatform for iOS で iOSアプリを作る

    DMM.swift#2 - 3/28 合同会社DMM.com - 堤下 薫
  2. © DMM 堤下 薫 / Tsutsumishita Kaoru 合同会社DMM.com 2020年中途入社 開発統括本部

    - アプリ開発室 DMMTV iOS開発のリードエンジニア 最近個人開発アプリを React Native → Compose Multiplatform に置き換えました💪 自己紹介 2
  3. © DMM この発表で話すこと ・Compose Multiplatform ( for iOS ) ってなに?

    ・iOSアプリを作るまでの流れ ・iOS上で動作するまでの仕組み ・iOSっぽいアプリって作れる? ・直近の更新情報 5
  4. © DMM AndroidのUI開発で利用する ”Jetpack Compose”を利用して UI開発を行えるフレームワーク Compose Multiplatform ( for

    iOS ) ってなに? 6   iOS ( Alpha ), Android   Windows, MacOS, Linux   Web ( Experimental ) @Composable fun App() { MaterialTheme { Column { Text("Hello World.") Button(onClick = { /* action */ }) { Text("Button") } } } }
  5. © DMM ・公式チュートリアル  Get started with Compose Multiplatform — tutorial

    ・プロジェクトのセットアップ  Kotlin Multiplatform Wizard ・GitHubリポジトリ  JetBrains/compose-multiplatform  JetBrains/compose-multiplatform-core ( Jetpack Compose 実装 ) JetBrains公式の情報 8
  6. © DMM 11 . ├── composeApp (Androidのディレクトリ) │ └── src

    │ ├── commonMain │ │ └── kotlin.com.jetbrains.kmpapp ─ App.kt │ ├── androidMain │ │ └── kotlin.com.jetbrains.kmpapp ─ MainActivity.kt │ └── iosMain │ └── kotlin.com.jetbrains.kmpapp ─ MainViewController.kt └── iosApp (iOSのディレクトリ) ├── iosApp ─ iOSApp.swift └── iosApp.xcodeproj (1) 共通のUIを開発する (2) AndroidでUI表示 (3) iOSでUIを利用するための準備 (4) iOSでUI表示 ファイル構成
  7. © DMM 12 (1) 共通のUIを開発する: App.kt @Composable fun App() {

    MaterialTheme { Column( modifier = Modifier.fillMaxSize(), /* 全画面に広げる */ horizontalAlignment = Alignment.CenterHorizontally /* 横中央寄せ */ ) { Text("Hello World.") Button(onClick = { /* action */ }) { Text("Button") } } } }
  8. © DMM 13 (2) AndroidでUI表示: MainActivity.kt class MainActivity : ComponentActivity()

    { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { App() } } }
  9. © DMM 14 (3) iOSでUIを利用するための準備 : MainViewController.kt fun MainViewController() =

    ComposeUIViewController { App() } /* ComposeUIViewControllerの定義 */ fun ComposeUIViewController( content: @androidx.compose.runtime.Composable () -> kotlin.Unit ): platform.UIKit.UIViewController
  10. © DMM struct ComposeView: UIViewControllerRepresentable { func makeUIViewController(context: Context) ->

    UIViewController { MainViewControllerKt.MainViewController() } func updateUIViewController(_ uiViewController: UIViewController, context: Context) {} } @main struct iOSApp: App { var body: some Scene { WindowGroup { ComposeView().ignoresSafeArea(.keyboard) // Compose has own keyboard handler } } } 15 (4) iOSでUI表示: iOSApp.swift
  11. © DMM 16 Android / iOS ビルド結果 @Composable fun App()

    { MaterialTheme { Column( modifier = Modifier.fillMaxSize(), horizontalAlignment = Alignment.CenterHorizontally ) { Text("Hello World.") Button(onClick = { /* action */ }) { Text("Button") } } } }
  12. © DMM ComposeUIViewController Jetpack Compose のレイアウトを Swiftで UIViewController として扱うためWrapper 実装の中身

    v1.5.12まで ComposeWindow.uikit.kt v1.6.0 から ComposeContainer.uikit.kt ※ 2024/02/29リリースされたバージョン 19
  13. © DMM 20 fun ComposeUIViewController( configure: ComposeUIViewControllerConfiguration.() -> Unit =

    {}, content: @Composable () -> Unit ): UIViewController = ComposeContainer( configuration = ComposeUIViewControllerConfiguration().apply(configure), content = content, ) ComposeUIViewController.uikit.kt
  14. © DMM 21 internal class ComposeContainer( private val content: @Composable

    () -> Unit, ) : CMPViewController(nibName = null, bundle = null) { private fun setContent(content: @Composable () -> Unit) { val mediator = ComposeSceneMediator( container = view, /* = UIViewController.view */ renderingUIViewFactory = ::createSkikoUIView, ... ) } private fun createSkikoUIView(renderRelegate: RenderingUIView.Delegate): RenderingUIView = RenderingUIView(renderDelegate = renderRelegate).apply { … } } ComposeContainer.uikit.kt
  15. © DMM 22 ComposeSceneMediator.uikit.kt internal class ComposeSceneMediator( private val container:

    UIView, ... private val renderingUIViewFactory: (RenderingUIView.Delegate) -> RenderingUIView, ) { init { container.addSubview(rootView) rootView.addSubview(interopViewContainer) /* UIKitViewでUIView実装以外のViewを扱うため */ rootView.addSubview(interactionView) /* キーボードやタップのインタラクションを管理 */ interactionView.addSubview(renderingView) } }
  16. © DMM 23 import org.jetbrains.skia.Canvas /* fun createSkikoUIView(...) で生成されるView */

    internal class RenderingUIView(...) : UIView(...) { private val metalLayer: CAMetalLayer get() = layer as CAMetalLayer internal val redrawer: MetalRedrawer = MetalRedrawer( metalLayer, callbacks = object : MetalRedrawerCallbacks { override fun render(canvas: Canvas, targetTimestamp: NSTimeInterval) { renderDelegate.render(canvas, targetTimestamp) } } ) } RenderingUIView.uikit.kt
  17. © DMM Skia, Skiko とは? 25 Skia: https://skia.org/, https://github.com/google/skia Flutter

    でも”利用されていた” C++製のレンダリングエンジン ※現在Flutterは Impeller が標準 Skiko: https://github.com/JetBrains/skiko Skia for Kotlinの略 Skia を Kotlin Multiplatform で扱うためのライブラリ
  18. © DMM 登場人物の整理 26  ComposeUIViewController  ComposeをiOSで利用するためのUIViewController  ComposeContainer  👆の内部実装クラス  ComposeSceneMediator  👆のView構成を管理するクラス

     RenderingUIView  ComposeのUIが描画されるView ( MetalLayer )  Skia  C++製のレンダリングエンジン  Skiko  👆をKotlinで利用するためのライブラリ
  19. © DMM JetBrains公式の見解 29 引用元: https://blog.jetbrains.com/ja/kotlin/2023/05/compose-multiplatform-for-ios-is-in-alpha/ クロスプラットフォーム UI フレームワークでは、 要素をどれくらいターゲットプラットフォームの外観に

    似せるかが重要な問題となります。 現時点で、JetBrains チームはネイティブの UI 要素と 一般的な外観の UI 要素のどちらを提供するかについては未決定です。
  20. © DMM ・UIViewController として扱えるため  SwiftUI / UIKit 環境どちらにも導入可能 ・UIKitView, UIKitViewController

    コンポーネントを利用することで  Compose の中に UIKit, SwiftUI を入れ込むことも可能  ⭕ Compose ↔ SwiftUI, UIKit の相互呼び出し レイアウトの特徴(2) 31
  21. © DMM 画面遷移について 32 ・Android標準で使われるAndroidX Navigationは使えない ・公式的には Voyager というライブラリが推奨されている  ※

    iOSのようにプッシュ/モーダル遷移という区別がない ・OS標準に寄せる場合、コード分岐すれば可能  Android: AndroidX Navigation, iOS: NavigationStack
  22. © DMM 36 What's new in Compose Multiplatform 1.6.0 ※2024/02/29リリース ・Aplha版のため、マイナーバージョンの更新でも破壊的変更あり

    ・iOSに追加サポートされた機能  ・Compose UIテスト, Accessibility, etc… ・iOSのUI改修  ・Composeで描画したUIViewController背景の透明化  ・TextFieldのカーソルがよりiOSネイティブに近い動作に変更 etc … 更新情報