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