InstantApps対応をするにはmulti module化は必須である。
実はprotobufのpluginも最近InstantAppsに対応したばっかりなので、まだまだハマリポイントは多い。
1moduleなら問題はないのだが、複数のfeature moduleでprotobufを使うと
generatedのdirectoryが解決出来なくなってしまうので、gradle側でdirectoryを追加してあげる必要がある。
しかし面倒なことにgeneratedのdirectoryは、flavorとbuild typeによってpathが異なる。
1つのflavorでもdebug buildとrelease buildがあるだろうから対応は必須となる。
普通なら以下のようにapplicationVariantsを使って指定したいが
applicationVariants.all { variant ->
}
このコードはfeature moduleからは使えない。
そこで、各flavorとbuild type一覧を取得して指定してみる
sourceSets {
def buildTypes = android.buildTypes.collect { type -> type.name }
def productFlavors = android.productFlavors.collect { flavor -> flavor.name }
productFlavors.each { productFlavorName ->
buildTypes.each { buildTypeName ->
// Create variant and target names
def targetName = "${productFlavorName}${buildTypeName.capitalize()}"
main.java.srcDirs += "build/generated/source/proto/${targetName}/grpc"
main.java.srcDirs += "build/generated/source/proto/${targetName}/javalite"
}
}
}
しかし、これも動作はしない。
なぜなら、srcDirに他のbuildで作成したファイルも参照してしまうので、同じクラスが重複してしまう。
毎回cleanすれば良いのだが、そんな面倒な事をしたくはない…
ということで、泥臭くtaskから現在のflavorとbuild typeを取得してやることにした。
以下のメソッドを作成
/**
* @return flavor + build type
* e.g. prdRelease, devDebug
*/
def getCurrentTaskName() {
String taskName = getGradle().getStartParameter().getTaskRequests().toString()
Pattern pattern
if (taskName.contains("assemble")) {
pattern = Pattern.compile("assemble(\\w+)")
} else if(taskName.contains("sideLoad")) {
pattern = Pattern.compile("sideLoad(\\w+)InstantApp")
} else if(taskName.contains("install")) {
pattern = Pattern.compile("install(\\w+)")
} else {
pattern = Pattern.compile("generate(\\w+)")
}
Matcher matcher = pattern.matcher(taskName)
if (matcher.find()) {
return matcher.group(1).uncapitalize()
} else {
return "" // Not found
}
}
gradleのtaskから正規表現でflavorとbuild typeを取ってきている。
sideLoad(\\w+)InstantApp
というtaskは普段は見慣れないとは思うが、
InstantAppsのinstallを行ってくれるtaskである。
例えば、flavorがDev
環境でbuild typeがDebug
の時の
Installedのアプリのtask名は assembleDevDebug
である。
InstantAppsのtask名は sideLoadDevDebugInstantApps
になる。
正規表現で取得した文字列は、そのままだとDevDebug
のようになってしまうので、uncapitalized()
で先頭を小文字にしている。
あとはsource setsにdirectoryを指定してあげれば良い
sourceSets {
def targetName = getCurrentTaskName()
main.java.srcDirs += "build/generated/source/proto/${targetName}/grpc"
main.java.srcDirs += "build/generated/source/proto/${targetName}/javalite"
}