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