見出し画像

REALITY Androidで使っている技術

REALITYでAndroidエンジニアをやっている、はるです。最近は煮干しに興味があります。

今回は煮干しの話・・・ではなく、REALITYのAndroidアプリで使っている技術を紹介したいと思います。

REALITYとは

こんな感じのバーチャルライブ配信アプリです。

歴史とチーム構成

REALITYは2018年夏にリリースしたアプリです(Androidで言えばJetpackが出始めたあたりですね)。リリース初期は動画の視聴機能だけを持ったアプリでした。その後、2018年冬にUnityで書かれた配信用アプリのREALITY Avatarをリリースし、2019年にはこの2つのアプリを1つに統合して(!!)、現在のREALITYに至っています。

開発初期のAndroidエンジニアは1~2名で、そこから増えたり減ったりがあり、現在は4名ほどで開発を行っています。

基本的なところ

* Kotlin
* Unity
* minSdkVersion: 21 -> 24
* targetSdkVersion: 29 -> 30
* AndroidX
* AppBundle
* Gradle Kotlin DSL

特徴的なのはUnityでしょうか。とはいえAndroidチームとUnityチームは別になっており、AndroidエンジニアがKotlin以外を書くことはほとんど無いです。

minSdkVersionは見直しをしていて、数カ月後に24にあげる予定があります。targetSdkVersionに関してもAndroid 11対応はほぼ完了していて、気づいた頃には30になっているかな、という感じです。

Gradle Kotlin DSLは部分的に導入していますが、技術的関心によるところが大きく、恩恵も現状はそこまで無いので、ややオーバーエンジニアリング気味です。

UnityとAndroid

前述の通り、今のREALITYは元々AndroidアプリだったところにUnityを追加していて、画面によってUnityが動いたり動かなかったりします。詳細は長くなるので省略しますが、普通のAndroidアプリが動作していて、必要に応じてUnityのViewやActivityがその上に乗っかるようなものと思ってください。

AndroidプロジェクトとUnityプロジェクトは別管理になっており、
Unityプロジェクトの生成物をAndroidのライブラリとして読み込みような形になっています。したがってAndroid側から見たUnityは一般のライブラリ同様、必要に応じてバージョンを更新をするだけで、(Unityに関連した機能開発でない限り)Unityをそこまで意識することなく開発できるようになっています。

アーキテクチャ

ベースはGoogleのアーキテクチャガイドに沿ったMVVMです。AACフル活用です。最近ではViewModel/Repositoryの肥大化に伴って間にUseCaseを導入しました。レイヤ間の通信はRxやコールバックによる通知でやり取りをしていましたが、最近はほぼコルーチンを使う形になっています。データレイヤからFlowで値を流していき、ViewModel以降はLiveDataに変換して使うような使い方で、そういった点ではAndroid Dev Summit appの構成に近いかもしれません。

モジュール分割

これもまた詳細を語ると長くなりそうな、難しいトピックです。

細かい戦略は色々ありますが、大方針としてはこちらの記事を参考にしています。モジュールを大きくFeatureモジュールとLibraryモジュールの2種類に分類します。

Featureモジュールは次のような性質を持っていて

* 画面を持つ機能単位で分割したモジュール
* チャット、プロフィール、設定など
* 他のFeatureモジュールに依存してはいけない
* Libraryモジュールに依存してもよい

Libraryモジュールは次のような性質を持っています。

* 複数のFeatureモジュールで共有される機能を持つモジュール
* カスタムView、アバター、ロギングなど
* Featureモジュールに依存してはいけない
* 他のLibraryに依存してもよい

Featureモジュールは機能による垂直分割で、Libraryモジュールはレイヤによる水平分割のイメージです。例えば、Featureモジュールは個々にMVVMのアーキテクチャを持っていますが、その中の共通処理等はLibraryモジュールに実装をまかせるような感じになっています。

ライブラリ

通信
HTTP APIでRetrofit + OkHttpを使う他、WebSocket周りでOkHttpを使用しています。JSONパーサーはMoshiです。Moshiはリフレクションとコード生成を併用して使っています。ログ出力にはLoggerを使っていますが、ここ数年メンテされていないようで、Timberに移行しそうな気配です。

UI
MaterialDesignの恩恵にあやかりつつ、ConstraintLayoutで組んでViewBinding/DataBindingして、画像はGlideで読み込んで、のよくある感じだと思います。最近はLottieやMotionLayoutでアニメーションを加えるような部分も出てきています。ダークモードやジェスチャーナビゲーションはかなり早いタイミングで対応したものの、当然Unityにはない概念なので、それを踏まえて完璧にサポートできているか、と言われると怪しい面もあります。Jetpack Composeはようやくdevを抜けたのでタイミングを見計らって導入したいところです。

Jetpack系

* Navigation
* Paging
* Room

NavigationはREALITYより後に登場したという事情もあって、部分的に導入しています。別件でSingle activity化を推し進めているというのもあり、将来的にはNavigationに統一したいと考えています。

Pagingはv2を使っています。Paging2は我々の用途にはやや合っていないところがあり、ハックっぽいコードが多く、苦労することも多いのでタイミングを見計らってv3に移行したいところです。

Roomは主にキャッシュ用途で使用しています。コルーチン/Flow等にも対応していて助かっています。

その他

* ExoPlayer
* Koin
* Flipper
* Firebase

ExoPlayerは一部のライブ視聴で使用しています。

DIはDaggerではなく、Koinです。
当時チーム内にDaggerの知見を持った人がいなかったのと、Daggerほど複雑なものを必要としていなかったのが大きいです。最近ではHiltの存在もあり、移行の機運はやや高まっていますが、頑張ってやる必要性をそこまで感じていないのもまた事実です。

Flipperはデバッグツールです。最近はAndroidStudioのデバッグ機能が充実してきているので、そちらでも良い気がします。

FirebaseはFeature flagの実装にRemote Configを使いつつ、CrashlyticsやAnalyticsを活用しています。あとはフェイストラッキングでML Kitを活用しています。

CI/CD

Jenkinsを使っています。これはAndroidの都合というよりも、iOSビルドとUnityビルドの制約に依存するところが大きいです。Androidビルドに限って言えば、Unityに依存した処理を除けば、通常のAndroidアプリと何ら変わらないはずで、Jenkinsから他のCI/CDサービスに移行できないか検討しているところです。

まとめ

REALITY Androidで使っているものをざっと列挙してみました。Unityという異様な存在がありつつも、Androidアプリとしてはわりかし新しいものを適宜取り込みつつ開発できているのでは?と思いたい気持ちです。一方で新しいものを入れればいいのか、という話もあり、それによってアプリの品質や開発効率が向上しないのであれば自己満足にしかなりません。最近はそういった指標の計測や評価を頑張っていたりするんですが、これはいつか別の記事で語られると思います。おそらく。

そしてまあ是非はありつつも、新しいもの入れたりで技術的なところの好奇心を満たすのが楽しいのは間違いなくて(個人差はあるかもしれない)、REALITYではそういったAndroidが好きなエンジニアを募集しています。よろしくお願いします。