1# Android {#android}
2
3The Android build environment provides three major features and a number of
4supporting features.
5
6## Deploying an Android SDK installation with plugins {#deploying-an-android-sdk-installation-with-plugins}
7
8The first use case is deploying the SDK with a desired set of plugins or subsets
9of an SDK.
10
11```nix
12with import <nixpkgs> {};
13
14let
15 androidComposition = androidenv.composeAndroidPackages {
16 cmdLineToolsVersion = "8.0";
17 toolsVersion = "26.1.1";
18 platformToolsVersion = "30.0.5";
19 buildToolsVersions = [ "30.0.3" ];
20 includeEmulator = false;
21 emulatorVersion = "30.3.4";
22 platformVersions = [ "28" "29" "30" ];
23 includeSources = false;
24 includeSystemImages = false;
25 systemImageTypes = [ "google_apis_playstore" ];
26 abiVersions = [ "armeabi-v7a" "arm64-v8a" ];
27 cmakeVersions = [ "3.10.2" ];
28 includeNDK = true;
29 ndkVersions = ["22.0.7026061"];
30 useGoogleAPIs = false;
31 useGoogleTVAddOns = false;
32 includeExtras = [
33 "extras;google;gcm"
34 ];
35 };
36in
37androidComposition.androidsdk
38```
39
40The above function invocation states that we want an Android SDK with the above
41specified plugin versions. By default, most plugins are disabled. Notable
42exceptions are the tools, platform-tools and build-tools sub packages.
43
44The following parameters are supported:
45
46* `cmdLineToolsVersion `, specifies the version of the `cmdline-tools` package to use
47* `toolsVersion`, specifies the version of the `tools` package. Notice `tools` is
48 obsolete, and currently only `26.1.1` is available, so there's not a lot of
49 options here, however, you can set it as `null` if you don't want it.
50* `platformsToolsVersion` specifies the version of the `platform-tools` plugin
51* `buildToolsVersions` specifies the versions of the `build-tools` plugins to
52 use.
53* `includeEmulator` specifies whether to deploy the emulator package (`false`
54 by default). When enabled, the version of the emulator to deploy can be
55 specified by setting the `emulatorVersion` parameter.
56* `cmakeVersions` specifies which CMake versions should be deployed.
57* `includeNDK` specifies that the Android NDK bundle should be included.
58 Defaults to: `false`.
59* `ndkVersions` specifies the NDK versions that we want to use. These are linked
60 under the `ndk` directory of the SDK root, and the first is linked under the
61 `ndk-bundle` directory.
62* `ndkVersion` is equivalent to specifying one entry in `ndkVersions`, and
63 `ndkVersions` overrides this parameter if provided.
64* `includeExtras` is an array of identifier strings referring to arbitrary
65 add-on packages that should be installed.
66* `platformVersions` specifies which platform SDK versions should be included.
67
68For each platform version that has been specified, we can apply the following
69options:
70
71* `includeSystemImages` specifies whether a system image for each platform SDK
72 should be included.
73* `includeSources` specifies whether the sources for each SDK version should be
74 included.
75* `useGoogleAPIs` specifies that for each selected platform version the
76 Google API should be included.
77* `useGoogleTVAddOns` specifies that for each selected platform version the
78 Google TV add-on should be included.
79
80For each requested system image we can specify the following options:
81
82* `systemImageTypes` specifies what kind of system images should be included.
83 Defaults to: `default`.
84* `abiVersions` specifies what kind of ABI version of each system image should
85 be included. Defaults to: `armeabi-v7a`.
86
87Most of the function arguments have reasonable default settings.
88
89You can specify license names:
90
91* `extraLicenses` is a list of license names.
92 You can get these names from repo.json or `querypackages.sh licenses`. The SDK
93 license (`android-sdk-license`) is accepted for you if you set accept_license
94 to true. If you are doing something like working with preview SDKs, you will
95 want to add `android-sdk-preview-license` or whichever license applies here.
96
97Additionally, you can override the repositories that composeAndroidPackages will
98pull from:
99
100* `repoJson` specifies a path to a generated repo.json file. You can generate this
101 by running `generate.sh`, which in turn will call into `mkrepo.rb`.
102* `repoXmls` is an attribute set containing paths to repo XML files. If specified,
103 it takes priority over `repoJson`, and will trigger a local build writing out a
104 repo.json to the Nix store based on the given repository XMLs.
105
106```nix
107{
108 repoXmls = {
109 packages = [ ./xml/repository2-1.xml ];
110 images = [
111 ./xml/android-sys-img2-1.xml
112 ./xml/android-tv-sys-img2-1.xml
113 ./xml/android-wear-sys-img2-1.xml
114 ./xml/android-wear-cn-sys-img2-1.xml
115 ./xml/google_apis-sys-img2-1.xml
116 ./xml/google_apis_playstore-sys-img2-1.xml
117 ];
118 addons = [ ./xml/addon2-1.xml ];
119 };
120}
121```
122
123When building the above expression with:
124
125```bash
126$ nix-build
127```
128
129The Android SDK gets deployed with all desired plugin versions.
130
131We can also deploy subsets of the Android SDK. For example, to only the
132`platform-tools` package, you can evaluate the following expression:
133
134```nix
135with import <nixpkgs> {};
136
137let
138 androidComposition = androidenv.composeAndroidPackages {
139 # ...
140 };
141in
142androidComposition.platform-tools
143```
144
145## Using predefined Android package compositions {#using-predefined-android-package-compositions}
146
147In addition to composing an Android package set manually, it is also possible
148to use a predefined composition that contains all basic packages for a specific
149Android version, such as version 9.0 (API-level 28).
150
151The following Nix expression can be used to deploy the entire SDK with all basic
152plugins:
153
154```nix
155with import <nixpkgs> {};
156
157androidenv.androidPkgs_9_0.androidsdk
158```
159
160It is also possible to use one plugin only:
161
162```nix
163with import <nixpkgs> {};
164
165androidenv.androidPkgs_9_0.platform-tools
166```
167
168## Building an Android application {#building-an-android-application}
169
170In addition to the SDK, it is also possible to build an Ant-based Android
171project and automatically deploy all the Android plugins that a project
172requires.
173
174
175```nix
176with import <nixpkgs> {};
177
178androidenv.buildApp {
179 name = "MyAndroidApp";
180 src = ./myappsources;
181 release = true;
182
183 # If release is set to true, you need to specify the following parameters
184 keyStore = ./keystore;
185 keyAlias = "myfirstapp";
186 keyStorePassword = "mykeystore";
187 keyAliasPassword = "myfirstapp";
188
189 # Any Android SDK parameters that install all the relevant plugins that a
190 # build requires
191 platformVersions = [ "24" ];
192
193 # When we include the NDK, then ndk-build is invoked before Ant gets invoked
194 includeNDK = true;
195}
196```
197
198Aside from the app-specific build parameters (`name`, `src`, `release` and
199keystore parameters), the `buildApp {}` function supports all the function
200parameters that the SDK composition function (the function shown in the
201previous section) supports.
202
203This build function is particularly useful when it is desired to use
204[Hydra](https://nixos.org/hydra): the Nix-based continuous integration solution
205to build Android apps. An Android APK gets exposed as a build product and can be
206installed on any Android device with a web browser by navigating to the build
207result page.
208
209## Spawning emulator instances {#spawning-emulator-instances}
210
211For testing purposes, it can also be quite convenient to automatically generate
212scripts that spawn emulator instances with all desired configuration settings.
213
214An emulator spawn script can be configured by invoking the `emulateApp {}`
215function:
216
217```nix
218with import <nixpkgs> {};
219
220androidenv.emulateApp {
221 name = "emulate-MyAndroidApp";
222 platformVersion = "28";
223 abiVersion = "x86"; # armeabi-v7a, mips, x86_64
224 systemImageType = "google_apis_playstore";
225}
226```
227
228Additional flags may be applied to the Android SDK's emulator through the runtime environment variable `$NIX_ANDROID_EMULATOR_FLAGS`.
229
230It is also possible to specify an APK to deploy inside the emulator
231and the package and activity names to launch it:
232
233```nix
234with import <nixpkgs> {};
235
236androidenv.emulateApp {
237 name = "emulate-MyAndroidApp";
238 platformVersion = "24";
239 abiVersion = "armeabi-v7a"; # mips, x86, x86_64
240 systemImageType = "default";
241 app = ./MyApp.apk;
242 package = "MyApp";
243 activity = "MainActivity";
244}
245```
246
247In addition to prebuilt APKs, you can also bind the APK parameter to a
248`buildApp {}` function invocation shown in the previous example.
249
250## Notes on environment variables in Android projects {#notes-on-environment-variables-in-android-projects}
251
252* `ANDROID_SDK_ROOT` should point to the Android SDK. In your Nix expressions, this should be
253 `${androidComposition.androidsdk}/libexec/android-sdk`. Note that `ANDROID_HOME` is deprecated,
254 but if you rely on tools that need it, you can export it too.
255* `ANDROID_NDK_ROOT` should point to the Android NDK, if you're doing NDK development.
256 In your Nix expressions, this should be `${ANDROID_SDK_ROOT}/ndk-bundle`.
257
258If you are running the Android Gradle plugin, you need to export GRADLE_OPTS to override aapt2
259to point to the aapt2 binary in the Nix store as well, or use a FHS environment so the packaged
260aapt2 can run. If you don't want to use a FHS environment, something like this should work:
261
262```nix
263let
264 buildToolsVersion = "30.0.3";
265
266 # Use buildToolsVersion when you define androidComposition
267 androidComposition = <...>;
268in
269pkgs.mkShell rec {
270 ANDROID_SDK_ROOT = "${androidComposition.androidsdk}/libexec/android-sdk";
271 ANDROID_NDK_ROOT = "${ANDROID_SDK_ROOT}/ndk-bundle";
272
273 # Use the same buildToolsVersion here
274 GRADLE_OPTS = "-Dorg.gradle.project.android.aapt2FromMavenOverride=${ANDROID_SDK_ROOT}/build-tools/${buildToolsVersion}/aapt2";
275}
276```
277
278If you are using cmake, you need to add it to PATH in a shell hook or FHS env profile.
279The path is suffixed with a build number, but properly prefixed with the version.
280So, something like this should suffice:
281
282```nix
283let
284 cmakeVersion = "3.10.2";
285
286 # Use cmakeVersion when you define androidComposition
287 androidComposition = <...>;
288in
289pkgs.mkShell rec {
290 ANDROID_SDK_ROOT = "${androidComposition.androidsdk}/libexec/android-sdk";
291 ANDROID_NDK_ROOT = "${ANDROID_SDK_ROOT}/ndk-bundle";
292
293 # Use the same cmakeVersion here
294 shellHook = ''
295 export PATH="$(echo "$ANDROID_SDK_ROOT/cmake/${cmakeVersion}".*/bin):$PATH"
296 '';
297}
298```
299
300Note that running Android Studio with ANDROID_SDK_ROOT set will automatically write a
301`local.properties` file with `sdk.dir` set to $ANDROID_SDK_ROOT if one does not already
302exist. If you are using the NDK as well, you may have to add `ndk.dir` to this file.
303
304An example shell.nix that does all this for you is provided in examples/shell.nix.
305This shell.nix includes a shell hook that overwrites local.properties with the correct
306sdk.dir and ndk.dir values. This will ensure that the SDK and NDK directories will
307both be correct when you run Android Studio inside nix-shell.
308
309## Notes on improving build.gradle compatibility {#notes-on-improving-build.gradle-compatibility}
310
311Ensure that your buildToolsVersion and ndkVersion match what is declared in androidenv.
312If you are using cmake, make sure its declared version is correct too.
313
314Otherwise, you may get cryptic errors from aapt2 and the Android Gradle plugin warning
315that it cannot install the build tools because the SDK directory is not writeable.
316
317```gradle
318android {
319 buildToolsVersion "30.0.3"
320 ndkVersion = "22.0.7026061"
321 externalNativeBuild {
322 cmake {
323 version "3.10.2"
324 }
325 }
326}
327
328```
329
330## Querying the available versions of each plugin {#querying-the-available-versions-of-each-plugin}
331
332repo.json provides all the options in one file now.
333
334A shell script in the `pkgs/development/mobile/androidenv/` subdirectory can be used to retrieve all
335possible options:
336
337```bash
338./querypackages.sh packages
339```
340
341The above command-line instruction queries all package versions in repo.json.
342
343## Updating the generated expressions {#updating-the-generated-expressions}
344
345repo.json is generated from XML files that the Android Studio package manager uses.
346To update the expressions run the `generate.sh` script that is stored in the
347`pkgs/development/mobile/androidenv/` subdirectory:
348
349```bash
350./generate.sh
351```