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