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