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