My name is Xavier Ducrohet.
I'm the lead for the Android SDK developer tools.
And I'm the main contributor to the new build
system for the SDK.
So why a new build system?
Well, if you look at the current situation, on one
hand, we have some end scripts that are somewhat
customizable, although we have no public API for it, and it's
likely to break whenever we update the SDK.
On the other hand, we have ADT custom builders, very rigid,
but at least it works in the IDE.
And then we have [INAUDIBLE]
that has its own builder.
It's a bit more flexible, but it doesn't do many fast
merging, some issues.
So we want to fix that.
We wanted to create a single build system that was very
flexible so that it adapts to all of your
needs, within reasons.
And we wanted that build system to work whether you're
building from your continuous integration server
or within the IDE.
If your customization doesn't work in your IDE, then it just
doesn't work.
It breaks your workflow.
We wanted to add some features, like dependency
management, the ability to deploy and run tests, but also
Android-specific features that developers have asked us.
We didn't want to start from scratch.
So we looked around.
There's a lot of build systems out there.
They have plug-in ecosystem, support in Jenkins, TeamCity,
and we wanted to leverage all of that.
So we looked around, and we settled on Gradle.
So why Gradle?
Well, as a user, it's very powerful,
great declarative syntax.
But you can customize to your need, and it has a great
tooling API to do IDE integration.
From our point of view, when we develop the plugin, we can
create a new domain-specific language to really make the
configuration of the build system
very specific to Android.
We can expose great APIs for you to
extend the build system.
And the IDE integration can be customized so that the IDE
really knows not just about, hey, just some sort of build
system, but it's really an Android Build System.
It's also developed by a company called Gradleware who
designed open source.
It's Apache, so that's great for us.
And we've worked together to make sure that the build
system Gradle itself is adding features, specifically, that
we need so that we can give the best possible experience
to you developers.
So I figure that a lot of you probably don't know Gradle, or
maybe just tried it a little bit.
So I wanted to start with some basics and go through some
simple projects.
So if you look at a very simple Java project, first the
configuration is in a file called build.gradle that's
located at the root of your project, where you would find
your build.xml, or pom.xml if you build
it with Ant or Maven.
So with a simple line, what you can do is build your main
code and generate the JAR file, build your test code,
run your test, and get to output some XML file that you
can feed into your Jenkins server to get some trends and
dashboard, and a local HTML report to get the same result
when you're running your test on your workstation.
The same Android project is a little bit more complicated,
but it's not that bad, really.
So the first section of the build script is about telling
Gradle where our plugin is.
So we're saying here, hey it's on mavenCentral.
Here's the artifact.
Just put it on the class path.
It's something that the Gradle developer wants to improve the
future, so hopefully it will be a bit less verbose.
So we just apply the plugin like we did
for the Java plugin.
And then the third block is really the beginning of the
configuration of the Android plugin.
And so we have two properties here.
The first one, compileSdkVersion is what
you'd use as target in project.properties.
We renamed it because target, target SDK version, there was
some confusion there.
And then the second property I will talk about later.
So what can you do with that?
Well, you can build an APK.
We can build a test APK.
It used to be that we had a separate test project.
It's just not flexible.
We have to find it.
It's so hard to find the relation
between the two projects.
So it's back in the main project.
You can deploy those two APKs and run the test on any number
of connected devices.
It will run them in parallel, and you'll get the same two
output-- the XML and the HTML.
So already, we do more than the Ant script.
So as you noticed, I didn't configure anything.
It's convention over configuration.
And for source folder, this is the convention for regular
Java projects, because you have your main code
and your test code.
It's in the source main and source test.
So for Android, we reuse the same convention.
We expand it a little bit, because we
have a lot more files.
So source main, we add Android manifest, XML.
We add the resources, the assets.
We move the AID and run the scripts files
under their own folders.
And then, on the test side, we call that instrument test.
We wanted to keep test for actual true local [? JUnit ?]
test.
We don't have a manifest in there.
It will be automatically generated.
I'll talk about that later.
All right, so that's your structure.
Now, how do you run the thing?
Oh wait, hold on.
So if you have an old project, I'm guessing that you probably
don't want to go back to all of that and change your
project just to try Gradle.
So this is how you configure a project that you currently
have to tell Gradle this is my structure.
So here's it's very simple.
Again, in the Android block, we have a sourceSet.
And that's a container of sourceSet.
And so, inside, we configure the main and
the instrument test.
So for our instrument test, what we do is that setRoot.
We'll just move everything from
source/instrumentTest to test.
So test/Java, test/res et cetera.
Notice how, for the main source sets, we have
res.srcDirs.
And it's actually a [INAUDIBLE] with bracket.
That's because we can actually now support
multiple res folders.
So you can just organize your source however you want them,
and then we just merge them together, detect duplicates,
and do the right thing.
All right, so to run Gradle.
Well, once you have installed Gradle, you go to your project
root, and you just do Gradle and some task name.
To get the task, there's a task called task that give you
the list of tasks.
And if you do dash dash all, it will give you all the
intermediate tasks that you probably don't care about.
And on the really complicated project, it's going to be 50
tasks, or something like that.
You don't care about all of those.
You care about four of them.
assemble will build your project output.
Check will run all your checked and test.
Build will do both assembling and testing.
This is what buildling a product is.
It's building it, but also testing it.
And then clean does the clean.
So the thing that's interesting here is that those
tasks actually don't do anything.
I like to call them anchor tasks.
Plugins will go and kind of like plug them under it, and
say, hey, when the users says assemble, here's the task that
you should actually call.
So the Java project, for instance,
has different tasks--
JAR to build the JAR, and test to run the test.
So that means that when you apply some other plugin like
the [INAUDIBLE], there's a FindBug plugin, you don't have
to care what it's tasks are.
You just call check, and it will call test, FindBugs main
and FindBugs test.
So it's very powerful and very extensible without you having
to know what's going on
So for Android, we do the same thing.
We have assemble, and then we have check, and then we have
connectedCheck and deviceCheck.
And this is because of the test without
device, test with device.
I'll talk about that later.
One of the differences, assemble will actually build
two different versions.
We have the debug in [INAUDIBLE] release, similar
to Ant release and debug.
Except that here, you can actually build both of them in
parallel and have them built while Ant will
override each other.
All right, so let's talk about customization a little bit.
That's why we're building this new build system.
So the most basic customization is, let's say
you want to override some properties.
So for example, here we have a defaultConfig object inside
the Android object that says hey, I'm going to do version
code and minSdkVersion, and something.
And so when you build, those values will get injected into
your manifest and that's great.
You're probably wondering, well, why do I want to do that
when I can actually just put those values in my manifest?
Well, imagine that you want to do a nightly build where you
want to increase the version code incrementally.
So you could do some script that goes in, and somehow hack
your manifest around, and do something, and that's probably
not very good.
So here, Gradle allow us to just do something while you
create a new function that will get that version code
from Jenkins, for example, through system property or
[INAUDIBLE].
And then you just inject it into the version code.
And that will work all the time.
And then, if the function actually returns minus one by
default, which is when you're running on your desktop, then
the value will not be injected.
So you can do some custom logic, but it's still very
declarative.
I mentioned just a minute ago that we
built debug and release.
And a lot of developers have asked us things like, hey, I
want to run ProGaurd in debug.
Can I do that please?
And before it was like, well we can't redo it.
So we looked at it, and we said we're going to do
something really flexible.
And so we introduced the concept of build types.
Build types are about how I package my application and
some options like, is it debuggable, how is it signed,
do I run ProGaurd?
And you start with a built-in debug and a built-in release
one, but you can create new ones.
So here's the DSL to do it.
So inside the Android object, you have a
very build types object.
That's also a container.
We saw that.
We saw sets.
We're going to use that again.
It's a typical pattern that we have.
And so in it, we configure the debug properties.
And we set some property of the debug build type.
And we set some properties.
And one of them is package name suffix.
So any time you build with debug, whatever the package
name of your application is, will append the debug at the
end of the package so that you can study it side by side with
your release application.
And then suffix name will just a suffix also to extend.
It's something that a lot of developers have asked us.
And then we have this new thing in Play Console where
you can have a beta version.
And maybe you want to actually build a specific beta version
for those testers.
And so you can create a new beta test.
And so here we are adding some properties.
And that's great.
But that's not really enough.
You should really want to customize that beta version.
So for each build type, you also get a
custom source folders.
So for example, in your beta version, it's a beta test, so
you want to gather some statistics on how your users
are using your application.
So how do I do that?
Well, under source/beta/java, you just put some code.
And that code will get packaged with your beta
application whenever you build only the beta version, not the
release, and not the debug version.
You probably want internet permission to be able to send
those data.
And maybe your regular application doesn't have the
internet permission.
So instead of bring it manually in the manifest some
time and forgetting to remove it, which is not great, you
just put it in source, beta, Android manifest, and that
gets merged into your main manifest when you build only
the beta version.
And you can use that also for things like if you have
MapView API key and you want a different API key on release
and debug because it's tied to you're signing configuration,
well, you can just put that into the res folder of those
different build types.
And of course, you need to be able to
build the beta version.
So that's where the assemble debug and assemble release are
coming from.
They are just automatically generated whenever you add a
new build type.
So you can actually have all three versions at the same
time and build them.
All right.
So I just said that signing was part of the build type
configuration.
So we wanted to make things very flexible here.
We have a container of signing configuration.
And a signing configuration is in a location of the KeyStore,
passwords, you know, name of the key.
And we have a default version one called debug.
And so here, what we're doing in that simple example is we
are telling Gradle, configuring the debug signing
configuration and using a KeyStore that's at the root of
my project so that way, everyone on your team or your
build server always would build with
the same debug KeyStore.
And there won't be an issue when your QA is trying to
install something coming from a different build.
And that's all you have to do.
The debug build type is automatically configured to
use that particular signing configuration.
Let's look at another a little bit more complicated example.
Let's say you have a release version of your application
that is different from your debug because maybe you have
some properties that tell it, hey, I want to use my
production server instead of some test server.
I'm using ProGuard.
I'm obfuscating and doing a lot of things.
And I want to test that version.
I want to debug it.
How do I do that?
Well, what you would do, you would create a new build type,
call it debug release, for instance.
InitWith will initialize it with the release build type.
So every time you go and change your release build
type, it just gets copied into your debug release.
And then we customize something.
So we say, hey, it's debuggable.
We add a suffix to the package name to make sure you can set
it in parallel with the your release version.
And then we assign the debug signing config so that anyone
can build it.
And then we change the sourceSet to make sure that
source/release, whatever you put in there, is also used to
build your debug release.
And just with these few lines, you suddenly have a new
version of your application that's exactly, and always
exactly, the same as your release, but you can debug it.
And if you wanted to have some custom ProGuard specifically,
also, for that version, to disable or enable some rules,
you could do that.
But by default, it will just pick up all the rules that the
version would use.
What I really like about that example, also, is that it's
not showing you that it's declarative.
But initWith here doesn't receive a primitive type.
It receives, actually, a buildtypes.release.
That's actually an object of type build type.
So what happens is that every time inside the build type
container, you start using release, or debug, or beta, if
that particular object doesn't exist, we create
a build type instance.
And we put it in the container.
So what you're really doing here is not just setting a
bunch of properties that will be read later on, and by
something that will parse that file, and build something.
Every line actually manipulates a live model.
And that's very important and very powerful.
That means that, let's say we have the release, beta, debug,
debug release.
That's a lot of them.
And maybe you don't want to put the suffix for the package
name on all of them manually.
What if you could just it programmatically?
Well, just do something like that.
After the Android block, where you configure all your build
types, just loop on the build types and just assign
automatically the package name.
What's really interesting here is that you're basically
building that model.
And that configured model is what is sent to the IDE during
the IDE integration when you report your project.
So whether you're setting those package name suffixes
manually or whether you're using some logic, a loop, or
maybe you say, hey, we only want to add them on Mondays,
whatever you're doing, it's just going to work.
The IDE will just be aware of what's going on, because it
gets the final configured model.
And that's very powerful.
That allows us to really have the IDE know everything about
your project based on that model.
However, it is, whatever logic you use to
actually configure it.
All right, let's look at dependencies.
It's something that a lot of developers have asked for.
So Gradle supports that natively, so we
benefit from that.
So there's four scopes of dependencies--
compile, runtime, that's for your main source code.
And runtime always extends compile.
So if you had a dependency to compile, runtime
automatically gets it.
And then there's the same for test.
So far Android, slightly different, mostly because we
renamed runtime to package, because it's
what really we do.
We package all of your dependencies into the APK.
And then test, instrument test, to make sure that it's
always instrumentation test.
So let's go back to your beta version, right?
We want to send the statistic to the user.
Let's say you want to use some library to help you.
Well, if you add them on compile, that means that your
release will also have that library.
And you don't want to do that.
So we have scopes specifically for your build types.
So here, only on the build type compile scope, you would
say, hey, I use [INAUDIBLE]
or something like that.
And then it's only for that build type.
So this is how you do dependency in Gradle.
You have a dependencies object.
Compile is the scope.
And then you give it whatever dependency you have.
Here we say, if I have an old project and I have a bunch of
JAR filing under my libs project, that's what you do.
[INAUDIBLE]
every JAR file under libs.
Very useful to migrate your current project.
So if you want to use remote dependencies,
this is what you do.
First, you tell it what repository to use.
So here we say mavenCentral, but you could say, if you have
a custom internal artifact repository, you
can put the URL there.
Whether it's Maven or Ivy, it will support it--
not a problem.
And then in the dependency block, the instrument test
compile, you give the artifact address.
And here we use the fest-android from square that
allow you to have some nice asserts and test output.
And then notice how the beta compile use the local JAR.
So it's not I want to use either dependency management
with Maven or a local JAR file, you can just mix
depending on what you have.
Gradle is very flexible.
It will use whatever you want.
So that's about using someone else's code.
If you want to use your own code, it's slightly different.
First, you need to have a multi-project setup.
It's something that we didn't have before.
Eclipse doesn't really support that, and [INAUDIBLE]
of course.
So here, what we have is, we have three
different package modules.
There's app, lib1, lib2.
They're all their own project with their own build.gradle.
And there is settings.gradle that say, here's all the
different modules.
And for the dependency, you just say, hey, I want to
include the project and the path of the project.
So that's very similar and very easy.
So library 1 could be a library project.
And then lib2 could be just like a JAR file.
And if lib1 depend on lib2, of course, app will get
transitively your dependencies.
And so if lib1 is a library project, this is how you
declare a library project.
It's exactly the same as a regular project.
It's the same plugin.
You only need one plugin.
It has both only one Maven artifact.
It has both plugins inside.
And the plugin name is different, but it's exactly
the same as a regular project.
The DSL is slightly different, because there's some
restrictions.
But I'm not going to go into detail on that.
So what does a library project do?
Very similar to what they currently do.
We have some new things.
The first thing is that, finally, we have binary
packaging of them.
So we package everything into an AAR format.
It's just a Zip file.
It's a bundle.
And you can upload that into repositories.
[APPLAUSE]
XAVIER DUCROHET: Guess it's been a long time coming.
Other thing that we support, we had support for assets, so
just put assets in your library.
They'll get merged into your application.
We have ProGuard rules.
So if, for example, your library has some specific
class that should not be obfuscated, just create a
ProGuard file to say keep that particular file.
And whenever that application that use that library runs
ProGuard, it will also enable that ProGuard rule so that
your class doesn't get obfuscated, for instance.
We don't have Lint integration yet, but as soon as add it, we
want to do things like not custom Lint rules, so that if
you have some custom-made APIs that you want to make sure
people use properly, you can have some rules there.
And we are looking at adding other metadata so that whoever
use your library, they have a better experience in the tool
chain, in the IDE, and it's better for your user.
All right, so library project have been used for people who
want to do free versus paid and things like that.
And it's great.
Now multiple APK support in Google Play also allow you to
do, for example, different APK for if you're targeting an
older version of Android or a newer version of Android, or
if you're targeting ARM versus MIPS versus x86.
But if you want to use all three or a combination, then
it becomes impossible to deal with library project.
And so we have build variants.
So this concept of product flavor is about what is your
application?
So it's going to support different applications,
whether they have the same package name or not, depending
if free versus paid or not.
And it will do customized things.
So it's really like a different
dimension from build type.
It's combined with build types.
So here's how you create them.
We have a product flavor containers.
And you can just create new ones.
So here I'm creating two flavors, flavor1, flavor2.
I'm assigning some packages.
One of them say, hey, I want a different minSDK version.
The other one will use the minSDK version from the
manifest automatically.
And of course you want to have different
code in those, right?
The free version will have some code specifically to
free, and the paid version to paid.
So for each of those, you get a new source folder as well.
And because you want to test it separately, you get a
separate test folder as well.
want to add some like dependency on AdMob's SDK, for
instance, but you don't want to put that on the paid
version as well, so you have a different scope.
So here, we'll have a lot of scope for all your
applications.
And basically, based on what you build, we'll pick all of
them and put all your dependencies together.
So the part that's important is that, if you don't have any
flavor, and you have debug and release build types, you get a
debug and a release application.
If you have flavors, then it's really a matrix, and we do a
combination of everything.
So if you have flavor1 and flavor2, then you can't have
just a debug build.
It doesn't mean anything anymore.
It's either flavor1 debug or flavor2 debug.
So that's very useful if you have flavors to [? spend. ?]
Now, if you also want to combine x86, versus MIPS and
versus ARM, well, that doesn't really work, right?
So we have flavor dimensions.
But we called then groups in the DSL.
We might have to rename that.
So it's really a different dimension compared to--
so one dimension is ABI, x86 versus ARM.
And the other one is the version, whether
it's paid or free.
And so here, we create two ARM, and we assign them to a
specific dimension.
So note how the ARM1 doesn't customize the package name.
That's because it's just the same version of you
application, while the paid version has
its own package name.
So there's going to be some combination of all of that.
First, at the end, you get a lot of packages.
And you just get them automatically.
And if you add a new dimension or add something, it will just
take care of generating all of that for you.
And so, because it's complicated, you need to
understand all the different ways we combined all of those
dimensions--
build type and different dimensions of product flavor.
So you could get up to four different source folders, for
example, in that particular example.
And so they're all going to be considered as if there was
just one source folder.
And we'll just combine everything into a single SDK.
If you have resources, we just use override mechanisms.
So we start with your base resources.
We override on top of it the flavors.
And then on top of that, we override the build types.
And that's for res and for assets as well.
And if you have libraries, they will be under the main
one, and they will be overridden by all that.
Signing configuration, here we have some flexibility.
It's a priority order.
So highest priority order is build type, and then flavor,
and then your main configuration.
What's interesting here is that the debug build type has
the default debug configuration.
And so every debug build type will get signed
with the same key.
For release, if you assign a signing configuration on the
release build type, all your release will be signed with
the same key.
But if you don't want to do that-- maybe your paid and
your free needs different signing key-- then don't
assign a signing configuration on the build type, and assign
it on the flavor instead.
And then it's the one that will get picked up, and you
can have different signing for two different
versions of your apps.
And the package name, so you saw that we have a lot of ways
of customizing package name.
So we start with the base Android
package name in the manifest.
If you have a different configuration that overrides
it, we take this one instead.
If you have a flavor, we take this one.
And then, when we figure out which package you have, if you
have one in the build type, we append the suffix.
But when we generate the R class, we always use the
package name in the src/main/AndroidManifest.xml
that so that all of your import, wherever you are, are
always the same one.
There's no switching.
You can generate many applications with different
package names.
But all your imports are always the same.
OK let's talk about testing.
I mentioned testing here and there, so
let's do a quick recap.
You have source folders for testing and one per flavor, if
you use flavors.
You have dependency scopes, one specific for testing and
one per flavors.
We generate the manifests.
And now you probably understand why we generate
those manifests, since if you generate six different
applications with six different packages, you don't
want to maintain six different manifests for your test
application.
The manifest for the test application actually reference
the package being tested.
So that would be a lot to maintain.
And for the package name of the test application, we
generate that automatically based on the package name of
the tested application.
And we're going to have one test app per tested
application.
So debug, by default, you can configure it.
We'll probably change that in the future.
But right now, it's just one.
And then finally, library project, even though they
output just an AAR not an APK, we can test those.
So inside the library project, one of the
outputs is the test APK.
And it will embed your library into it, so you can test your
library separately and inside your APK also, if you want.
All right, so that's about building.
What about running tests?
So that's a little bit complicated.
And we looked into it.
And we found out that there's really
three different scenarios.
The first scenario is I don't have devices.
I just want to test something.
And we link that to the regular
check task from Gradle.
So you're going to be limited to what you can run there.
You're going to be able to run static analysis like other
FindBugs and all links.
And if you use Robolectric, well, you can
run them there too.
The second scenario is, I'm a developer sitting at my desk.
I have my phone connected to my workstation,
maybe also a tablet.
I want to run something.
So that's what connected check is.
It will just look for connected devices, run
everything on it in parallel, just give you your results.
OK, third scenario is your build server.
Well here, you shouldn't really have devices connected
directly to your build server.
Several issues.
First, well, you may have more than one build server.
So that's a problem.
You're going to enable a lot more devices.
If you do build in parallel, you can't run instrumentation
tests that hit the UI in parallel, because that's just
not going to work.
So we need to have some sort of queue, right?
So we looked around, and there's really two different
scenarios there, sub-scenarios.
So the first one is, you have a device lab somewhere.
And you have a queue system.
And your build system just builds something, and then it
gets put in the queue.
And you have devices, and you test that.
And, well, you're going to get a remote dashboard, because
it's not going to be your Jenkins systems
running your tests.
So you'll get a different dashboard.
But that will work.
So one thing that we think is important here is that you
don't want Jenkins to, after your build, say hey, what's
the output?
I grab the output and I upload it somewhere because Jenkins
doesn't know about all the build variants that I just
talked about.
So you want to have the build system, who is aware of that,
actually do the push.
So that whenever you add a new build variant, or remove one,
you don't have to go back and configure
your Jenkins instance.
So we created an API.
And we call that test server APIs.
And it allows you to upload an APK somewhere.
It's very easy to implement.
And so if you have your own testing lab, you
can implement it.
If you don't have your own testing lab, well, there are
services out there that do that.
Testdroid is one.
AppThwack is one.
Both of them are on the Sandbox.
So you should go and talk to them.
And we're going to work with those guys to make sure that
they create a plugin, and we integrate with them.
The second scenario is, well, what if you have [INAUDIBLE]
devices or emulators, it's generally going to be emulator
that runs directly and on demand.
So here we have another API.
It's very simple.
We get the list of devices.
And for each device, we connect to them, which in case
of emulator is really going to be just starting them.
Then we install, we get the test, we drop them, and then
we have, actually, a local result.
And there's different companies doing that.
One of them is Manimal.
They're here, also, on the Sandbox.
So you can go and talk to them.
Or maybe I can show you, actually.
We worked with those guys, and we created a plugin.
So let's look at what that looks like.
So here I have a sample project.
It's very basic.
I have a build.gradle here.
So we applied the Android plugin right here and then
their plugin.
So what that does is, basically, their plugin, upon
being installed, automatically finds our plugin and says,
hey, I'm implementing that extension
point, just go there.
And then, because it's a greater plugin, it can also
have its own DSL.
So here we have a custom DSL that says, hey, I want to test
on those two devices.
But they have over 50 different emulator
configurations.
And so if you don't provide any device, it's just going to
say, I want to test on all of them.
So it's going to get the list from their server, find the
ones that are compatible with your application, depending on
your minSDK version and things like that.
Well, right now, only minSDK version, but later, ABIs and
things like that.
And it will just run all the tests in parallel.
So here, for it to be easier, we're just going to test on
two different ones.
So the first thing I want to show you is, when you get the
list of tasks, because we know that there's
this extension point--
instrument test method.
And so, every time you have a new service provider, we have
a new task for it.
But we're not going to call it.
On your build server, you would directly do Gradle
device check.
I'm going to do info here.
And so it's going to be build the application, which
actually doesn't need to be built.
So it's going to say, up-to-date, up-to-date,
up-to-date.
And here we start building.
Say, hey, connecting to that emulator.
And so my device is not starting any emulator here.
It's actually connecting in the cloud.
It's starting the [INAUDIBLE] one.
And then it's going to deploy.
Hey, I have a test that succeeded.
And it's shutting it down now.
And then I have another test that succeeded.
And it's done.
And that's it.
I just tested on two different emulators on the cloud.
It could've been 20, 50 in parallel.
Super easy to do.
And then you just go and you do open build/reports/in
strumentTests/device--
and you have a report per provider--
index.html.
And you have your test.
It's tested on those two devices.
You can look per device.
And it's there.
Super easy to do.
We really wanted to improve.
[APPLAUSE]
XAVIER DUCROHET: So we really want to improve the experience
of testing for Android.
And there's a lot of things that go in there.
There's helping you write tests.
And we need to work on that.
But running them is a big part of it.
And working with companies like Manimal.
So again, down on the show floor, they actually have a
special offer for I/O attendees.
So you should definitely go and check them out.
Integrating with third-party services, or making it easy
for you to integrate with your own system
internally is super important.
And we want to make sure that is super easy for you to use
All right, the last thing I want to talk about is the
built environment.
So we know that, in the past, we've regularly updated the
tools and somehow broke your build.
You get a new version of ADT, and nothing compiles anymore.
And it's a big problem.
And we want to fix that.
We want to make sure that this doesn't happen again.
And Gradle is really going to help us do that.
There's four key points to that.
First, well, you're in charge of the Gradle version.
And you were already in charge of the Ant version somewhat,
but Gradle actually--
they increased, they added new features so quickly compared
to Ant that it's good that you're in charge.
And they have this feature called the Wrapper that makes
it super easy for you to really control the fact that
every developer, everybody build server, has the same
version of Gradle.
It's a really sleek tool.
Really check it out.
Second point is, you're in charge of the
version of the plugin.
So you saw in the DSL right at the beginning how I say, hey,
get the plugin from Maven Central, and here's it is.
Well, part of the artifact address is the version number.
When we update a new version, we're not going to remove the
old version.
So you can always stay on an older version.
And it's up to you to switch when you're ready to switch.
The second point is that probably, that I didn't talk
about also at the beginning.
So the plugin uses some tools, like APT to compile the
resources, DX to compile the bytecode into Dalvik.
And it used to be in the SDK under a component called
Platform Tools.
And there was only one version of it.
And sometimes, when you update the tools, it forces you to
update the platform tool, and so, suddenly, hey, it's
updated under you, and you don't have a choice.
So here, we moved that out of the SDK platform tool
component, and we created a new component
called Build Tools.
And the big point about Build Tools is it that you can have
many of them in the SDK.
So imagine a case where you have--
[APPLAUSE]
XAVIER DUCROHET: So imagine a case where you have an SDK.
You have an old project that you don't want to migrate,
because it's fine the way it is.
It's using an old plugin and an version of Build Tools.
It's not a problem.
You want to start a new project.
You want to start fresh.
You use the new version of the plugin.
You use a new version of Build Tools, and you have two
different projects using two different tool chains from a
single SDK.
And then finally, the fourth point is that, well, the IDE I
mentioned that when we talked about Studio on Wednesday.
The IDE doesn't do a build anymore.
You import greater projects.
You delegate to greater project whenever you do build.
So before, when you updated the ADT, you would get both,
inside the same plugin, a builder and editors.
Here, Studio is all about editing, and
debugging, and profiling.
It's not about building anymore.
So feel free, every time we release a new version of
Studio or of ADT, when we integrate Gradle into ADT,
which is coming, feel free to get the new version.
Because Gradle, it's only when you change those values in
your build script that you will force yourself to switch
to a new version of the build.
All right, so this is a very short introduction to the
build system.
There's a lot of information online at tools.android.com, a
lot of documentation, and more details about
configuring the build.
Like I mentioned, the DSL for the library is very different.
So you should check it out.
We need your feedback, right?
We want to make sure that it's as flexible as it needs to be
for all of you.
I think we already have a lot of customization.
But I'm sure there are some things that we're missing.
And so give us feedback, try it.
Especially with Studio, anyway, you have to try it.
So that's why we're very happy.
And just give us feedback, FindBug, and we'll do whatever
we can to improve things.
So actually, it looks like I do have time for questions.
XAVIER DUCROHET: Thank you.
So I will be after anyway in the Sandbox upstairs to answer
whatever questions.
But we do have time, so I guess we
can take some questions.
AUDIENCE: So you mentioned that I believe you had compile
and release dependencies or runtime dependencies-- you
guys have different names for it.
How is android.jar treated?
XAVIER DUCROHET: I'm sorry, android.jar?
AUDIENCE: Yeah, because it's like a build-only dependency.
XAVIER DUCROHET: So it's done automatically.
You don't have to do it.
In your DSL, at the beginning, when you say compile SDK
version 17, it just picks the SDK version from 17.
AUDIENCE: So can you add a hook for that?
Is it possible for you guys to add a hook for that?
XAVIER DUCROHET: I'm sorry, do what?
AUDIENCE: Well, some of us are compiling custom versions of
android.jar.
XAVIER DUCROHET: Umm--
well, you probably shouldn't be.
[LAUGHTER]
AUDIENCE: Some of us are.
XAVIER DUCROHET: Yeah.
And we'll have to figure something out, I guess.
AUDIENCE: Thanks.
AUDIENCE: First, thank you.
It's a lot of stuff.
I have two questions.
One is about library projects dot AAR.
Do they each have their own R.java or does the whole lab
have its own R.java?
XAVIER DUCROHET: So AAR has--
Can you repeat?
AUDIENCE: So can library projects
have their own resources?
XAVIER DUCROHET: Yeah, resources, assets.
So the AAR is a zip file.
In it, you have classes.jar.
That's your compile classes.
It has your manifest, in case you have activities,
permissions, and things like that.
It has resource folder, assets folder, it has a ProGuard
file, in case you have one.
Ultimately, it will have JNI libraries if you have them,
[INAUDIBLE], whatever.
AUDIENCE: OK, thanks you.
And the second question is about NDK integration.
XAVIER DUCROHET: Yeah.
AUDIENCE: You had a couple things there
about x86 and JNI.
XAVIER DUCROHET: So I do mention the whole x86 and ARM,
and that's the design of it.
But we don't support the NDK right now.
So that's coming very soon though.
So you'll be able to build directly.
Gradle will call out to the NDK.
It will have a way of configuring in a build type
which ABI you want to use, either all three if you want
to do a fat package or just one.
And then it will call out to the NDK saying, hey, please
build the ARM version and put the result here for that build
type, build it for another ABI, and put it there for
another build type.
And so that's how we're going to do the filtering.
AUDIENCE: And will that be integrated into Android Studio
also, the NDK building?
XAVIER DUCROHET: Yes, so it will be part of Gradle.
So whenever you build with Gradle, if you say, hey, I
want to build native stuff, it will build it.
And Studio will technically not care about it.
At some point, we'll have to add editing features for them.
That's going to take longer.
But at least you would be able to edit your files and just to
make it work.
AUDIENCE: So where can we see details of
what's coming for NDK?
XAVIER DUCROHET: We don't really have any roadmap
planned at this time.
AUDIENCE: OK.
XAVIER DUCROHET: I mean, we do have some plans, but we don't
have anything written down.
AUDIENCE: Hi, my name is Mark.
I would like to know that, OK, so now we have many folders,
like, SRC, JAVA, JNI, RRS, asset, and so on.
And the merging process of these
folders, are they different?
Or what I really want to know, can we have dependencies and
assets, so if we have library processes with the assets in
it-- right now it's not built into the final APK--
is that true for the new one, for the Gradle build?
XAVIER DUCROHET: Yeah, so if you have assets in your
library that will get packed into your package.
You can have assets, per flavor.
Every flavor, every build type, has its own JAVA code,
its own manifest, it's own resources, its own assets.
And depending on which flavor you're building, it just picks
up and merge all of that together automatically.
And libraries are picked up automatically and merged.
And it's--
AUDIENCE: Thanks, I waited a long time for that.
XAVIER DUCROHET: All right.
AUDIENCE: So since you're not supporting NDK, how about Ant?
Is that still going to be supported for the time being?
XAVIER DUCROHET: Ant is going to be, I guess, deprecated.
I would recommend moving to Gradle as soon
as you're able to.
If you're missing features--
AUDIENCE: You're not supporting NDK.
XAVIER DUCROHET: Oh support for the NDK?
AUDIENCE: You just said that you're not supporting NDK at
this moment.
So the only way to build it-- well, not the only way, but--
XAVIER DUCROHET: Well, right now, the NDK doesn't build
with Ant either.
It just makes files.
AUDIENCE: Yes, but it's easy to integrate.
XAVIER DUCROHET: Yes, but that's not the future.
[LAUGHTER]
XAVIER DUCROHET: It's like, I mean, we're going to keep the
make files inside the NDK anyway.
So you can call it manually if you want.
It's like, the problem with the Ant stuff is that it's a
mix of, I have some scripting in the XML, we have some
custom code, because whenever we have some really complex
logic, like combining all of those sourceSet, assets, res,
all of that, you can do that in XML.
So we have custom tasks.
I reimplemented quick if/else statements in the custom task
to be able to use it in my XML.
But it's like, it's a mix.
And we pass a lot of things to the custom task, and then back
to the XML, and back to another custom task, it's just
a fucking mess.
It's just, we can't maintain that.
And I'm happy to let it be whatever it is when it was
switched to Gradle, but we're not going to improve it.
It's not going to work from an IDE.
It will be deprecated.
But I mean, it's open source.
Take it, make sure that you have a good version, if you
really want to maintain it.
But we're not going to keep maintaining it.
The goal of this build system is to have a single one that
works everywhere.
So I'm not going to keep maintaining also another one--
although right now I am.
But when we switch to 1.0, we're not anymore.
AUDIENCE: Hi [INAUDIBLE].
My name's William.
I've been using Maven to build up until now.
So it looks like I've got to change the way I'm thinking
about things.
One of things that Maven does really well is you can go and
release your APK at the end.
And it handles all of the versioning and makes sure
everything works all right.
How's that going to work with Gradle?
XAVIER DUCROHET: Wait, sorry, can you repeat that?
that Maven does where, when you want to go and release a
version of your APK, it handles the versioning,
interacts with your source control mechanism, does all
the build for you, updates source control, publishes to
your artifcat repositories, et cetera.
XAVIER DUCROHET: Yeah, that's probably more like a question
for Gradle itself than our plugin.
You know Gradle, where they have a Sandbox, and when I
take questions, there will be people from Gradleware.
Because it's more like the whole
workflow behind releasing.
And Gradle I'm sure supports that.
We'll do that upstairs.
We'll take that question upstairs.
AUDIENCE: All right, the other one is, APK libs, which are
pretty common imports now--
XAVIER DUCROHET: Yes, so the Maven plugin will switch to
AAR format.
I'm looking to supporting APK lib.
But I'm not sure if that's going to happen or not.
But they're switching to AAR.
And I know some libraries are going to
publish to AAR already.
So I talk to Jack [? Wharton ?].
[INAUDIBLE]
at some point are going to distribute AAR.
So you'd be able to use that.
AUDIENCE: So we'll be able to, for our libraries we intend on
publishing, we'll be able to create an AAR as an output?
XAVIER DUCROHET: Yeah.
AUDIENCE: All right, cool, thanks.
XAVIER DUCROHET: All right, thank you, so I'll be upstairs
if you have more questions, feel free to
come and talk to me.
[APPLAUSE]