Tutorial - Build an Android App

The sample Android app in this tutorial is a very simple application that makes an HTTP connection to the backend server and displays the resulting response.

Here, you'll do the following:

  • Review the source files for the app
  • Update the WORKSPACE file
  • Create a BUILD file
  • Run the build
  • Find the build outputs
  • Run the app

Review the source files

Let's take a look at the source files for the app. These are located in $WORKSPACE/android/.

The key files and directories are:

Note that you‘re just looking at these files now to become familiar with the structure of the app. You don’t have to edit any of the source files to complete this tutorial.

Update the WORKSPACE file

Bazel needs to run the Android SDK build tools and uses the SDK libraries to build the app. This means that you need to add some information to your WORKSPACE file so that Bazel knows where to find them. Note that this step is not required when you build all types of outputs. For example, Bazel automatically detects the location of Java, C++ and Objective-C compilers from settings in your environment.

Add the following lines to your WORKSPACE file:

android_sdk_repository(
    name = "androidsdk",
    # Replace with path to Android SDK on your system
    path = "/Users/username/Library/Android/sdk",
    # Replace with the Android SDK API level
    api_level = 23,
    # Replace with the verion in sdk/build-tools/
    build_tools_version="23.0.0"
)

Create a BUILD file

A BUILD file is a text file that describes the relationship between a set of build outputs -- for example, compiled software libraries or executables -- and their dependencies. These dependencies may be source files in your workspace or other build outputs. BUILD files are written in the Bazel build language.

BUILD files are part of concept in Bazel known as the package hierarchy. The package hierarchy is a logical structure that overlays the directory structure in your workspace. Each package is a directory (and its subdirectories) that contains a related set of source files and a BUILD file. The package also includes any subdirectories, excluding those that contain their own BUILD file. The package name is the name of the directory where the BUILD file is located.

Note that this package hierarchy is distinct from, but coexists with, the Java package hierarchy for your Android app.

For the simple Android app in this tutorial, we'll consider all the source files in $WORKSPACE/android/ to comprise a single Bazel package. A more complex project may have many nested packages.

At a command-line prompt, open your new BUILD file for editing:

$ vi $WORKSPACE/android/BUILD

Add an android_library rule

A BUILD file contains several different types of instructions for Bazel. The most important type is the build rule, which tells Bazel how to build an intermediate or final software output from a set of source files or other dependencies.

Bazel provides two build rules, android_library and android_binary, that you can use to build an Android app. For this tutorial, you‘ll first use the android_library rule to tell Bazel how to build an Android library module from the app source code and resource files. Then you’ll use the android_binary rule to tell it how to build the Android application package.

Add the following to your BUILD file:

android_library(
  name = "activities",
  srcs = glob(["src/main/java/com/google/bazel/example/android/activities/*.java"]),
  custom_package = "com.google.bazel.example.android.activities",
  manifest = "src/main/java/com/google/bazel/example/android/activities/AndroidManifest.xml",
  resource_files = glob(["src/main/java/com/google/bazel/example/android/activities/res/**"]),
)

As you can see, the android_library build rule contains a set of attributes that specify the information that Bazel needs to build a library module from the source files. Note also that the name of the rule is activities. You'll reference the rule using this name as a dependency in the android_binary rule.

Add an android_binary rule

The android_binary rule builds the Android application package (.apk file) for your app.

Add the following to your build file:

android_binary(
    name = "android",
    custom_package = "com.google.bazel.example.android",
    manifest = "src/main/java/com/google/bazel/example/android/AndroidManifest.xml",
    resource_files = glob(["src/main/java/com/google/bazel/example/android/res/**"]),
    deps = [":activities"],
)

Here, the deps attribute references the output of the activities rule you added to the BUILD file above. This means that, when Bazel builds the output of this rule, it checks first to see if the output of the activities library rule has been built and is up-to-date. If not, it builds it and then uses that output to build the application package file.

Now, save and close the file. You can compare your BUILD file to the completed example in the master branch of the GitHub repo.

Run the build

You use the bazel command-line tool to run builds, execute unit tests and perform other operations in Bazel. This tool is located in the output subdirectory of the location where you installed Bazel. During installation, you probably added this location to your path.

Before you build the sample app, make sure that your current working directory is inside your Bazel workspace:

$ cd $WORKSPACE

Now, enter the following to build the sample app:

$ bazel build //android:android

The build subcommand instructs Bazel to build the target that follows. The target is specified as the name of a build rule inside a BUILD file, with along with the package path relative to your workspace directory. Note that you can sometimes omit the package path or target name, depending on your current working directory at the command line and the name of the target. See Labels in Bazel Concepts and Terminology page for more information about target labels and paths.

Bazel now launches and builds the sample app. During the build process, its output will appear similar to the following:

INFO: Found 1 target...
Target //android:android up-to-date:
  bazel-bin/android/android_deploy.jar
  bazel-bin/android/android_unsigned.apk
  bazel-bin/android/android.apk
INFO: Elapsed time: 7.237s, Critical Path: 5.81s

Find the build outputs

Bazel stores the outputs of both intermediate and final build operations in a set of per-user, per-workspace output directories. These directories are symlinked from the following locations:

  • $WORKSPACE/bazel-bin, which stores binary executables and other runnable build outputs
  • $WORKSPACE/bazel-genfiles, which stores intermediary source files that are generated by Bazel rules
  • $WORKSPACE/bazel-out, which stores other types of build outputs

Bazel stores the Android .apk file generated using the android_binary rule in the bazel-bin/android/ directory, where the subdirectory name android is derived from the name of the Bazel package.

At a command prompt, list the contents of this directory and find the android.apk file:

$ ls $WORKSPACE/bazel-bin/android

Run the app

You can now deploy the app to a connected Android device or emulator from the command line using the bazel mobile-install command. This command uses the Android Debug Bridge (adb) to communicate with the device. You must set up your device to use adb following the instructions in Android Debug Bridge before deployment.

Enter the following:

$ bazel mobile-install //android:android

Note that the mobile-install subcommand also supports the --incremental flag that can be used to deploy only those parts of the app that have changed since the last deployment.

What's next

Now that you‘ve built a sample app for Android, it’s time to do the same for the iOS app.