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