AndroidStudioでCompose Multiplatformを試す

## 概要
- Compose Multiplatformを2023年5月の段階で試すときに最初に知っておくと良さそうな知見を書き出してみました
- 変化が激しい領域なので、新鮮さはすぐに失われる情報だと思うので、読んでくださった時期によってはあまり参考にしない方がいいかもしれません🙏

## 目次
- 押さえておきたい開発リポジトリ
- どんな環境でComposeが使えるのか
- テンプレートを使って楽々セットアップ
- Android/iOS/Desktop/Webを網羅したサンプルは存在するのか
- AndroidStudio上でiOSアプリをビルドするPlugin
- Compose for DesktopでUIプレビューを表示するPlugin

## 押さえておきたいリポジトリ
### [JetBrains/compose-multiplatform](https://github.com/JetBrains/compose-multiplatform)
- Compose Multiplatformはここで作られています
- `examples`: サンプルがあります
- `turorial`: 事始めの内容やテンプレートリポジトリへのリンクがあります
- `experimental`: 動画プレイヤーが開発されていそうです

### [Kotlin/kotlin-wasm-examples](https://github.com/Kotlin/kotlin-wasm-examples)
- Kotlin/Wasmでも動作するマルチプラットフォームプロジェクトのサンプルがあります

### [cashapp/molecule](https://github.com/cashapp/molecule)
- Compose Multiplatformにも対応しているため表示ロジックを分離したい場合は採用を検討できそうです

### [arkivanov/Decompose](https://github.com/arkivanov/Decompose)
- ビジネスロジックとルーティング、スタックを管理できるライブラリです
- Kotlin/Wasmには現在対応していませんが、いずれ対応されていくことが予想されます
    - [issues/375](https://github.com/arkivanov/Decompose/issues/375)

他にも出てきた場合は余力があれば足したいと思います。


## どんな環境でComposeが使えるのか
図にしてみました。

まずはKotlin Multiplatformが現在サポートしているターゲットから書き出してみたいと思います。
案外、網羅された図が探しても無かったので、間違っているところがあるかもしれません。
p.s. [ありました](https://kotlinlang.org/docs/multiplatform-hierarchy.html#see-the-full-hierarchy-template)。が、現時点だとwasmがなさそうです

<font color="#DEE2FC">■</font> : `getting`でアクセスできます
<font color="#CDDC39">■</font> : Kotlin Multiplatformプラグインが定義してくれているので`getting`でアクセスできます(Shortcut)
<font color="#DFF5CE">■</font> : `getting`ではアクセスできません。`creating`でグルーピングを新規作成しています
<font color="#86B049">■</font> : main or test をSuffixとしてキャメルケースで繋いで取得します (ex. commonMain, iosTest, etc)

```mermaid
graph RL
    common:::getting
    common -.-> main:::def
    common -.-> test:::def

    jvm:::getting --> common
    web:::creating --> common
    native:::creating --> common
    android:::getting --> common

        js:::getting --> web
        wasm:::getting --> web
    
        desktop:::gettingByShortcut --> native
        darwin:::creating --> native
        androidNative:::creating --> native

            mingw:::creating --> desktop
            linux:::creating --> desktop
            macos:::creating --> desktop

                mingwX64:::getting --> mingw
                linuxX64:::getting --> linux
                linuxArm64:::getting --> linux
                macosX64:::getting --> macos
                macosArm64:::getting --> macos

            ios:::gettingByShortcut --> darwin
            watchos:::gettingByShortcut --> darwin
            tvos:::gettingByShortcut --> darwin
            macos --> darwin

                iosX64:::getting --> ios
                iosArm64:::getting --> ios
                iosSimulatorArm64:::getting -. manually set .-> ios

                watchosArm32:::getting --> watchos
                watchosArm64:::getting --> watchos
                watchosDeviceArm64:::getting --> watchos
                watchosX64:::getting --> watchos
                watchosSimulatorArm64:::getting -. manually set .-> watchos

                tvosArm64:::getting --> tvos
                tvosX64:::getting --> tvos
                tvosSimulatorArm64:::getting -. manually set .-> tvos

            androidNativeArm32:::getting --> androidNative
            androidNativeArm64:::getting --> androidNative
            androidNativeX64:::getting --> androidNative
            androidNativeX86:::getting --> androidNative


    classDef getting fill:#DEE2FC
    classDef gettingByShortcut fill:#CDDC39
    classDef creating fill:#DFF5CE
    classDef def fill:#86B049

```

注釈
- Kotlin1.8.20時点でDeprecatedになっているTargetは除外しています
- `darwin`の箇所はオフィシャルには`apple`と表現されています
- `web`の箇所は`jsWasm`として実装されているところもあります

蛇足ですが、KotlinのTargetは以下に自動生成されたコードがあるので見ると便利です。DesktopのPresetは見当たりませんでした。どこからか参照できるのだとは思います👀

```kotlin
import org.jetbrains.kotlin.gradle.dsl.KotlinTargetContainerWithPresetFunctions
import org.jetbrains.kotlin.gradle.dsl.KotlinTargetContainerWithJsPresetFunctions
import org.jetbrains.kotlin.gradle.dsl.KotlinTargetContainerWithWasmPresetFunctions
import org.jetbrains.kotlin.gradle.dsl.KotlinTargetContainerWithNativeShortcuts
```

Compose Multiplatformは以下で使えます。

```mermaid
graph RL
    common:::getting
    common -.-> main:::def
    common -.-> test:::def

    jvm:::getting --> common
    web:::creatingCompose --> common
    native:::creating --> common
    android:::gettingCompose --> common

        js:::gettingCompose --> web
        wasm:::gettingCompose --> web
    
        desktop:::gettingByShortcutCompose --> native
        darwin:::creating --> native
        androidNative:::creating --> native

            mingw:::creatingCompose --> desktop
            linux:::creatingCompose --> desktop
            macos:::creatingCompose --> desktop

                mingwX64:::gettingCompose --> mingw
                linuxX64:::gettingCompose --> linux
                linuxArm64:::gettingCompose --> linux
                macosX64:::gettingCompose --> macos
                macosArm64:::gettingCompose --> macos

            ios:::gettingByShortcutCompose --> darwin
            watchos:::gettingByShortcut --> darwin
            tvos:::gettingByShortcut --> darwin
            macos --> darwin

                iosX64:::gettingCompose --> ios
                iosArm64:::gettingCompose --> ios
                iosSimulatorArm64:::gettingCompose -. manually set .-> ios

                watchosArm32:::getting --> watchos
                watchosArm64:::getting --> watchos
                watchosDeviceArm64:::getting --> watchos
                watchosX64:::getting --> watchos
                watchosSimulatorArm64:::getting -. manually set .-> watchos

                tvosArm64:::getting --> tvos
                tvosX64:::getting --> tvos
                tvosSimulatorArm64:::getting -. manually set .-> tvos

            androidNativeArm32:::getting --> androidNative
            androidNativeArm64:::getting --> androidNative
            androidNativeX64:::getting --> androidNative
            androidNativeX86:::getting --> androidNative


    classDef getting fill:#FFFFFF
    classDef gettingByShortcut fill:#FFFFFF
    classDef gettingCompose fill:#FFC06E
    classDef gettingByShortcutCompose fill:#FFC06E
    classDef creating fill:#FFFFFF
    classDef creatingCompose fill:#FFC06E
    classDef def fill:#FFFFFF
```

注釈
- `android`とそれ以外とで実装や依存関係の追加を分けたい場合が多そうなので、`nonAndroid`というグループを作っている実装もありました。図では割愛しています。

`creating`で作成したターゲットや、Shortcutで定義されたターゲットごとにComposeの定義を加えることで、シンプルに依存関係を追加することができます。
つまり、上記のグルーピングを開発環境で作っていれば、`ios`、`android`、`web`、`desktop`といったターゲットに対して設定していくことができます。



### テンプレートを使って楽々セットアップ
対応したいプラットフォームによって、テンプレートも複数用意されています。要件にあったものを選ぶと良いでしょう。

- Android, iOS, Desktop
    - https://github.com/JetBrains/compose-multiplatform-template
- Android, iOS (KMM)
    - https://github.com/JetBrains/compose-multiplatform-ios-android-template
- Desktop
    - https://github.com/JetBrains/compose-multiplatform-desktop-template

## Android/iOS/Desktop/Webを網羅したサンプルは存在するのか
Kotlin Multiplatformに対応しており、対応PFも多いサンプルプロジェクトは存在しますが、Compose Multiplatformかつ対応PFが多いものはまだ少ないようです。
Kotlin/Wasmが使えるようになったことで、Kotlin/JSで動作する状態から移行していきたい時期なのかなと思います。
そのため、手前で紹介した[ Kotlin/kotlin-wasm-examples ](https://github.com/Kotlin/kotlin-wasm-examples)にある以下2つのサンプルを追っておくと良さそうです。

- `compose-imageviewer`
- `compose-jetsnack`

[JetBrains/compose-multiplatform ](https://github.com/JetBrains/compose-multiplatform)にもWebで動作するサンプルがありますが、こちらは現在はKotlin/JSで動いています

- `todoapp`


## AndroidStudio上でiOSアプリをビルドするPlugin
- 入れるだけなのですが、たどり着くのに多少時間がかかったので、参照してみてください。
    - iOSでビルドする際は、[ kdoctor ](https://github.com/Kotlin/kdoctor)を使って環境のセットアップができているかを確認した上で進められると良さそうです

https://plugins.jetbrains.com/plugin/14936-kotlin-multiplatform-mobile

## Compose for DesktopでUIプレビューを表示するPlugin
- こちらも同じく入れるだけです。

https://plugins.jetbrains.com/plugin/16541-compose-multiplatform-ide-support