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