Plugin for Plugin, или расширяем Android New Build System. Антон Руткевич

53

description

Plugin for Plugin, или расширяем Android New Build System

Transcript of Plugin for Plugin, или расширяем Android New Build System. Антон Руткевич

Page 1: Plugin for Plugin, или расширяем Android New Build System. Антон Руткевич
Page 2: Plugin for Plugin, или расширяем Android New Build System. Антон Руткевич

Plugin for plugin, or extending Android New Build System Anton Rutkevich

Page 3: Plugin for Plugin, или расширяем Android New Build System. Антон Руткевич

About me

›  4+ years of Android development

›  Mobile game-dev experience

›  At Yandex:

1.  Mobile Yandex.Metrica

2.  Continuous Integration

Page 4: Plugin for Plugin, или расширяем Android New Build System. Антон Руткевич

The image cannot be displayed. Your computer may not have enough memory to open the image, or the image may have been corrupted. Restart your computer, and then open the file again. If the red x still appears, you may have to delete the image and then insert it again.

Intro

Why do I need this?

Page 5: Plugin for Plugin, или расширяем Android New Build System. Антон Руткевич

What can be done?

›  Additional resources/code/manifest processing

›  Output processing (apk, aar, jar)

›  Other things

Page 6: Plugin for Plugin, или расширяем Android New Build System. Антон Руткевич

Flavors 2 Flavors!

Story

Prod / test servers Logs on/off Test / prod analytics Ads on/off Unique build number! ...

I want to configure it myself!

3 Flavors? Hmm…

Page 7: Plugin for Plugin, или расширяем Android New Build System. Антон Руткевич

Story Prod / test

servers Flavors!

Logs on/off Test / prod analytics Ads on/off Unique build

number! ...

I want to configure it

myself!

2 Flavors! 3 Flavors? Hmm...

Android dev Manager

Page 8: Plugin for Plugin, или расширяем Android New Build System. Антон Руткевич

How should it work

Java code build.gradle Teamcity

Actual value: "https://my.server.com"

CI server can do it

Our job

Page 9: Plugin for Plugin, или расширяем Android New Build System. Антон Руткевич

Insert CI value into BuildConfig.java

// app/build.gradle apply plugin: 'com.android.application' android { � defaultConfig { buildConfigField "String", "URL", "\"${teamcity['server-url']}\"" buildConfigField "String", "URL", "\"#server-url\"" } �} project.teamcity = [

"server-url" : "https://my.server.com" // ... �]

buildConfigField "String", "URL", "\"${teamcity['server-url']}\"".

Page 10: Plugin for Plugin, или расширяем Android New Build System. Антон Руткевич

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; // ... }

public static final String SERVER_URL = "https://my.server.com";

Page 11: Plugin for Plugin, или расширяем Android New Build System. Антон Руткевич

BuildConfig placeholder plugin

›  Replaces placeholder values with values from some map

›  Map can come from anywhere

Page 12: Plugin for Plugin, или расширяем Android New Build System. Антон Руткевич

Goal

// app/build.gradle apply plugin: 'com.android.application' apply plugin: 'placeholder' �placeholder { � replacements = project.teamcity } android { � defaultConfig { � buildConfigField "String", "URL", "\"#server-url\"" � } �}

Page 13: Plugin for Plugin, или расширяем Android New Build System. Антон Руткевич

Table of contents

›  Gradle basics

›  New Build System workflow

›  Hello, Gradle plugin!

›  Extending Android New Build System

Page 14: Plugin for Plugin, или расширяем Android New Build System. Антон Руткевич

The image cannot be displayed. Your computer may not have enough memory to open the image, or the image may have been corrupted. Restart your computer, and then open the file again. If the red x still appears, you may have to delete the image and then insert it again.

Gradle basics

Tools we will use

Page 15: Plugin for Plugin, или расширяем Android New Build System. Антон Руткевич

Plugins everywhere

NBS

Page 16: Plugin for Plugin, или расширяем Android New Build System. Антон Руткевич

Tasks

›  Can be configured with { }

›  Consist of actions

›  Can depend on other tasks

›  Can have inputs / outputs

Page 17: Plugin for Plugin, или расширяем Android New Build System. Антон Руткевич

Task consists of actions

Action Action

Action Action

doFirst() doLast(), or <<

Task

Page 18: Plugin for Plugin, или расширяем Android New Build System. Антон Руткевич

Tasks execution order

Task 2

Task 3

Task 4

Execution order

dependsOn

Task 1

Task 2 Task 3 Task 4 Task 1

dependsOn

dependsOn

Page 19: Plugin for Plugin, или расширяем Android New Build System. Антон Руткевич

Outputs

Task inputs / outputs

Task Inputs

Inputs & outputs did not change =>

UP-TO-DATE

Page 20: Plugin for Plugin, или расширяем Android New Build System. Антон Руткевич

Task example

task myTask { ext.myMessage = "hello" } myTask << { println myMessage } task otherTask(dependsOn: myTask)

Page 21: Plugin for Plugin, или расширяем Android New Build System. Антон Руткевич

Task example output

>> gradle otherTask :app:myTask hello :app:otherTask

Page 22: Plugin for Plugin, или расширяем Android New Build System. Антон Руткевич

Build lifecycle

Initialization Configuration Execution

settings.gradle

Projects creation Projects configuration Tasks creation Tasks configuration project.afterEvaluate { }

Task graph execution

Task graph

build.gradle

Build initialization

Page 23: Plugin for Plugin, или расширяем Android New Build System. Антон Руткевич

The image cannot be displayed. Your computer may not have enough memory to open the image, or the image may have been corrupted. Restart your computer, and then open the file again. If the red x still appears, you may have to delete the image and then insert it again.

The New Build System workflow

What's so special?

Page 24: Plugin for Plugin, или расширяем Android New Build System. Антон Руткевич

What tasks will be launched?

build

check assemble

assembleDebug assembleRelease

assemble<VariantName> Guaranteed

Page 25: Plugin for Plugin, или расширяем Android New Build System. Антон Руткевич

Android project build overview

Page 26: Plugin for Plugin, или расширяем Android New Build System. Антон Руткевич

Tasks we will need

assemble<VariantName>

generate<VariantName>BuildConfig

compile<VariantName>Java

....

....

....

Page 27: Plugin for Plugin, или расширяем Android New Build System. Антон Руткевич

Variant API

Source code is your documentation!

›  Access to most variant's tasks

›  Variant output related properties

›  Different for apps & libraries

Page 28: Plugin for Plugin, или расширяем Android New Build System. Антон Руткевич

The image cannot be displayed. Your computer may not have enough memory to open the image, or the image may have been corrupted. Restart your computer, and then open the file again. If the red x still appears, you may have to delete the image and then insert it again.

Hello, Gradle plugin!

The first steps

Page 29: Plugin for Plugin, или расширяем Android New Build System. Антон Руткевич

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!" } } }

Page 30: Plugin for Plugin, или расширяем Android New Build System. Антон Руткевич

Bind plugin class to plugin name

src/main/resources/META-INF/gradle-plugins/placeholder.properties

implementation-class=com.example.gradle.PlaceholderPlugin

Page 31: Plugin for Plugin, или расширяем Android New Build System. Антон Руткевич

Extension

Extension

Page 32: Plugin for Plugin, или расширяем Android New Build System. Антон Руткевич

Add extension

src/main/groovy/com/example/gradle/PlaceholderExtension.gradle

class PlaceholderExtension { � def replacements = [:] } �

Page 33: Plugin for Plugin, или расширяем Android New Build System. Антон Руткевич

Add extension

@Override �void apply(Project project) { � project.task('hello') << { println "Hello Gradle plugin!" println "Hi, ${project.placeholder.replacements}" } } �

PlaceholderExtension extension = project.extensions.create( � "placeholder", PlaceholderExtension�);

println "Hello Gradle plugin!"

Page 34: Plugin for Plugin, или расширяем Android New Build System. Антон Руткевич

Use extension

// app/build.gradle apply plugin: 'placeholder' ��placeholder { � replacements = ["server-url" : "https://my.server.com"] } �--------------------------------------------- >> gradle hello :app:hello�Hi, [server-url:https://my.server.com]

Page 35: Plugin for Plugin, или расширяем Android New Build System. Антон Руткевич

The image cannot be displayed. Your computer may not have enough memory to open the image, or the image may have been corrupted. Restart your computer, and then open the file again. If the red x still appears, you may have to delete the image and then insert it again.

Extending The New Build System

Let's do it!

Page 36: Plugin for Plugin, или расширяем Android New Build System. Антон Руткевич

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 } } �

Page 37: Plugin for Plugin, или расширяем Android New Build System. Антон Руткевич

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 } }

Page 38: Plugin for Plugin, или расширяем Android New Build System. Антон Руткевич

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) } } }

Page 39: Plugin for Plugin, или расширяем Android New Build System. Антон Руткевич

Add task

// PlaceholderPlugin.groovy def addActions(Project project, variant, PlaceholderExtension extension) { Task processPlaceholders = project.task( "process${variant.name.capitalize()}Placeholders" ) processPlaceholders << { println "I will replace ${variant.name}!" } }

Page 40: Plugin for Plugin, или расширяем Android New Build System. Антон Руткевич

Insert task into build process assemble<VariantName>

generate<VariantName>BuildConfig

compile<VariantName>Java

....

....

....

process<VariantName>Placeholders

Page 41: Plugin for Plugin, или расширяем Android New Build System. Антон Руткевич

Insert task into build process

// PlaceholderPlugin.groovy def addActions(Project project, variant, PlaceholderExtension extension) { Task processPlaceholders = ... ... variant.javaCompile.dependsOn processPlaceholders� processPlaceholders.dependsOn variant.generateBuildConfig }

Page 42: Plugin for Plugin, или расширяем Android New Build System. Антон Руткевич

Does it really work?

>> gradle assembleDebug :app:preBuild ... :app:generateDebugBuildConfig ... :app:processDebugPlaceholders I will replace debug! :app:compileDebugJava ...

Page 43: Plugin for Plugin, или расширяем Android New Build System. Антон Руткевич

Actual work. Perform replacements

// PlaceholderPlugin.addActions() processPlaceholders << { def buildConfigFile = getBuildConfig(variant) � extension.replacements.each { replacement -> � project.ant.replace( � file: buildConfigFile, � token: "#${replacement.key}", value: replacement.value � ) � } }

Page 44: Plugin for Plugin, или расширяем Android New Build System. Антон Руткевич

Handling inputs / outputs

process Placeholders

BuildConfig.java BuildConfig.java

replacements

generate BuildConfig

...

replacements << Action

BuildConfig.java

Page 45: Plugin for Plugin, или расширяем Android New Build System. Антон Руткевич

Replace task with 'doLast'

// PlaceholderPlugin.addActions() processPlaceholders << { variant.generateBuildConfig << { def buildConfigFile = ... extension.replacements.each { ... } } variant.generateBuildConfig.inputs.property( "replacements", extension.replacements )

processPlaceholders << {

Page 46: Plugin for Plugin, или расширяем Android New Build System. Антон Руткевич

│ We've done it!

Page 47: Plugin for Plugin, или расширяем Android New Build System. Антон Руткевич

Remember how to use it?

// app/build.gradle apply plugin: 'com.android.application' �apply plugin: 'placeholder' ��placeholder { � replacements = project.teamcity } ��android { � defaultConfig { � buildConfigField "String", "URL", "\"#server-url\"" � } �}

Page 48: Plugin for Plugin, или расширяем Android New Build System. Антон Руткевич

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"; }

Page 49: Plugin for Plugin, или расширяем Android New Build System. Антон Руткевич

The image cannot be displayed. Your computer may not have enough memory to open the image, or the image may have been corrupted. Restart your computer, and then open the file again. If the red x still appears, you may have to delete the image and then insert it again.

To summarize

Page 50: Plugin for Plugin, или расширяем Android New Build System. Антон Руткевич

Key steps

›  Create Gradle plugin

›  Inside afterEvaluate { }

›  Process every variant

›  Add action to generateBuildConfig

›  Handle inputs / outputs

Page 51: Plugin for Plugin, или расширяем Android New Build System. Антон Руткевич

What's next?

›  Default values support

›  Errors handling

›  Publish ( jcenter / mavenCentral / other )

Page 52: Plugin for Plugin, или расширяем Android New Build System. Антон Руткевич

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

Page 53: Plugin for Plugin, или расширяем Android New Build System. Антон Руткевич

Thank you for your attention!

[email protected]

Anton Rutkevich

Senior software engineer

[email protected]