Even with all the current and upcoming changes in the Android compiler toolchains and build systems used for both applications and the platform, one common issue continues to come up amongst Android platform developer community: What is the best way to develop platform applications given the current state of the tools?

## The Problem

With the introduction of the Gradle build system (used by Android Studio), the default project structure for an application has deviated from the platform’s internal build system (based on `Android.mk` files). This creates a problem if you are working on internal applications destined to be packaged with a custom system image.

Which build system do you choose? Either way you go, some mapping is required. The default project structure for a platform package (application) looks something like this:

``` PlatformAppPackage/
aidl/
assets/
AndroidManifest.xml
Android.mk
java/
jni/
res/```

Where the contents of the `Android.mk` file might include:

`Android.mk`
``````LOCAL_PATH:= $(call my-dir) include$(CLEAR_VARS)

LOCAL_MODULE_TAGS := optional
# Reference java/ and aidl/ source files
# res/ and assets/ are discovered automatically
LOCAL_SRC_FILES := \
$(call all-java-files-under, java) \$(call all-named-files-under, *.aidl, aidl)

LOCAL_PACKAGE_NAME := MySystemApplication
LOCAL_SDK_VERSION := current
LOCAL_PROGUARD_ENABLED := disabled
LOCAL_CERTIFICATE := platform

include $(BUILD_PACKAGE) ####################################### include$(CLEAR_VARS)
LOCAL_SRC_FILES:= \
$(call all-cpp-files-under, jni) LOCAL_MODULE := mypackage_jni include$(BUILD_SHARED_LIBRARY)``````

## Hacking Android.mk

Most folks are typically inclined to migrate the entire project structure to a Gradle-based project, so that Android Studio will recognize the sources and the developers can more easily work with the code. Then the necessary changes are made to the `Android.mk` files to support building with the platform. This would take the above project and make it look more like this:

``` GradleAppPackage/
Android.mk                  (1)
app/
Android.mk                (1)
src/
Android.mk              (1)
main/
aidl/
assets/
Android.mk            (2)
AndroidManifest.xml
java/
jni/
res/
 1 Required intermediate makefile to allow build to find real makefile 2 Real makefile used to compile the package 3 Top-level Gradle build file to declare project dependencies 4 Gradle module file used to compile the package 5 Gradle project file allowing top-level to reference the module

The first thing you may notice is that it’s makefiles all the way down! What’s worse, all those intermediate makefiles look like this:

``include $(call all-subdir-makefiles)`` Their only purpose is to allow the build system to find the actual makefile that lives in a subdirectory. Without these, the module might be skipped by the build system depending on what other directories are around it. The reason for this is that the build implicitly looks for the `res/` and `assets/` directories in the local path. The `build.gradle` files in this case are standard fare that Android Studio would generate: `build.gradle` ``````buildscript { repositories { jcenter() } dependencies { classpath 'com.android.tools.build:gradle:1.5.0' ... } }`````` `app/build.gradle` ``````apply plugin: 'com.android.application' android { compileSdkVersion 23 buildToolsVersion "23.0.2" defaultConfig { applicationId "..." minSdkVersion 15 targetSdkVersion 23 versionCode 1 versionName "1.0" } ... } dependencies { ... }`````` ## Alternate Android.mk One alternative to remove the excess is to map the implicit dependencies in the `Android.mk` file. We can replace the above Gradle structure with the following: ``` GradleAppPackage/ Android.mk app/ build.gradle src/ main/ aidl/ assets/ AndroidManifest.xml java/ jni/ res/ build.gradle settings.gradle``` If we modify the base `Android.mk` file to look more like this: `Android.mk` ``````LOCAL_PATH:=$(call my-dir)
include $(CLEAR_VARS) LOCAL_MODULE_TAGS := optional # Reference java/ and aidl/ source files LOCAL_SRC_FILES := \$(call all-java-files-under, app/src/main/java) \
$(call all-named-files-under, *.aidl, app/src/main/aidl) # Re-map res/ and assets/ directly LOCAL_RESOURCE_DIR :=$(LOCAL_PATH)/app/src/main/res
LOCAL_ASSET_DIR := $(LOCAL_PATH)/app/src/main/assets LOCAL_PACKAGE_NAME := MySystemApplication LOCAL_SDK_VERSION := current LOCAL_PROGUARD_ENABLED := disabled LOCAL_CERTIFICATE := platform include$(BUILD_PACKAGE)

#######################################

include $(CLEAR_VARS) # Re-map native code path LOCAL_SRC_FILES:= \$(call all-cpp-files-under, app/src/main/jni)

LOCAL_MODULE := mypackage_jni

include \$(BUILD_SHARED_LIBRARY)``````

One advantage to this approach is that you could leverage the product flavors feature of a Gradle build, and potentially map different build targets to each of the variants.

The other option is to keep the source files in the structure that `Android.mk` prefers and create a `build.gradle` that maps the appropriate directories using source sets.

This was a common technique in the early days of migrating ADT-based projects to the Gradle build system before Android Studio came with an importer that moved all the files around automatically for you. Since then, using the `sourceSets` attribute has become somewhat of a lost art amongst Android folks.

In this case, the source tree would look like the following:

``` PlatformAppPackage/
aidl/
assets/
AndroidManifest.xml
Android.mk
java/
jni/
res/```

Awesome! We only had to add one file! Let’s see what it looks like:

`build.gradle`
``````//Top-level buildscript information
buildscript {
repositories {
mavenCentral()
}
dependencies {
}
}

//App module build information
apply plugin: 'com.android.application'

android {
compileSdkVersion 23
buildToolsVersion "23.0.2"

defaultConfig {
targetSdkVersion 23
...
}

sourceSets {
main {
manifest.srcFile 'AndroidManifest.xml'
java.srcDirs = ['java']
resources.srcDirs = ['java']
aidl.srcDirs = ['aidl']
res.srcDirs = ['res']
assets.srcDirs = ['assets']
}
}
}``````

You may notice that this has the contents of both previous `build.gradle` files condensed into one. If we have no intention of supporting multiple modules in the same build project, this is perfectly legal.

The key here, though, is the `sourceSets` attribute. This maps the source files and directories from their current locations into the Gradle build without requiring us to move them to the locations where Gradle would implicitly search.

The advantage to this approach is that it requires the least amount of change to map an existing platform project into allowing Gradle builds.

## Summary

So, which method should you choose? I suppose it depends on where you are coming from. If you are integrating an existing Studio project into platform builds, the first option may be less work for you. If the reverse is true, the second approach may make more sense. If you are starting from scratch, pick your favorite.

If you were to corner me at a conference and ask that question, my personal preference would be to use `sourceSets` in Gradle to map a standard project. If your application is intended for platform builds, this creates consistency between your project and the rest of the source tree. Gradle functionality is only provided as an extension to make developer lives easier.