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