📝

ココナラAndroidアプリへのJetpack Compose導入

2023/05/29に公開

こんにちは。株式会社ココナラアプリ開発グループ、Androidチームの藤永です。

今回は、ココナラのAndroidアプリ開発でJetpack Composeを導入するにあたって取り組んだことをご紹介します。

ココナラのAndroidアプリは2014年の初回リリースからこれまで、Android Viewで画面を構築していました。
一方で、2021年にJetpack Composeのv1.0がリリースされて以後、Androidアプリ開発においてはJetpack Composeを用いた宣言的UIによって画面を構築することが主流となりつつあり、Google公式の各種サンプル実装やドキュメントもJetpack Composeに基づいた内容に更新されてきています。

今後、ココナラのAndroidアプリでも段階的にJetpack Composeを用いた実装にシフトしていくことを計画しています。

ココナラAndroidアプリの構成

ココナラAndroidアプリはマルチモジュール構成を採用しており、以下のような形で構成されています。

モジュール構成

一定の機能単位でfeature:モジュールが存在しており、app:から各モジュールを参照して一つのアプリが構成されています。
core:モジュールには各モジュールから共通で参照されるようなデザインシステムの定義やリソース、各種共通ロジックが存在しています。

各画面はMVVMで構成されており、画面ごとにActivity + Fragment + ViewModel が存在しています。
ViewModelとFragment(やレイアウト)とはLiveData + Data bindingで実現しており、ViewModelはRepositoryを介してAPIを呼び出します。

画面単位の構成

ViewModelからViewの層へイベントを通知する必要がある場合は、Navigatorと呼称するinterfaceの実装をFragmentが所有し、ViewModelからNavigatorのメソッドを呼び出す形となっています。
他モジュール内の画面を表示する場合など、モジュールをまたぐ処理についてはapp:モジュールでinterfaceを実装し、そのinterfaceのメソッドを各モジュール内から呼び出すことで実現しています。

Jetpack Compose導入までのフロー

バージョンの選定

Jetpack ComposeのバージョンはAndroid Gradle Plugins (AGP)やKotlin、Lifecycle系ライブラリとの関連性があるため、スムーズに導入できるバージョンを選定する必要がありました。
ココナラの画面デザインで必要となるAPIが使用できそうなバージョンを検討し、v1.2.0を選択しました。

試作

ココナラアプリ内で使用しているUIコンポーネントをComposeの実装に移行した際に課題となるポイントを洗い出すことにしました。

この試作においてはNow In Androidの実装を参考に、既存の画面をいくつかピックアップしてJetpack Composeで実装し直してみました。このとき注意したのは下記のような観点です。

  • つまづくポイントはどこか
  • 非Composeの画面との親和性を考慮した構成はどのようなものになるか
  • Android Viewでは容易に実現できるが、Compose移行後は実現困難となるような機能はないか
  • Android Viewと大きくデザインが異なるコンポーネントはないか

他のメンバにも内容を確認してもらい、同じように自分で実装しようと思ったときに困りそうな点などをヒアリングしました。

ドキュメント作成

試作とヒアリング結果を受け、これまでと実装の仕方が異なるうえに実装の自由度が高いことで、メンバごとに実装の仕方に差が生まれそうというのが懸念として挙がりました。

そこで、導入後に各メンバが迷わずに開発できるだけの指針が必要と考え、下記のようなドキュメントを作成しました。
各ドキュメントは他のメンバにもレビューを依頼し、目線を揃えました。

  • アーキテクチャの差分説明、サンプル実装
  • Composable関数のコーディングルール
  • 実装ガイドライン
    • どこに何を実装するかの判断指針
    • 今後の改修時に画面全体をリプレイスすべきか、コンポーネント単位でリプレイスすべきか、Android Viewのまま回収するかの判断指針
    • 基本構成での実装例
  • 参考URLの一覧

段階的に移行していくことも踏まえて、アーキテクチャは大きく変更せずに以下のような形を取ることにしました。
FragmentはComposable関数に置き換わり、Navigatorは各UI操作のコールバックはViewModelを経由しなくなるため不要になりました。

画面単位の構成

ViewModel上のデータはLiveDataからStateFlowへ移行することにしました。

コーディングルールについてはJetpack ComposeのAPIとの親和性を考慮してCompose APIガイドラインをベースにしつつ、既存のコーディングルールとの親和性を考慮して命名規則などをカスタマイズする形で策定しました。

デザイン観点での検討

ココナラのアプリ開発はデザインシステムに基づいて開発されており、共通コンポーネントのスタイルを定義して各画面で共通利用する形になっています。

ただし、画面によっては古いデザインが残っていたり、定義されている共通デザインと実装とで乖離があったりと、整理しきれていない部分が以前から課題となっていました。
また、OS標準コンポーネント自体にもAndroid ViewとJetpack Composeとで見た目や振る舞いに差があるものもあり、既存の見た目を100%再現すること自体が難しいケースも存在します。

これらの課題はエンジニアサイドだけで解決することはできないため、デザイナーと協力しながら機能開発とは別に各コンポーネントを再定義することにしました。
デザインとしてどうあるべきか、実装上どのようにすべきか、お互いの意見を交換し合いつつ実際の動作を確認しながら進めています。

まとめと今後について

今回はココナラのAndroidアプリ開発でJetpack Composeを導入する際に取り組んだ内容をお伝えしました。

現段階での取り組みはJetpack Composeを導入するところまでに留まっており、引き続き取り組みが必要です。

既存のAndroid Viewで実装された画面がなくなるまで少しずつ実装を置き換えていく必要がありますし、各共通コンポーネントの実装は継続していくことになります。
ComposeはAndroid Viewと比較してノウハウがまだ浅いため、今後もそれなりに壁にぶつかるように思いますが、古いものにしがみつかずに改善していきたいと思っています。

Discussion