plugin for plugin, or extending android new build system

52

Upload: anton-rutkevich

Post on 12-Jul-2015

369 views

Category:

Engineering


3 download

TRANSCRIPT

Page 1: Plugin for plugin, or extending android new build system
Page 2: Plugin for plugin, or extending android new build system

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

Page 3: Plugin for plugin, or extending 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, or extending android new build system

Не удается отобразить рисунок. Возможно, рисунок поврежден или недостаточно памяти для его открытия. Перезагрузите компьютер, а затем снова откройте файл. Если вместо рисунка все еще отображается красный крестик, попробуйте удалить рисунок и вставить его заново.

Intro

Why do I need this?

Page 5: Plugin for plugin, or extending 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, or extending 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 7: Plugin for plugin, or extending 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 8: Plugin for plugin, or extending 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 9: Plugin for plugin, or extending 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 10: Plugin for plugin, or extending android new build system

BuildConfig placeholder plugin

›  Replaces placeholder values with values from some map

›  Map can come from anywhere

Page 11: Plugin for plugin, or extending 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 12: Plugin for plugin, or extending android new build system

Table of contents

›  Gradle basics

›  New Build System workflow

›  Hello, Gradle plugin!

›  Extending Android New Build System

Page 13: Plugin for plugin, or extending android new build system

Не удается отобразить рисунок. Возможно, рисунок поврежден или недостаточно памяти для его открытия. Перезагрузите компьютер, а затем снова откройте файл. Если вместо рисунка все еще отображается красный крестик, попробуйте удалить рисунок и вставить его заново.

Gradle basics

Tools we will use

Page 14: Plugin for plugin, or extending android new build system

Plugins everywhere

NBS

Page 15: Plugin for plugin, or extending android new build system

Tasks

›  Can be configured with { }

›  Consist of actions

›  Can depend on other tasks

›  Can have inputs / outputs

Page 16: Plugin for plugin, or extending android new build system

Task consists of actions

Action Action

Action Action

doFirst() doLast(), or <<

Task

Page 17: Plugin for plugin, or extending 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 18: Plugin for plugin, or extending android new build system

Outputs

Task inputs / outputs

Task Inputs

Inputs & outputs did not change =>

UP-TO-DATE

Page 19: Plugin for plugin, or extending android new build system

Task example

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

Page 20: Plugin for plugin, or extending android new build system

Task example output

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

Page 21: Plugin for plugin, or extending 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 22: Plugin for plugin, or extending android new build system

Не удается отобразить рисунок. Возможно, рисунок поврежден или недостаточно памяти для его открытия. Перезагрузите компьютер, а затем снова откройте файл. Если вместо рисунка все еще отображается красный крестик, попробуйте удалить рисунок и вставить его заново.

The New Build System workflow

What's so special?

Page 23: Plugin for plugin, or extending android new build system

What tasks will be launched?

build

check assemble

assembleDebug assembleRelease

assemble<VariantName> Guaranteed

Page 24: Plugin for plugin, or extending android new build system

Android project build overview

Page 25: Plugin for plugin, or extending android new build system

Tasks we will need

assemble<VariantName>

generate<VariantName>BuildConfig

compile<VariantName>Java

....

....

....

Page 26: Plugin for plugin, or extending 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 27: Plugin for plugin, or extending android new build system

Не удается отобразить рисунок. Возможно, рисунок поврежден или недостаточно памяти для его открытия. Перезагрузите компьютер, а затем снова откройте файл. Если вместо рисунка все еще отображается красный крестик, попробуйте удалить рисунок и вставить его заново.

Hello, Gradle plugin!

The first steps

Page 28: Plugin for plugin, or extending 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 29: Plugin for plugin, or extending 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 30: Plugin for plugin, or extending android new build system

Extension

Extension

Page 31: Plugin for plugin, or extending android new build system

Add extension

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

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

Page 32: Plugin for plugin, or extending 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 33: Plugin for plugin, or extending 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 34: Plugin for plugin, or extending android new build system

Не удается отобразить рисунок. Возможно, рисунок поврежден или недостаточно памяти для его открытия. Перезагрузите компьютер, а затем снова откройте файл. Если вместо рисунка все еще отображается красный крестик, попробуйте удалить рисунок и вставить его заново.

Extending The New Build System

Let's do it!

Page 35: Plugin for plugin, or extending 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 36: Plugin for plugin, or extending 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 37: Plugin for plugin, or extending 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 38: Plugin for plugin, or extending 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 39: Plugin for plugin, or extending android new build system

Insert task into build process assemble<VariantName>

generate<VariantName>BuildConfig

compile<VariantName>Java

....

....

....

process<VariantName>Placeholders

Page 40: Plugin for plugin, or extending 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 41: Plugin for plugin, or extending android new build system

Does it really work?

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

Page 42: Plugin for plugin, or extending 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 43: Plugin for plugin, or extending android new build system

Handling inputs / outputs

process Placeholders

BuildConfig.java BuildConfig.java

replacements

generate BuildConfig

...

replacements << Action

BuildConfig.java

Page 44: Plugin for plugin, or extending 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 45: Plugin for plugin, or extending android new build system

│ We've done it!

Page 46: Plugin for plugin, or extending 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 47: Plugin for plugin, or extending 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 48: Plugin for plugin, or extending android new build system

Не удается отобразить рисунок. Возможно, рисунок поврежден или недостаточно памяти для его открытия. Перезагрузите компьютер, а затем снова откройте файл. Если вместо рисунка все еще отображается красный крестик, попробуйте удалить рисунок и вставить его заново.

To summarize

Page 49: Plugin for plugin, or extending android new build system

Key steps

›  Create Gradle plugin

›  Inside afterEvaluate { }

›  Process every variant

›  Add action to generateBuildConfig

›  Handle inputs / outputs

Page 50: Plugin for plugin, or extending android new build system

What's next?

›  Default values support

›  Errors handling

›  Publish ( jcenter / mavenCentral / other )

Page 51: Plugin for plugin, or extending 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 52: Plugin for plugin, or extending android new build system

Thank you for your attention!

[email protected]

Anton Rutkevich

Senior software engineer

[email protected]