Qiita Nightの資料になります。 ↑ 右下の拡大ボタンを押すと読みやすくなります。
https://increments.connpass.com/event/251564/
どうAndroidプロジェクトをセットアップするか?
takahiromという名前で活動しています。
Androidが好きです。
GDE for AndroidやDroidKaigi Co-organizerやCyberAgent Developers Expertなどの活動をしています。
初めてQiitaスライドを使いました。
初めてAndroidアプリを作りたいという方
Googleから公式のチュートリアルが提供されているので、最新のAndroidの開発について確認してみてください!一緒に開発していきましょう🙌
https://developer.android.com/courses/android-basics-compose/course
今日のテーマ: Androidのアプリを複数人で開発して運用していくときに、どうプロジェクトをセットアップするか。
- すべてのサイズのプロジェクトにマッチするセットアップはないと思っていますが、数人ぐらいの規模で考えています。
※ 自分だったらこれを選ぶというだけで、もちろん、この仕組み以外を使っても全然いいと思っています。
※ 何かあれば編集リクエストやコメントなどをください
GoogleからNow in AndroidというAndroid関連のニュースアプリが公開されていてかなりいいサンプルのアプリになっています。このアプリの考え方を取り入れています。
今回の紹介するテンプレートプロジェクト
セットアップした内容をGitHubにあげています。これはテンプレートとして使えます。このプロジェクトの中のコードを参照しながら説明していきます。
このサンプルではコードに関しては全然書いておらず、最低限になっていて、cloneして好きなようにコードを書き始められるようになっています。
ビルドシステム
ビルドシステムとしてはGradleを採用を採用します。Androidアプリのプロジェクトのデフォルトの構成なのでGradleを採用することに特に悩む必要はないのかなと思います。
使い方は基本的にAndroid Studioを使うとデフォルトで利用されます。
Bazel(ベイゼル)など別のビルドシステムで頑張ってみるのも楽しいかもしれません。
ビルドファイルの書き方
Gradle Kotlin DSL(build.gradle.kts) を採用します。Kotlinでビルド関連のコードが書けます。
- デフォルトのGroovyと比較してKotlinが静的型付けである
- Kotlinなので、Androidエンジニアであれば記述が楽です。
など
使い方は基本的にbuild.gradle
のビルドファイルの代わりにbuild.gradle.kts
でビルドファイルを書くだけです。
実際Kotlin DSLってどう?
デメリット
- ビルド速度
- 書き方がbuild.gradleと違うので管理が難しい
- Kotlin DSL特有の問題などがある場合があるなどが挙げられます。
Kotlin DSLじゃないのも個人的には好きなんですが、最近はKotlin DSLでもかなりサンプルも充実してきた(逆にKotlin DSLしかサンプルがない場合も増えてきた)ので今年はこちらで。
バージョン管理
Gradle Version Catalogでtomlによる管理を採用。
これを利用するとプロジェクト内で、モジュール間やビルドスクリプトでライブラリのバージョンの共有ができます。
使い方はgradle/libs.versions.tomlにtomlファイルを置いて、そこにバージョンを記述します。
libs.versions.tomlの例
https://github.com/takahirom/android-project-template-2022/blob/main/gradle/libs.versions.toml
Gradle Version Catalogってどう?1
こちらも採用に是非が分かれるかと思います。Gradle 7.4からPreview機能でもなくなり、Android Open Source ProjectのAndroidXでも採用されたり、Now in Androidでの採用されるなど、ここ一年でかなりメジャーな機能になっています。
Gradle Version Catalogってどう?2
ただ、例えばライブラリを新しく導入する場合には、以下のような文字列がREADMEなどで提供されているのでそれを入れる必要があるのですが、これをVersion Catalogの記法に変換するのがめんどくさいというデメリットがあります。
よくREADMEに書かれているbuild.gradleへの追加の記法
implementation 'androidx.core:core-ktx:1.7.0'
↓どうにかして以下に直したい。
Gradle Version Catalogの記述例
androidx-core-ktx = { module = "androidx.core:core-ktx", version.ref = "androidxCore" }
Gradle Version Catalogってどう?3
gradle-version-catalog-converterを作ったので簡単に変換できるので利用してみてください
自動バージョンアップ
RenovateがGradle Version Catalogの自動アップデートが使えるのでこちらを使います。
以下から設定すると簡単に利用できます。
Renovate設定の流れ
- 基本的な導入の流れはWeb上でGitHub Appを追加するボタンが出てくるので、それを押す
- 適応するプロジェクトが選べるので選ぶ
- Renovateが設定ファイルを追加するプルリクエストを投げるので、それをマージすることで利用開始することができます。
Renovateが作るPR
Gradleの依存関係の変更の検知
ライブラリを導入したりバージョンアップするときに、ライブラリが推移的にライブラリに依存を始めたり、破壊的変更のあるバージョンへのアップデートをしてしまう場合があります。これをプルリクエストで確認できるようにする方法を紹介します。このようなコメントをプルリクエストにさせることができます。
JakeWharton/dependency-tree-diff
だとdiffが長くなってしまって、分かりにくいという問題があったのでcareem/dependency-diff-tldr
を使っています。
CIサービス
自分が知る限り、特に新しいトレンドは見つけられていないです。自作も含め、好きなサービスで良いと思いますが、今回はGitHub Actionsを使っています。
GitHub Actionsはファイルを独立して設定できるので移植性が高い(コピペできる)のが個人的に好きなポイントです。またGitHubとの統合は強いなと思います。
ただ、CIを自作したりするともっと柔軟にグラフで確認したり、差分でなにかしたりなどがやりやすい場合があるかもです。
Android StudioのベースとなったIntelliJを作っているJetBrainsが提供しているTeamCityも気になるので、どなたか試して知見を共有してください。
CIで何を行うか
ビルド、テスト、リリース、ベンチマークなどを行うのが良いと思います。基本的にはGitHubを使っていれば、.github/workflows/xxx.yml
の設定ファイルを置くだけで利用することが出来ます。 Now in Androidで行っていたものがほとんどですがこちらで確認できます。
コードフォーマット
フォーマット定義に関してはAndroidのKotlin Style guideを基本的に利用します。これはこの定義によるメリデメというよりはフォーマットが決まっていることによって開発中に議論の手間が減るというメリットがあります。
コードフォーマットツール CIのセットアップ
KtLint + Spotless。
ローカルではIDE + KtLint + Spotlessを利用します。こちらも別のツールでも良いと思います。
./gradlew spotlessKotlinCheckでチェック
./gradlew spotlessKotlinApplyでコードフォーマットができます。
コードフォーマットツール IDEのセットアップ
- プロジェクト内に
.idea/codeStyles/Project.xml
.idea/codeStyles/codeStyleConfig.xml
をGitに追加(codeStyleConfig.xmlにProjectの設定使うよ。って書いておいて、Project.xmlの内容が使われるようになるイメージです。) - gradle.propertiesに
kotlin.code.style=official
を定義
導入PR
コードフォーマットツール補足 1
また、今回は新規プロジェクトなので、利用していませんが、途中から適応する場合に、プロジェクト全体をフォーマットしなくても例えばmainブランチの状態をベースラインとして、アップデートしていくことができます。
コードフォーマットツール補足 2
自動でフォーマットをかけてSuggested Changeさせることもできます。 (指摘内容が分かりやすい)
https://qiita.com/takahirom/items/2a3d2912e74107748765
また最近知ったのですが .git-blame-ignore-revs
でGitのコミットハッシュを指定すると、フォーマットのコミットをgit blameから除外できるのでおすすめです。
Gradleのモジュール分けについて
Gradleにはプロジェクトという概念があります。
root ← ルートプロジェクト
├── :app ← サブプロジェクト, モジュール
└── :library ← サブプロジェクト, モジュール
プロジェクトはネストすることができ、基本的には根本にあるルートプロジェクトとサブプロジェクトから構成されます。
サブプロジェクトを慣習的にモジュールと呼びます。
Gradleのモジュール分けについて
モジュールを分けるとさまざまなメリットがあります。
- 並列ビルドやキャッシュによるビルド速度の改善
- コードが分かれることによる並列作業
など
以下にかなりまとまっています。
https://github.com/android/nowinandroid/blob/main/docs/ModularizationLearningJourney.md#overview
どうモジュールを分けるか?
これに関してはさまざまな考え方があると思いますが、Now In Androidアプリでは大きく分けるとappとfeatureとcoreの3モジュールによる分け方を採用しています。 (テンプレートプロジェクトは好きにカスタマイズしてください)
このやり方のメリットはルールが分かりやすいことかもしれません。おそらくcoreはかなり増えていくことになると思います。
- app,feature,coreのモジュールがある
- app: MainActivityやApplicationクラスなど
- feature: 特定の機能など
- core: 共有される必要のあるライブラリモジュール
- app -> feature -> coreの依存方向になっている。
- featureはappモジュールが複数ある場合使い回される可能性がある
- featureがfaetureに依存してはいけない。その場合はcoreモジュールになる。
- coreがcoreに依存しても良い。
ビルドロジックの共通化方法
ビルドロジックの共通化方法
色んな方法を今まで書いてきました。。ベストプラクティスを見つけるのはむずかしい。。
ビルドロジックの共通化方法
今回はNow in Androidアプリでも採用された、build-logicによるビルドのロジックの共通化を採用しています。
メリデメに関しては https://qiita.com/takahirom/items/f42a22f309b547411975 参照してください。
ビルドロジックの共通化方法
ここで、少し実験的な部分として、featureモジュールとcoreモジュールにような関係をGradleのロジックの共通化にも導入しています。
- primitiveプラグイン:
- androidのライブラリプラグイン, Compose, Hilt, Spotlessといった単一の機能
- conventionプラグイン:
- primitiveプラグインを使ってfeatureなどの一般的なユースケースごとのプラグインを定義する
ビルドロジックの共通化方法 primitiveプラグイン
例えばこのようにcore-uiモジュールのbuild.gradle.ktsは以下のように設定します。
実際にはprimitive同士がComposeはAndroidのプラグインが適応されている必要があるなどの依存関係が必要になるため、その部分はパッケージのパスで表現しています。
plugins {
id("com.example.primitive.android")
id("com.example.primitive.android.compose")
id("com.example.primitive.android.hilt")
id("com.example.primitive.spotless")
}
ビルドロジックの共通化方法 conventionプラグイン 1
feature-home/build.gradle.ktsのようなモジュールでは以下のように設定します。ここではconvention
という名前を採用して、一気に適応できるようにします。
plugins {
id("com.example.convention.androidfeature")
}
ビルドロジックの共通化方法 conventionプラグイン 2
そしてそのプラグインの実装では以下のようにそれぞれのプラグインを適応しています。
class AndroidFeature : Plugin<Project> {
override fun apply(target: Project) {
with(target) {
with(pluginManager) {
apply("com.example.primitive.android")
apply("com.example.primitive.android.compose")
apply("com.example.primitive.android.hilt")
apply("com.example.primitive.spotless")
}
}
}
}
ビルドロジックの共通化方法
このようにprimitiveプラグインとconventionプラグインを利用することで構成可能にしつつ、管理できる方法を模索しています。
まとめ
最近の事情を踏まえたAndroidプロジェクトのセットアップをお話しました。
いろんなアプローチがあると思うので、こんなやり方あるよとか教えて下さい。
@ronnnnn 内容のレビューありがとうございました