Top Banner
52

Plugin for plugin, or extending android new build system

Jul 12, 2015

Download

Engineering

Anton Rutkevich
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
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]