Android Gradle Plugin3系におけるマルチモジュール時のconfigurationの解決について
こんにちは。釘宮です。
マルチモジュールなプロジェクトをやって行く上で、以前は下記のような記述をよく書いていました。
devCompile project(path: 'library', configuration: 'dev')
Android Gradle Plugin3系(gradle4系)から compile
(など)ではなく implementation
(など)を使っていきましょうともろもろ変わりました。
なので、単純に下記のように implementation
と書き直してみます。
devImplementation project(path: 'library', configuration: 'dev')
これでビルドをして見ると、がっつりエラーが出てきます。
解決方法などをまとめたので今回記事として見ました。
ここに書いていあることは 公式ページ に書いてあることの一部 + αでdす。
結論から言うと implementation project('library') で良い (条件付き)
app/build.gradle | library/build.gradle |
android { : flavorDimensions 'api' productFlavors { dev { dimension 'api' } stg { dimension 'api' } prod { dimension 'api' } } : } dependencies { : implementation project(":library") : } |
android { : flavorDimensions 'api' productFlavors { dev { dimension 'api' } stg { dimension 'api' } prod { dimension 'api' } } : } |
このようになっている場合、appではlibraryで同じ名前のflavorのものを選択してbuildされます。
いままでは
devCompile project(path: ':library', configuration: 'dev') stgCompile project(path: ':library', configuration: 'stg') prodCompile project(path: ':library', configuration: 'prod')
などと書いてましたが、下記一行で済むようになりました。便利ですね。
implementation project(":library")
ただこれに関しては app側にある api-dimension に所属する dev
, stg
, prod
をlibrary側も同じものを持っているという条件を満たしている時に限ります。
そのため、library側が余計に dev1
というflavorを持っていても使われないだけでビルドは問題なく通ります。
以下から簡略化のため、 api-dimensionに所属する dev
, stg
, prod
のflavorがある 状態を [api => (dev, stg, prod)]
と書くようにしますね。
例1. appでは[api => (dev, stg, qa, prod)]、libraryでは[ api => (dev, stg, prod)]となっている時
app側に qa
があるけど library側にそれがない場合です。
appの qa
時には library では stg
を選択したいとします。
こう言う時は matchingFallbacks
を使用します。
app/build.gradle | library/build.gradle |
android { : flavorDimensions 'api' productFlavors { dev { dimension 'api' } stg { dimension 'api' } qa { dimension 'api' matchingFallbacks = ["stg"] } prod { dimension 'api' } } : } dependencies { : implementation project(":library") : } |
android { : flavorDimensions 'api' productFlavors { dev { dimension 'api' } stg { dimension 'api' } prod { dimension 'api' } } : } |
依存先に対象flavorが見つからない場合に matchingFallbacks
によって優先順位を指定できます。
上記の例では stg
のみ指定しいます。 (なお、 flavor dimention が一致していないと、matchingFallbacks に指定しても動きません)。
加えてこのmatchingFallbacks
は下記のようにbuildTypeでも同様の使い方ができます。
app/build.gradle | library/build.gradle |
android { : buildTypes { debug { } stg { } qa { matchingFallbacks = ["stg"] } release { } } : } dependencies { : implementation project(":library") : } |
android { : buildTypes { debug { } stg { } release { } } : } |
例2. library側に知らないdimensionがある時
そもそもdimensionとは
あえて触れてこなかったんですが flavorDimensions 'api'
のところの話です。
Android Gradle Plugin3.0.0より前ではなかったものです。 いままでもありましたが、3系からは指定が必須になったようです。
いままでは productFlavors とはフラットなものでして、あるflavorと他のflavorを組み合わせるということはできませんでした。これを可能にするのが flavorDimension
です。
言葉だと難しいので実際に設定して見ましょう。
productFlavors { buildTypes { debug release } flavorDimensions 'api', 'persistence' dev { dimension 'api' } stg { dimension 'api' } prod { dimension 'api' } local { dimension 'persistence' } cloud { dimension 'persistence' } }
flavorDimension
を指定しない場合、 buildVariant
は (dev, stg, prod, local, cloud) × (debug, release) の 5×2 = 10通りのconfigurationがとなっていました。
これが、 現状は上記のようにdimensionを使い分けることで (dev, stg, prod) × (local, cloud) × (debug, release) の 3×2×2 = 12通りconfigurationが作られるようになったと言うことです。
何が便利かと言うと、観点ごとにコードを分けれることでしょうか。上記の場合だと api は (dev, stg, prod) のどの環境を使うか、永続化(persistence)は ローカルなのかクラウドなのかという例になっています。
ざっくりここまでがdimensionの説明です。
appは [api => (dev, stg, prod)]、 libraryが [api => (dev, stg, prod), persistence => (local, cloud)] の時
appの知らない persistence
dimension がlibraryにある場合を考えます。
appで、例えば stg
をbuildしたい時に、 library側では stg
と言っても stgLocal
と stgCloud
の組み合わせがあるのでどっちを使えば良いのかわからないと言う状況です。;
この場合は missingDimensionStrategy
を使用します
missingDimensionStrategy (dimension名) (flavor名), (flavor名),...
と言うふうに 知らないdimensionがきた時に、どのflavorを優先的に採用するかということを決めることができます。
missingDimensionStrategy 'persistence' 'local' 'cloud'
この場合は persistence
dimensionがきたら local
, cloud
の順で採用すると言うことになります。
これを踏まえると下記のようになりました。
app/build.gradle | library/build.gradle |
android { : defaultConfig { : missingDimensionStrategy 'persistence', 'local', 'cloud' : } flavorDimensions 'api' productFlavors { dev { dimension 'api' missingDimensionStrategy 'persistence', 'local' } stg { dimension 'api' missingDimensionStrategy 'persistence', 'cloud' } prod { dimension 'api' missingDimensionStrategy 'persistence', 'cloud' } } : } dependencies { : implementation project(":library") : } |
android { : flavorDimensions 'api', 'persistence' productFlavors { dev { dimension 'api' } stg { dimension 'api' } prod { dimension 'api' } local { dimension 'persistence' } cloud { dimension 'persistence' } } : } |
上記のように各Flavorごとに missingDimensionStrategy
を設定することができます。
まとめ
これからは configuration の解決は dependencies
のところではなく flavor名、 matchingFallbacks
や missingDimensionStrategy
で頑張りましょう。