Suckless Android SDK setup
Saturday, 27 May 2023 / last updated: Sunday, 26 May 2024
Android SDK is one of the first things I set up on a new computer. This post is a reference for future me and for anyone who wants to do it right and learn something along the way.
This post is for you if you:
- need Android SDK, but don’t want to install the bulky Android Studio
- want to know more about what Android SDK provides and have a rough idea of its structure
Preface and rant
Why am I writing this post? Surely there are official guides on installing Android SDK?
Well, I think that the official, recommended way of downloading Android SDK sucks. More specifically, telling everyone to install Android Studio sucks.
I’m under the impression that the official docs are optimized for the lowest common denominator type of person. That’s not a bad thing when you’re just getting started with Android development, but after doing the setup of SDK a few times, I want to know more about what I am doing and why I am doing it. And that’s what the official docs fall short of.
Another problems appears when building on CI. The more popular ones have some kind of pre-built “Set up Android SDK” step, but it’s not always the case. And you won’t install Android Studio on a CI server, right. Right?
I also strongly believe that everyone should know a thing or two about the tools they’re depending on every day.
Basics
Install Java Development Kit
On macOS, I prefer to use the OpenJDK distribution provided by Homebrew, but other ones (like Eclipse Temurin) are also fine:
brew install openjdk
Unless you have valid reasons not to, you should the latest JDK.
Here’s a great post from Jake Wharton that explains this in much more detail. Go read it!
Then, set JAVA_HOME and add the binaries to PATH. To do it, open your
~/.bashrc, ~/.zshrc, or whateverrc you use and add:
export JAVA_HOME="/Library/Java/JavaVirtualMachines/openjdk.jdk/Contents/Home"
export PATH="$JAVA_HOME/bin:$PATH"
Install core command-line tools
The official, recommended way to get Android SDK is to simply download Android
Studio from developer.android.com/studio. (You see? There’s no /download,
there’s /studio! They’re trying so hard to shove Android Studio down our
throats! /s). I don’t like installing Android Studio because it’s heavy and
because I already have IntelliJ IDEA installed. Why should I bother installing
something I won’t use?
The latest version
So on that page, instead of clicking “Download Android Studio”, scroll down and
find the “Command line tools only” section and then download the variant for
your OS. Alternatively, you can use curl:
$ curl -fsSL \
--output-dir ~ \
--output android-clt.zip \
https://dl.google.com/android/repository/commandlinetools-mac-9477386_latest.zip
To make things consistent, let’s assume we download this zip into the
Downloadsdirectory:$ cd ~/Downloads
A specific version
That weird number in the filename determines the version of command-line tools, though I have no idea what logic lies behind the way it’s generated. The list of all versions of command-line tools to download is also nowhere to be found, so once summer evening I decided to figure it out – see this StackOverflow question.
What’s inside
Now extract the downloaded archive:
$ unzip commandlinetools-*.zip
Extracting the zip created the cmdline-tools directory. Let’s see what
executable binaries it contains:
$ ls -1 cmdline-tools/bin
apkanalyzer
avdmanager
lint
profgen
retrace
screenshot2
sdkmanager
The program that is most interesting to us now is sdkmanager, which allows for
downloading additional Android SDK components. But before doing that, let’s move
the cmdline-tools directory into the right place.
Let’s put this extracted directory into ~/Downloads, so that we’ll be able to
find it at ~/Downloads/cmdline-tools.
First, create a place where Android SDK will be located. In my case, it’s always
~/androidsdk, because that’s where I like having it.
$ mkdir ~/androidsdk
Then create a directory for the command-line tools:
$ mkdir -p ~/androidsdk/cmdline-tools/latest
Now we’re ready to copy the contents of the cmdline-tools directory into the
final location:
$ cp -r ~/Downloads/cmdline-tools/* ~/androidsdk/cmdline-tools/latest
The reason why I’m using latest is that you might want to install other
versions of the command line tools. Google recommends doing it this way.
Modify PATH
Finally, you want to add the path where command-line tools live to PATH, and
also export 2 environment variables. Open ~/.zshrc and add these lines:
export ANDROID_HOME="$HOME/androidsdk" # sdk lives here
export ANDROID_USER_HOME="$HOME/.android" # config and tmp files live here
export PATH="$ANDROID_HOME/cmdline-tools/latest/bin:$PATH"
ANDROID_HOME and ANDROID_USER_HOME variables are used by other tools, such
as Android Studio and flutter CLI. When they’re not defined, those tools often
try to guess other common locations. I think it’s a good practice to define them
explicitly.
Reload the shell to apply these changes. For example, if you happen to be using
zsh, run exec zsh.
To learn more about the environment variables used by Android SDK, see this page.
More advanced stuff
At this point, you’ve got the basics done. You should be able to go to your app
project and run ./gradlew :app:assembleDebug, or flutter build apk, or
similar, and it should just work. If you’re in hurry, you can stop reading
here!
The first build will take quite a long time, and if you observe the logs carefully, you’ll notice that Gradle downloads a bunch of stuff. In the rest of this post, I’ll take a closer look at what exactly is being downloaded, and what’s the purpose of each component.
Install more tools with sdkmanager
Now you’ve got yourself a few command-line tools. But that’s about it. You still don’t have any build tools (compilers, resource mergers, shrinkers, that sort of stuff), system images, and even an emulator.
To get them, you use
sdkmanager. It’s
part of the cmdline-tools zip we’ve just downloaded and it lets you install
everything you might need in your Android development journey. It’s located in
~/androidsdk/cmdline-tools/latest/bin. BTW, from now on, I’ll use
$ANDROID_HOME instead of ~/androidsdk now that it’s set.
Now let’s run sdkmanager again and download stuff that is always needed.
A useful command to remember sdkmanager --list_installed. Much faster than
opening up the GUI of SDK manager in Android Studio.
Emulator
It’s not necessary to build apps, but most people use it. Let’s install it:
$ sdkmanager --install 'emulator'
This will install a bunch of stuff, including the emulator binary, under
$ANDROID_HOME/emulator. Let’s add that directory to PATH so we’ll be able to
run emulator from anywhere. Open .zshrc and append:
export PATH="$ANDROID_HOME/emulator:$PATH"
System images
System images are only needed if you plan to use the emulator. You’ll save a few gigs of disk space by not downloading them.
I’m on MacBook powered by Apple Silicon, so I download arm64-v8 variants:
$ sdkmanager --install 'system-images;android-33;google_apis;arm64-v8'
If you’re on a more classic PC box, you’ll likely want to replace arm64-v8
with x86_64.
And to download the same system image, but with Play Store and a few more Google apps installed:
$ sdkmanager --install 'system-images;android-33;google_apis_playstore;arm64-v8'
Build tools
To build apps, you need build tools. By default, Android Gradle Plugin (AGP) takes care of downloading the right version of build tools, so you usually don’t have to care about them, but if you’re curious, read on.
As everything else in Android SDK, build tools are installed using sdkmanager
(That’s what AGP does under the hood as well):
$ sdkmanager --install 'build-tools;33.0.2'
After the installation completes, this particular build tools version can be
found under $ANDROID_HOME/build-tools/33.0.2. Some of the most important
executables in that directory are:
d8, which compiles.classfiles (Java bytecode) to.dexfiles (Dalvik Executables) that Android Runtime can executeaapt2, which merges all the resources (such asxmlfiles asd graphics assets) so that they can be packaged into an APKapksignerwhich, unsurprisingly, signs APK files
There are many build tools, but each one of them does one thing and does it well. They’re invoked by the build system (usually it’s Android Gradle Plugin who calls them) and few people use them directly (unless they’re something less common, such as integrating with an alternative build system). If you’d like to learn more about the build tools, head over here.
Adding build tools binaries to PATH is a bit more involved, because there are
often many versions of them under $ANDROID_HOME/build-tools. Here’s what I
have in my ~/.zshrc to automatically export the latest version:
if [ -d "$ANDROID_HOME/build-tools" ]; then
build_tools=$(
command ls "$ANDROID_HOME/build-tools" |
sort --version-sort --reverse |
head -n 1
)
export PATH="$ANDROID_HOME/build-tools/$build_tools:$PATH"
fi
Platform tools
(AGP handles these automatically, but we’re not interested in that right now)
Platform tools let you interact with a running Android device, either physical or virtual.
$ sdkmanager --install 'platform-tools'
After the installation completes, platform tools can be found under
$ANDROID_HOME/platform-tools. Again, let’s add that directory to PATH:
export PATH="$ANDROID_HOME/platform-tools:$PATH"
The most famous binary inside platform-tools is definitely adb. If you’ve
been into custom ROMs at some point, you might’ve also heard of fastboot.
Platforms
(AGP handles these automatically, but we’re not interested in that right now)
First, let’s get installation out of our way:
$ sdkmanager --install 'platforms;android-33'
Unsurprisingly, platform android-33 will be installed under
$ANDROID_HOME/platforms.
But what are platforms?
A “platform” includes the source code of classes that are part of the OS, so
that IDEs can show the code when you navigate to a symbol from the android
namespace, for example Context or Bundle.
The packages from the android top-level namespace in the beginning aren’t
built into the APK. They’re only placed on the compile classpath, but that’s it.
The real implementation is provided by the OS itself. To illustrate this, let’s
consider this Java file:
import android.content.Context;
import android.content.Intent;
import android.graphics.Color;
import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity;
public class MainActivity extends AppCompatActivity {
// ...
}
The packages starting with android are implemented in the OS and made
available to your app at runtime. On the other hand, the androidx packages are
“extra” and they are bundled into the APK. It’s easy to verify that yourself by
running apkanalyzer (from cmdline-tools) on the APK.
./gradlew :app:assembleDebug
cd app/build/outputs/apk/debug
apkanalyzer dex packages app-debug.apk --defined-only | grep '^C' # only classes
There’ll be lots of classes whose namespace starts with androidx namespace,
but (almost) none of them will be from the android
namespace.
Obsolete tools
Some obsolete tools, such as uiautomatorviewer, can be installed with:
$ sdkmanager --install 'tools'
It will be installed under $ANDROID_HOME/tools.
To see if it’s installed, run:
$ sdkmanager --list_installed --include_obsolete
<omitted other packages>
Installed Obsolete Packages:
Path | Version | Description | Location
------- | ------- | ------- | -------
tools | 26.1.1 | Android SDK Tools | tools
Summary
And that’s it for this article. Before we part, here’s a shell script for me in the future to quickly install what I need:
sdkmanager --install 'emulator'
sdkmanager --install 'sources;android-34'
sdkmanager --install 'system-images;android-33;google_apis;arm64-v8a'
sdkmanager --install 'system-images;android-33;google_apis_playstore;arm64-v8a'
sdkmanager --install 'system-images;android-34;google_apis;arm64-v8a'
sdkmanager --install 'system-images;android-34;google_apis_playstore;arm64-v8a'
sdkmanager --install 'platform-tools'
sdkmanager --install 'platforms;android-34'
Last thing: here’s my own shell config file, from where you can easily copy the PATH-related commands. Be inspired by it! (or just copy-paste)
Now you’ve got everything set up, and hopefully you’ve also learned something about the SDK’s structure. You can go to your Android app project and start building it.