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
107repoXmls = {
108 packages = [ ./xml/repository2-1.xml ];
109 images = [
110 ./xml/android-sys-img2-1.xml
111 ./xml/android-tv-sys-img2-1.xml
112 ./xml/android-wear-sys-img2-1.xml
113 ./xml/android-wear-cn-sys-img2-1.xml
114 ./xml/google_apis-sys-img2-1.xml
115 ./xml/google_apis_playstore-sys-img2-1.xml
116 ];
117 addons = [ ./xml/addon2-1.xml ];
118};
119```
120
121When building the above expression with:
122
123```bash
124$ nix-build
125```
126
127The Android SDK gets deployed with all desired plugin versions.
128
129We can also deploy subsets of the Android SDK. For example, to only the
130`platform-tools` package, you can evaluate the following expression:
131
132```nix
133with import <nixpkgs> {};
134
135let
136 androidComposition = androidenv.composeAndroidPackages {
137 # ...
138 };
139in
140androidComposition.platform-tools
141```
142
143## Using predefined Android package compositions {#using-predefined-android-package-compositions}
144
145In addition to composing an Android package set manually, it is also possible
146to use a predefined composition that contains all basic packages for a specific
147Android version, such as version 9.0 (API-level 28).
148
149The following Nix expression can be used to deploy the entire SDK with all basic
150plugins:
151
152```nix
153with import <nixpkgs> {};
154
155androidenv.androidPkgs_9_0.androidsdk
156```
157
158It is also possible to use one plugin only:
159
160```nix
161with import <nixpkgs> {};
162
163androidenv.androidPkgs_9_0.platform-tools
164```
165
166## Building an Android application {#building-an-android-application}
167
168In addition to the SDK, it is also possible to build an Ant-based Android
169project and automatically deploy all the Android plugins that a project
170requires.
171
172
173```nix
174with import <nixpkgs> {};
175
176androidenv.buildApp {
177 name = "MyAndroidApp";
178 src = ./myappsources;
179 release = true;
180
181 # If release is set to true, you need to specify the following parameters
182 keyStore = ./keystore;
183 keyAlias = "myfirstapp";
184 keyStorePassword = "mykeystore";
185 keyAliasPassword = "myfirstapp";
186
187 # Any Android SDK parameters that install all the relevant plugins that a
188 # build requires
189 platformVersions = [ "24" ];
190
191 # When we include the NDK, then ndk-build is invoked before Ant gets invoked
192 includeNDK = true;
193}
194```
195
196Aside from the app-specific build parameters (`name`, `src`, `release` and
197keystore parameters), the `buildApp {}` function supports all the function
198parameters that the SDK composition function (the function shown in the
199previous section) supports.
200
201This build function is particularly useful when it is desired to use
202[Hydra](https://nixos.org/hydra): the Nix-based continuous integration solution
203to build Android apps. An Android APK gets exposed as a build product and can be
204installed on any Android device with a web browser by navigating to the build
205result page.
206
207## Spawning emulator instances {#spawning-emulator-instances}
208
209For testing purposes, it can also be quite convenient to automatically generate
210scripts that spawn emulator instances with all desired configuration settings.
211
212An emulator spawn script can be configured by invoking the `emulateApp {}`
213function:
214
215```nix
216with import <nixpkgs> {};
217
218androidenv.emulateApp {
219 name = "emulate-MyAndroidApp";
220 platformVersion = "28";
221 abiVersion = "x86"; # armeabi-v7a, mips, x86_64
222 systemImageType = "google_apis_playstore";
223}
224```
225
226Additional flags may be applied to the Android SDK's emulator through the runtime environment variable `$NIX_ANDROID_EMULATOR_FLAGS`.
227
228It is also possible to specify an APK to deploy inside the emulator
229and the package and activity names to launch it:
230
231```nix
232with import <nixpkgs> {};
233
234androidenv.emulateApp {
235 name = "emulate-MyAndroidApp";
236 platformVersion = "24";
237 abiVersion = "armeabi-v7a"; # mips, x86, x86_64
238 systemImageType = "default";
239 app = ./MyApp.apk;
240 package = "MyApp";
241 activity = "MainActivity";
242}
243```
244
245In addition to prebuilt APKs, you can also bind the APK parameter to a
246`buildApp {}` function invocation shown in the previous example.
247
248## Notes on environment variables in Android projects {#notes-on-environment-variables-in-android-projects}
249
250* `ANDROID_SDK_ROOT` should point to the Android SDK. In your Nix expressions, this should be
251 `${androidComposition.androidsdk}/libexec/android-sdk`. Note that `ANDROID_HOME` is deprecated,
252 but if you rely on tools that need it, you can export it too.
253* `ANDROID_NDK_ROOT` should point to the Android NDK, if you're doing NDK development.
254 In your Nix expressions, this should be `${ANDROID_SDK_ROOT}/ndk-bundle`.
255
256If you are running the Android Gradle plugin, you need to export GRADLE_OPTS to override aapt2
257to point to the aapt2 binary in the Nix store as well, or use a FHS environment so the packaged
258aapt2 can run. If you don't want to use a FHS environment, something like this should work:
259
260```nix
261let
262 buildToolsVersion = "30.0.3";
263
264 # Use buildToolsVersion when you define androidComposition
265 androidComposition = <...>;
266in
267pkgs.mkShell rec {
268 ANDROID_SDK_ROOT = "${androidComposition.androidsdk}/libexec/android-sdk";
269 ANDROID_NDK_ROOT = "${ANDROID_SDK_ROOT}/ndk-bundle";
270
271 # Use the same buildToolsVersion here
272 GRADLE_OPTS = "-Dorg.gradle.project.android.aapt2FromMavenOverride=${ANDROID_SDK_ROOT}/build-tools/${buildToolsVersion}/aapt2";
273}
274```
275
276If you are using cmake, you need to add it to PATH in a shell hook or FHS env profile.
277The path is suffixed with a build number, but properly prefixed with the version.
278So, something like this should suffice:
279
280```nix
281let
282 cmakeVersion = "3.10.2";
283
284 # Use cmakeVersion when you define androidComposition
285 androidComposition = <...>;
286in
287pkgs.mkShell rec {
288 ANDROID_SDK_ROOT = "${androidComposition.androidsdk}/libexec/android-sdk";
289 ANDROID_NDK_ROOT = "${ANDROID_SDK_ROOT}/ndk-bundle";
290
291 # Use the same cmakeVersion here
292 shellHook = ''
293 export PATH="$(echo "$ANDROID_SDK_ROOT/cmake/${cmakeVersion}".*/bin):$PATH"
294 '';
295}
296```
297
298Note that running Android Studio with ANDROID_SDK_ROOT set will automatically write a
299`local.properties` file with `sdk.dir` set to $ANDROID_SDK_ROOT if one does not already
300exist. If you are using the NDK as well, you may have to add `ndk.dir` to this file.
301
302An example shell.nix that does all this for you is provided in examples/shell.nix.
303This shell.nix includes a shell hook that overwrites local.properties with the correct
304sdk.dir and ndk.dir values. This will ensure that the SDK and NDK directories will
305both be correct when you run Android Studio inside nix-shell.
306
307## Notes on improving build.gradle compatibility {#notes-on-improving-build.gradle-compatibility}
308
309Ensure that your buildToolsVersion and ndkVersion match what is declared in androidenv.
310If you are using cmake, make sure its declared version is correct too.
311
312Otherwise, you may get cryptic errors from aapt2 and the Android Gradle plugin warning
313that it cannot install the build tools because the SDK directory is not writeable.
314
315```gradle
316android {
317 buildToolsVersion "30.0.3"
318 ndkVersion = "22.0.7026061"
319 externalNativeBuild {
320 cmake {
321 version "3.10.2"
322 }
323 }
324}
325
326```
327
328## Querying the available versions of each plugin {#querying-the-available-versions-of-each-plugin}
329
330repo.json provides all the options in one file now.
331
332A shell script in the `pkgs/development/mobile/androidenv/` subdirectory can be used to retrieve all
333possible options:
334
335```bash
336./querypackages.sh packages
337```
338
339The above command-line instruction queries all package versions in repo.json.
340
341## Updating the generated expressions {#updating-the-generated-expressions}
342
343repo.json is generated from XML files that the Android Studio package manager uses.
344To update the expressions run the `generate.sh` script that is stored in the
345`pkgs/development/mobile/androidenv/` subdirectory:
346
347```bash
348./generate.sh
349```