How to create a basic Gradle plugin that interacts with Android New Build System.
Video in russian can be found here:
https://events.yandex.ru/lib/talks/2447/
3. About me
› 4+ years of Android development
› Mobile game-dev experience
› At Yandex:
1. Mobile Yandex.Metrica
2. Continuous Integration
4. Не удается отобразить рисунок. Возможно, рисунок
поврежден или недостаточно памяти для его открытия.
Перезагрузите компьютер, а затем снова откройте файл.
Если вместо рисунка все еще отображается красный
крестик, попробуйте удалить рисунок и вставить его
заново.
Why do I need this?
Intro
5. What can be done?
› Additional resources/code/manifest processing
› Output processing (apk, aar, jar)
› Other things
6. Story
Prod / test
servers
Flavors!
LoTgesst o /n /poroffd
AaUndnasil qyotunice/s bo uffi ld
numb...e r!
I want to
configure it
myself!
2 Flav3o rs!
FlaHvmorms?.. .
Manager Android dev
7. How should it work
Java code build.gradle Teamcity
Actual value:
"https://my.server.com"
CI server can do it
Our job
9. Use BuildConfig.java from Java
public class SomeJavaClass {
"
// ...
public static final String SERVER_URL = "https://my.server.com";
public static final String SERVER_URL = BuildConfig.URL;
// ...
}
12. Table of contents
› Gradle basics
› New Build System workflow
› Hello, Gradle plugin!
› Extending Android New Build System
13. Не удается отобразить рисунок. Возможно, рисунок
поврежден или недостаточно памяти для его открытия.
Перезагрузите компьютер, а затем снова откройте файл.
Если вместо рисунка все еще отображается красный
крестик, попробуйте удалить рисунок и вставить его
заново.
Tools we will use
Gradle basics
22. The New Build System
workflow
Не удается отобразить рисунок. Возможно, рисунок
поврежден или недостаточно памяти для его открытия.
Перезагрузите компьютер, а затем снова откройте файл.
Если вместо рисунка все еще отображается красный
крестик, попробуйте удалить рисунок и вставить его
заново.
What's so special?
23. What tasks will be launched?
build
check assemble
assembleDebug assembleRelease
Guaranteed assemble<VariantName>
25. Tasks we will need
assemble<VariantName>
....
generate<VariantName>BuildConfig
....
compile<VariantName>Java
....
26. Variant API
Source code
is your documentation!
› Access to most variant's tasks
› Variant output related properties
› Different for apps & libraries
27. Hello, Gradle plugin!
Не удается отобразить рисунок. Возможно, рисунок
поврежден или недостаточно памяти для его открытия.
Перезагрузите компьютер, а затем снова откройте файл.
Если вместо рисунка все еще отображается красный
крестик, попробуйте удалить рисунок и вставить его
заново.
The first steps
28. The very basic one
src/main/groovy/com/example/gradle/PlaceholderPlugin.gradle
public class PlaceholderPlugin implements Plugin<Project> {
@Override"
void apply(Project project) {
project.task('hello') << {"
println "Hello Gradle plugin!"
}
}
}
29. Bind plugin class to plugin name
src/main/resources/META-INF/gradle-plugins/placeholder.properties
implementation-class=com.example.gradle.PlaceholderPlugin
34. Extending
The New Build System
Не удается отобразить рисунок. Возможно, рисунок
поврежден или недостаточно памяти для его открытия.
Перезагрузите компьютер, а затем снова откройте файл.
Если вместо рисунка все еще отображается красный
крестик, попробуйте удалить рисунок и вставить его
заново.
Let's do it!
35. Check for New Build System
// PlaceholderPlugin.groovy
@Override"
void apply(Project project) {
if (project.hasProperty("android")) {
PlaceholderExtension extension = project.extensions.create("
"placeholder", PlaceholderExtension"
);
def android = project.android
// all code goes here
}
}"
36. Let the New Build System do its job
// PlaceholderPlugin.apply()
if (project.hasProperty("android")) {
PlaceholderExtension extension = project.extensions.create("
"placeholder", PlaceholderExtension"
);
def android = project.android
project.afterEvaluate {"
// at this point we have all
// tasks from New Build System
}
}
37. Process every variant
// PlaceholderPlugin.apply()
project.afterEvaluate {
if (android.hasProperty('applicationVariants')) {
android.applicationVariants.all { variant ->
addActions(project, variant, extension)
}
} else if (android.hasProperty('libraryVariants')) {
android.libraryVariants.all { variant ->
addActions(project, variant, extension)
}
}
}
41. Does it really work?
>> gradle assembleDebug
:app:preBuild
...
:app:generateDebugBuildConfig
...
:app:processDebugPlaceholders
I will replace debug!
:app:compileDebugJava
...
47. Does it work?
app/build/generated/source/buildConfig/debug/com/example/
sample/BuildConfig.java
public final class BuildConfig {"
// Fields from default config."
public static final String URL = "https://my.server.com";
}
48. Не удается отобразить рисунок. Возможно, рисунок
поврежден или недостаточно памяти для его открытия.
Перезагрузите компьютер, а затем снова откройте файл.
Если вместо рисунка все еще отображается красный
крестик, попробуйте удалить рисунок и вставить его
заново.
To summarize
49. Key steps
› Create Gradle plugin
› Inside afterEvaluate { }
› Process every variant
› Add action to generateBuildConfig
› Handle inputs / outputs
50. What's next?
› Default values support
› Errors handling
› Publish ( jcenter / mavenCentral / other )
51. Links
Gradle
http://www.gradle.org/
The New Build System
http://tools.android.com/tech-docs/new-build-system
http://tools.android.com/tech-docs/new-build-system/build-workflow
Github sample
https://github.com/roottony/android-placeholder-plugin
52. Thank you for your attention!
Anton Rutkevich
Senior software engineer
antonrut@yandex-team.ru
anton.rutkevich@gmail.com