about summary refs log tree commit diff
path: root/doc/languages-frameworks/android.section.md
blob: 6f9717ca09cca5319fa761e3f93a05a9baa3e3d3 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
# Android {#android}

The Android build environment provides three major features and a number of
supporting features.

## Deploying an Android SDK installation with plugins {#deploying-an-android-sdk-installation-with-plugins}

The first use case is deploying the SDK with a desired set of plugins or subsets
of an SDK.

```nix
with import <nixpkgs> {};

let
  androidComposition = androidenv.composeAndroidPackages {
    cmdLineToolsVersion = "8.0";
    toolsVersion = "26.1.1";
    platformToolsVersion = "30.0.5";
    buildToolsVersions = [ "30.0.3" ];
    includeEmulator = false;
    emulatorVersion = "30.3.4";
    platformVersions = [ "28" "29" "30" ];
    includeSources = false;
    includeSystemImages = false;
    systemImageTypes = [ "google_apis_playstore" ];
    abiVersions = [ "armeabi-v7a" "arm64-v8a" ];
    cmakeVersions = [ "3.10.2" ];
    includeNDK = true;
    ndkVersions = ["22.0.7026061"];
    useGoogleAPIs = false;
    useGoogleTVAddOns = false;
    includeExtras = [
      "extras;google;gcm"
    ];
  };
in
androidComposition.androidsdk
```

The above function invocation states that we want an Android SDK with the above
specified plugin versions. By default, most plugins are disabled. Notable
exceptions are the tools, platform-tools and build-tools sub packages.

The following parameters are supported:

* `cmdLineToolsVersion `, specifies the version of the `cmdline-tools` package to use
* `toolsVersion`, specifies the version of the `tools` package. Notice `tools` is
  obsolete, and currently only `26.1.1` is available, so there's not a lot of
  options here, however, you can set it as `null` if you don't want it.
* `platformsToolsVersion` specifies the version of the `platform-tools` plugin
* `buildToolsVersions` specifies the versions of the `build-tools` plugins to
  use.
* `includeEmulator` specifies whether to deploy the emulator package (`false`
  by default). When enabled, the version of the emulator to deploy can be
  specified by setting the `emulatorVersion` parameter.
* `cmakeVersions` specifies which CMake versions should be deployed.
* `includeNDK` specifies that the Android NDK bundle should be included.
  Defaults to: `false`.
* `ndkVersions` specifies the NDK versions that we want to use. These are linked
  under the `ndk` directory of the SDK root, and the first is linked under the
  `ndk-bundle` directory.
* `ndkVersion` is equivalent to specifying one entry in `ndkVersions`, and
  `ndkVersions` overrides this parameter if provided.
* `includeExtras` is an array of identifier strings referring to arbitrary
  add-on packages that should be installed.
* `platformVersions` specifies which platform SDK versions should be included.

For each platform version that has been specified, we can apply the following
options:

* `includeSystemImages` specifies whether a system image for each platform SDK
  should be included.
* `includeSources` specifies whether the sources for each SDK version should be
  included.
* `useGoogleAPIs` specifies that for each selected platform version the
  Google API should be included.
* `useGoogleTVAddOns` specifies that for each selected platform version the
  Google TV add-on should be included.

For each requested system image we can specify the following options:

* `systemImageTypes` specifies what kind of system images should be included.
  Defaults to: `default`.
* `abiVersions` specifies what kind of ABI version of each system image should
  be included. Defaults to: `armeabi-v7a`.

Most of the function arguments have reasonable default settings.

You can specify license names:

* `extraLicenses` is a list of license names.
  You can get these names from repo.json or `querypackages.sh licenses`. The SDK
  license (`android-sdk-license`) is accepted for you if you set accept_license
  to true. If you are doing something like working with preview SDKs, you will
  want to add `android-sdk-preview-license` or whichever license applies here.

Additionally, you can override the repositories that composeAndroidPackages will
pull from:

* `repoJson` specifies a path to a generated repo.json file. You can generate this
  by running `generate.sh`, which in turn will call into `mkrepo.rb`.
* `repoXmls` is an attribute set containing paths to repo XML files. If specified,
  it takes priority over `repoJson`, and will trigger a local build writing out a
  repo.json to the Nix store based on the given repository XMLs.

```nix
repoXmls = {
  packages = [ ./xml/repository2-1.xml ];
  images = [
    ./xml/android-sys-img2-1.xml
    ./xml/android-tv-sys-img2-1.xml
    ./xml/android-wear-sys-img2-1.xml
    ./xml/android-wear-cn-sys-img2-1.xml
    ./xml/google_apis-sys-img2-1.xml
    ./xml/google_apis_playstore-sys-img2-1.xml
  ];
  addons = [ ./xml/addon2-1.xml ];
};
```

When building the above expression with:

```bash
$ nix-build
```

The Android SDK gets deployed with all desired plugin versions.

We can also deploy subsets of the Android SDK. For example, to only the
`platform-tools` package, you can evaluate the following expression:

```nix
with import <nixpkgs> {};

let
  androidComposition = androidenv.composeAndroidPackages {
    # ...
  };
in
androidComposition.platform-tools
```

## Using predefined Android package compositions {#using-predefined-android-package-compositions}

In addition to composing an Android package set manually, it is also possible
to use a predefined composition that contains all basic packages for a specific
Android version, such as version 9.0 (API-level 28).

The following Nix expression can be used to deploy the entire SDK with all basic
plugins:

```nix
with import <nixpkgs> {};

androidenv.androidPkgs_9_0.androidsdk
```

It is also possible to use one plugin only:

```nix
with import <nixpkgs> {};

androidenv.androidPkgs_9_0.platform-tools
```

## Building an Android application {#building-an-android-application}

In addition to the SDK, it is also possible to build an Ant-based Android
project and automatically deploy all the Android plugins that a project
requires.


```nix
with import <nixpkgs> {};

androidenv.buildApp {
  name = "MyAndroidApp";
  src = ./myappsources;
  release = true;

  # If release is set to true, you need to specify the following parameters
  keyStore = ./keystore;
  keyAlias = "myfirstapp";
  keyStorePassword = "mykeystore";
  keyAliasPassword = "myfirstapp";

  # Any Android SDK parameters that install all the relevant plugins that a
  # build requires
  platformVersions = [ "24" ];

  # When we include the NDK, then ndk-build is invoked before Ant gets invoked
  includeNDK = true;
}
```

Aside from the app-specific build parameters (`name`, `src`, `release` and
keystore parameters), the `buildApp {}` function supports all the function
parameters that the SDK composition function (the function shown in the
previous section) supports.

This build function is particularly useful when it is desired to use
[Hydra](https://nixos.org/hydra): the Nix-based continuous integration solution
to build Android apps. An Android APK gets exposed as a build product and can be
installed on any Android device with a web browser by navigating to the build
result page.

## Spawning emulator instances {#spawning-emulator-instances}

For testing purposes, it can also be quite convenient to automatically generate
scripts that spawn emulator instances with all desired configuration settings.

An emulator spawn script can be configured by invoking the `emulateApp {}`
function:

```nix
with import <nixpkgs> {};

androidenv.emulateApp {
  name = "emulate-MyAndroidApp";
  platformVersion = "28";
  abiVersion = "x86"; # armeabi-v7a, mips, x86_64
  systemImageType = "google_apis_playstore";
}
```

Additional flags may be applied to the Android SDK's emulator through the runtime environment variable `$NIX_ANDROID_EMULATOR_FLAGS`.

It is also possible to specify an APK to deploy inside the emulator
and the package and activity names to launch it:

```nix
with import <nixpkgs> {};

androidenv.emulateApp {
  name = "emulate-MyAndroidApp";
  platformVersion = "24";
  abiVersion = "armeabi-v7a"; # mips, x86, x86_64
  systemImageType = "default";
  app = ./MyApp.apk;
  package = "MyApp";
  activity = "MainActivity";
}
```

In addition to prebuilt APKs, you can also bind the APK parameter to a
`buildApp {}` function invocation shown in the previous example.

## Notes on environment variables in Android projects {#notes-on-environment-variables-in-android-projects}

* `ANDROID_SDK_ROOT` should point to the Android SDK. In your Nix expressions, this should be
  `${androidComposition.androidsdk}/libexec/android-sdk`. Note that `ANDROID_HOME` is deprecated,
  but if you rely on tools that need it, you can export it too.
* `ANDROID_NDK_ROOT` should point to the Android NDK, if you're doing NDK development.
  In your Nix expressions, this should be `${ANDROID_SDK_ROOT}/ndk-bundle`.

If you are running the Android Gradle plugin, you need to export GRADLE_OPTS to override aapt2
to point to the aapt2 binary in the Nix store as well, or use a FHS environment so the packaged
aapt2 can run. If you don't want to use a FHS environment, something like this should work:

```nix
let
  buildToolsVersion = "30.0.3";

  # Use buildToolsVersion when you define androidComposition
  androidComposition = <...>;
in
pkgs.mkShell rec {
  ANDROID_SDK_ROOT = "${androidComposition.androidsdk}/libexec/android-sdk";
  ANDROID_NDK_ROOT = "${ANDROID_SDK_ROOT}/ndk-bundle";

  # Use the same buildToolsVersion here
  GRADLE_OPTS = "-Dorg.gradle.project.android.aapt2FromMavenOverride=${ANDROID_SDK_ROOT}/build-tools/${buildToolsVersion}/aapt2";
}
```

If you are using cmake, you need to add it to PATH in a shell hook or FHS env profile.
The path is suffixed with a build number, but properly prefixed with the version.
So, something like this should suffice:

```nix
let
  cmakeVersion = "3.10.2";

  # Use cmakeVersion when you define androidComposition
  androidComposition = <...>;
in
pkgs.mkShell rec {
  ANDROID_SDK_ROOT = "${androidComposition.androidsdk}/libexec/android-sdk";
  ANDROID_NDK_ROOT = "${ANDROID_SDK_ROOT}/ndk-bundle";

  # Use the same cmakeVersion here
  shellHook = ''
    export PATH="$(echo "$ANDROID_SDK_ROOT/cmake/${cmakeVersion}".*/bin):$PATH"
  '';
}
```

Note that running Android Studio with ANDROID_SDK_ROOT set will automatically write a
`local.properties` file with `sdk.dir` set to $ANDROID_SDK_ROOT if one does not already
exist. If you are using the NDK as well, you may have to add `ndk.dir` to this file.

An example shell.nix that does all this for you is provided in examples/shell.nix.
This shell.nix includes a shell hook that overwrites local.properties with the correct
sdk.dir and ndk.dir values. This will ensure that the SDK and NDK directories will
both be correct when you run Android Studio inside nix-shell.

## Notes on improving build.gradle compatibility {#notes-on-improving-build.gradle-compatibility}

Ensure that your buildToolsVersion and ndkVersion match what is declared in androidenv.
If you are using cmake, make sure its declared version is correct too.

Otherwise, you may get cryptic errors from aapt2 and the Android Gradle plugin warning
that it cannot install the build tools because the SDK directory is not writeable.

```gradle
android {
    buildToolsVersion "30.0.3"
    ndkVersion = "22.0.7026061"
    externalNativeBuild {
        cmake {
            version "3.10.2"
        }
    }
}

```

## Querying the available versions of each plugin {#querying-the-available-versions-of-each-plugin}

repo.json provides all the options in one file now.

A shell script in the `pkgs/development/mobile/androidenv/` subdirectory can be used to retrieve all
possible options:

```bash
./querypackages.sh packages
```

The above command-line instruction queries all package versions in repo.json.

## Updating the generated expressions {#updating-the-generated-expressions}

repo.json is generated from XML files that the Android Studio package manager uses.
To update the expressions run the `generate.sh` script that is stored in the
`pkgs/development/mobile/androidenv/` subdirectory:

```bash
./generate.sh
```