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