问题
I'm trying to build a project that uses both Google protocol buffers and Kotlin using Gradle. I want the proto files to compile into Java source, which is then called from my Kotlin code.
My source files are arranged like this:
src/main/proto/*.proto
src/main/kotlin/*.kt
src/test/kotlin/*.kt
Here's my build.gradle
file:
version '1.0-SNAPSHOT'
apply plugin: 'kotlin'
apply plugin: 'java'
apply plugin: 'com.google.protobuf'
repositories {
mavenCentral()
maven { url "http://dl.bintray.com/kotlin/kotlin-eap-1.1" }
}
buildscript {
ext.kotlin_version = '1.1-M02'
repositories {
mavenCentral()
maven { url "http://dl.bintray.com/kotlin/kotlin-eap-1.1" }
}
dependencies {
classpath 'com.google.protobuf:protobuf-gradle-plugin:0.8.0'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
protobuf {
protoc {
artifact = 'com.google.protobuf:protoc:3.0.0'
}
}
dependencies {
compile 'com.google.protobuf:protobuf-java:3.0.0'
compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
testCompile 'junit:junit:4.12'
}
When I run ./gradlew assemble
I get a bunch of "Unresolved reference" errors during :compileKotlin
. Afterwards I can see that there are no Java source files generated, so it appears that the proto compiler is not being invoked at all.
If I remove the apply plugin: 'kotlin'
line, then ./gradlew assemble
successfully generates the Java source, but of course my Kotlin source is never compiled.
How do I fix my build.gradle
so that I can call my protobuf code from Kotlin?
回答1:
I was able to get this to work by adding two lines to my build.gradle.
The first line adds the directory in which the proto compiler generates Java code to the directories the :compileKotlin
looks for Java source:
sourceSets.main.java.srcDirs += 'build/generated/source/proto/main/java'
The second ensures that the Java code is (re)generated before invoking :compileKotlin
:
compileKotlin.dependsOn ':generateProto'
回答2:
For Kotlin and Android:
android {
sourceSets {
debug.java.srcDirs += 'build/generated/source/proto/debug/java'
release.java.srcDirs += 'build/generated/source/proto/release/java'
}
}
An additional source directory has to be added for every build type. In this sample there are two build types: debug
and release
.
If you're using grpc, another line has to be added per build type:
android {
sourceSets {
debug.java.srcDirs += 'build/generated/source/proto/debug/java'
debug.java.srcDirs += 'build/generated/source/proto/debug/grpc'
release.java.srcDirs += 'build/generated/source/proto/release/java'
release.java.srcDirs += 'build/generated/source/proto/release/grpc'
}
}
At least with Kotlin 1.0.6, protobuf-gradle-plugin 0.8.0, protobuf 3.2.x and grpc 1.x it's not required to fiddle with the task order.
回答3:
if you are working with multiple build types and flavors in android and with protobuf-lite use below with kotlin.
for example I have debug
and release
builds with demo
and prod
flavors it will create demoDebug
, demoRelease
and prodDebug
and prodRelease
variants.
then use
`
android{
sourceSets {
debug.java.srcDirs += 'build/generated/source/proto/demoDebug/javalite'
debug.java.srcDirs += 'build/generated/source/proto/prodDebug/javalite'
release.java.srcDirs += 'build/generated/source/proto/demoRelease/javalite'
release.java.srcDirs += 'build/generated/source/proto/prodRelease/javalite'
}
}
`
tie the different compileKotlin with generateProto
tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).all {
if (getName() == 'compileDemoDebugKotlin')
dependsOn(':app:generateDemoDebugProto')
if (getName() == 'compileDemoReleaseKotlin')
dependsOn(':app:generateDemoReleaseProto')
if (getName() == 'compileProdDebugKotlin')
dependsOn(':app:generateProdDebugProto')
if (getName() == 'compileProdReleaseKotlin')
dependsOn(':app:generateProdReleaseProto')
}
来源:https://stackoverflow.com/questions/40499452/how-to-build-google-protocol-buffers-and-kotlin-using-gradle