entry-header-eye-catch.html
entry-title-container.html

entry-header-author-info.html
Article by

build.gradle.ktsのandroidブロックをbuildSrcで共通化させてみる

こんにちは、18新卒エンジニアのまーくん(@m4kvn)です。講談社と共同で開発しているパルシィというアプリのAndroid版を担当しています。エンジニアの採用にも携わっています!

パルシィのAndroidアプリではビルドスクリプトを全てKotlin Gradle DSLで記述しています。そこで、アプリのマルチモジュール化を考えるときにAndroid Libraryのandroidブロックで共通する部分を切り出したい モチベーションが発生しました。そこで 「これは全部Kotlinで記述でき共通化もさせられるんじゃね 🤔」 と思い挑戦した過程と結果を共有します。

Gradle Scriptではどうするか

まず、マルチモジュールではどのようにandroidブロックを切り出し共通化させているのかGradle Scriptで記述する方法から見てみます。Gradle Scriptで記述する場合は androidブロックの記述を切りだしたファイルを用意してあげれば良いので以下のようなファイルを作ってあげます。

このファイル を各モジュールから読み込んであげれば良いです。

Kotlin Gradle DSLではどうするか

Gradle Scriptで記述された android-common.gradle をそのまま使い回す方法があります。使いたいモジュールから以下のように読み込んであげましょう。

この方法ならば大きく変更する必要がないため、Gradle ScriptからKotlin Gradle DSLに移行する場合は、このように徐々に切り出していく方法もありそうです。ただし android-common.gralde.kts のように Kotlin Gradle DSLで記述されていた場合は上手く動きません。こちらは issue としても上がっています ⇛ Using apply(from...) partial files android #1287

パルシィでは全てのビルドファイルをKotlinで記述していて今更Gradle Scriptに戻すのもなぁという感じなので、なんとかKotlinで記述できないか模索してみます。

buildSrcでandroidブロックを記述してみる

Kotlin Gradle DSLを使った場合、buildSrc内のKotlinで記述されたものを使い回すことができます。各モジュールの依存関係なんかは、この方法を使って共通化されます。この方法が現状の問題の解決方法と近いため、こちらの方法で攻めてみます。とりあえずbuildSrc内でProjectにメソッドを生やし、androidブロックが使えるか確かめてみます。

まぁ当然ながらエラーでした。これはbuildSrcのプロジェクトでKotlin Gradle DSLを依存関係として持っていないので当然です。では、Kotlin Gradle DSLのソースコードを見に行って同じような実装をしてみます。

ふむふむ 🤔 、 BaseAppModuleExtensionがどうやらandroidブロックの正体っぽいです。では、このBaseAppModuleExtensionがないとandroidブロックが使えないということですね。このクラスは com.android.build.gradle に属しているのでビルドツールを依存関係に追加してあげれば良さそうです。

このあとGradle Syncして以下のようなメソッドを定義しました。

このメソッドを実際にAndroid Applicationモジュールから読み込んでみます。

うごくじゃん。これを使えば各モジュールでandroidブロックの共通化ができるじゃん。

と思ってた時期が僕にもありました。

Android Libraryで使ってみる

さっきはAndroid Applicationモジュールで使ってみて上手く動くことが確認できました。では次に、Android Libraryを作って上手く動くが確認してみます。以下のようにAndroid Libraryモジュール側からbuildSrcのコードを利用してみます。

すると以下のようなエラーが表示されました。

BaseAppModuleExtensionにキャストできないのはなるほどって感じです。com.android.application はBaseAppModuleExtensionsですが com.android.library のときはLibraryExtensionになります。つまりLibraryExtension用のメソッドも生やしてあげる必要があるのですがBaseAppModuleExtensionsとLibraryExtensionsの親クラスを見てみるとBaseExtensionsが共通しています。ですのでこいつを使うようにしてあげれば良さそうです。最終的には以下のようなメソッドを定義しました。

こちらのメソッドをAndroid ApplicationとAndroid Libraryでそれぞれ使ってみます。

ええやん。これでandroidブロックの切り出しと共通化が上手くいきました。

おまけ

androidブロックと同じ要領で依存関係も全てbuildSrcで記述できます。

これをそれぞれ以下のように使用します。

20191219012842
makun
2018年4月新卒入社。講談社と共同で開発しているパルシィというアプリのAndroid版を担当する。エンジニア採用や育成も行う。