skip to content
私的歌詞倉庫

Remote Composeを使ってボタンを作る

/ 9 min read

Updated:
Table of Contents

はじめに

最近Jetpack ComposeにRemote Composeというライブラリが追加されました(最近といっても半年くらい前?)。

このライブラリを使うことでサーバーサイドで定義したComposeをAndroidアプリ上で表示できるようになります。描画方法としてはComposeのレイアウトをバイトデータとして設置して、それをAndroid側から取得して再生することで表示できるようでした。

まだ完全には理解してないのですがとりあえず表示まではできたので紹介したいと思います。

今回使用したライブラリとバージョンはこちらです。

libs.versions.toml
[versions]
remoteCompose = "1.0.0-alpha05"
[libraries]
remote-core = { group = "androidx.compose.remote", name = "remote-core", version.ref = "remoteCompose" }
remote-creation = { group = "androidx.compose.remote", name = "remote-creation", version.ref = "remoteCompose" }
remote-creation-core = { group = "androidx.compose.remote", name = "remote-creation-core", version.ref = "remoteCompose" }
remote-creation-android = { group = "androidx.compose.remote", name = "remote-creation-android", version.ref = "remoteCompose" }
remote-creation-compose = { group = "androidx.compose.remote", name = "remote-creation-compose", version.ref = "remoteCompose" }
remote-player-core = { group = "androidx.compose.remote", name = "remote-player-core", version.ref = "remoteCompose" }
remote-player-view = { group = "androidx.compose.remote", name = "remote-player-view", version.ref = "remoteCompose" }
remote-tooling-preview = { group = "androidx.compose.remote", name = "remote-tooling-preview", version.ref = "remoteCompose" }
remote-player-compose = { group = "androidx.compose.remote", name = "remote-player-compose", version.ref = "remoteCompose" }

実装したコードはGitHubにアップしています。

Lorem ipsum dolor sit amet, consectetur adipiscing elit.
00K00KMIT

Remote Composeのコードはこちらにあるので具体的な内部の処理を見たい場合はこちらを見てください。

実装したコード

今回はサーバーに設置して読み取りはせずに、ローカルでデータを作ってバイトデータに変換して、読み取り&表示を実装します。

コードの流れはこちらです。

  1. RemoteComposeContextAndroidを使ってComposeで描画したいレイアウトを作成
    • 作成したレイアウトをRemoteComposeWriter形式に変換後さらにバイトデータに変換
    • クリック時になにか処理をさせたい場合はonClickでActionを指定
  2. バイトデータを取得後RemoteDocumentPlayerで描画
    • クリック処理をしたい場合はonActionでActionで指定した値で判定し処理

UI構築

まずはUIのコードです。

CreateYellowButtonRemoteCompose.kt
@SuppressLint("RestrictedApi")
fun createYellowButtonRemoteCompose(): RemoteComposeWriter {
return RemoteComposeContextAndroid(
width = 500,
height = 300,
contentDescription = "Yellow Button",
apiLevel = 6,
profiles = 0,
platform = AndroidxRcPlatformServices(),
) {
root {
box(RecordingModifier()
.background(Color.YELLOW)
.onClick(HostAction(100))
) {
text("This is Button!")
}
}
}.writer
}

RemoteComposeContextAndroidではapiLevelでは使用するAPIのバージョンを指定しました(こちらを参考にとりあえず6にしました)。 今回はAndroidで表示するためにplatformでAndroidxRcPlatformServices()を指定しました。

widthとheightはサイズなのはわかるんですが、RecordingModifier().fillMaxSize()を指定したらサイズいっぱいに広がるので何を指定しているかはよくわかってないです…

ここからRemote Composeのレイアウト記法です。

rootからRemote Composeで指定したレイアウトという指示を出しているようでした(root抜きだとAndroid側で表示できませんでした)。

boxでボタンの領域を作ります。Remote Composeにはまだbuttonがないためboxで作りました。

onClick(HostAction(100))でAndroid側でボタンのクリック処理をするために実装しました。この引数の数値(100)を使ってAndroid側で特定の処理を実行します。Remote Compose側で具体的な処理(特定のAPIにリクエストを送るとか)はできないようでした(セキュリティ的な観点でも今後できるようなことはなさそう…)。数値以外にも文字列などを指定することも可能みたいです。

表示側

次にAndroid側のコードです。

MyRemoteScreen.kt
@SuppressLint("RestrictedApi")
@Composable
fun MyRemoteScreen() {
val binaryData = remember { createYellowButtonRemoteCompose().encodeToByteArray() }
val remoteDocument = remember(binaryData) { RemoteDocument(binaryData) }
if (remoteDocument != null) {
RemoteDocumentPlayer(
document = remoteDocument.document,
documentWidth = 500,
documentHeight = 300,
modifier = Modifier
.background(Color.Red),
onAction = { id, res ->
when (id) {
100 -> println("Button Clicked!")
}
println("id=${id}, res=${res}")
},
debugMode = 0,
)
}
}

RemoteDocumentPlayerで受け取ったデータを表示します。

今回は数値(onClick(HostAction(100)))でクリック時のIDを指定したので、onActionのidで100の場合はButton Clicked!をログに出力するようにしました。これをうまく使えばクリック時の処理をあらかじめAndroidで実装しておくことで、サーバー側で任意のタイミングで特定の処理(ページの遷移先を変えるとか)をすることができそうで色々使い道がありそうです。

今回実装したコードを実行するとこのような画面になります。

Remote Composeを表示したスクショ

その他

実装以外での注意点です。

新規でAndroidプロジェクトを作っていたのですが、コードを書いてビルドするとこちらのエラーが出ました。 androidx.compose.remote.player.composeのライブラリを使うにはminSdkを29以上にするか、tools:overrideLibrary="androidx.compose.remote.player.compose"を使って強制的に上書きして使う必要がありました。今回はminSdkのバージョンを29にすることで解決しました。

エラーメッセージ
Manifest merger failed : uses-sdk:minSdkVersion 24 cannot be smaller than version 29 declared in library [androidx.compose.remote:remote-player-compose:1.0.0-alpha05] /.gradle/caches/9.2.1/transforms/05a536aeaf9f8e7c6484b279b14160ed/transformed/remote-player-compose-1.0.0-alpha05/AndroidManifest.xml as the library might be using APIs not available in 24
Suggestion: use a compatible library with a minSdk of at most 24,
or increase this project's minSdk version to at least 29,
or use tools:overrideLibrary="androidx.compose.remote.player.compose" to force usage (may lead to runtime failures)

次に使用するライブラリについてです。

特に何も考えずにこちらに載っていたライブラリを全部入れたのですが、remote-creation-jvmremote-creation-androidでライブラリ内でコードが重複してエラーが出ました。今回はAndroidで検証したかったので、remote-creation-jvmを削除して解決しました。

エラーメッセージ
Duplicate class androidx.compose.remote.creation.ExperimentalRemoteCreationApi found in modules remote-creation-jvm-1.0.0-alpha05.jar -> remote-creation-jvm-1.0.0-alpha05 (androidx.compose.remote:remote-creation-jvm:1.0.0-alpha05) and remote-creation.aar -> remote-creation-runtime (androidx.compose.remote:remote-creation-android:1.0.0-alpha05)
Duplicate class androidx.compose.remote.creation.RemotePath found in modules remote-creation-jvm-1.0.0-alpha05.jar -> remote-creation-jvm-1.0.0-alpha05 (androidx.compose.remote:remote-creation-jvm:1.0.0-alpha05) and remote-creation.aar -> remote-creation-runtime (androidx.compose.remote:remote-creation-android:1.0.0-alpha05)
Duplicate class androidx.compose.remote.creation.RemotePath$Companion found in modules remote-creation-jvm-1.0.0-alpha05.jar -> remote-creation-jvm-1.0.0-alpha05 (androidx.compose.remote:remote-creation-jvm:1.0.0-alpha05) and remote-creation.aar -> remote-creation-runtime (androidx.compose.remote:remote-creation-android:1.0.0-alpha05)
Duplicate class androidx.compose.remote.creation.RemotePathBase found in modules remote-creation-jvm-1.0.0-alpha05.jar -> remote-creation-jvm-1.0.0-alpha05 (androidx.compose.remote:remote-creation-jvm:1.0.0-alpha05) and remote-creation.aar -> remote-creation-runtime (androidx.compose.remote:remote-creation-android:1.0.0-alpha05)
Duplicate class androidx.compose.remote.creation.RemotePathBase$Companion found in modules remote-creation-jvm-1.0.0-alpha05.jar -> remote-creation-jvm-1.0.0-alpha05 (androidx.compose.remote:remote-creation-jvm:1.0.0-alpha05) and remote-creation.aar -> remote-creation-runtime (androidx.compose.remote:remote-creation-android:1.0.0-alpha05)
Duplicate class androidx.compose.remote.creation.RemotePathBaseKt found in modules remote-creation-jvm-1.0.0-alpha05.jar -> remote-creation-jvm-1.0.0-alpha05 (androidx.compose.remote:remote-creation-jvm:1.0.0-alpha05) and remote-creation.aar -> remote-creation-runtime (androidx.compose.remote:remote-creation-android:1.0.0-alpha05)

終わりに

Remote Composeを使って描画までをやってみました。まだ最新なだけあって解説記事が1件くらいしか見当たらず、ほぼGeminiに相談しながら実装してみました。

まだ複雑なUIは難しそうですが、簡単なボタンの実装や、特定の画面遷移させる程度だったら便利そうです。使い方次第では他にももっとすごいことも出来そうだなと思っているので引き続き調査をしたいと思います。

今回は使いませんでしたが、@RemoteComposableなどの何に使うかよくわからない機能が他にも色々ありそうです…

参考文献