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