DEV Community

Lunar
Lunar

Posted on

Using mise to install dependencies in Android development

There is a large and complex Gradle build system and the Android Gradle Plugin (AGP) to install most of the Android SDK components required for your application. But what if you don't want to manually install Android Studio, Android SDK, CMake, scrcpy, and other necessary tools? This is where mise https://mise.jdx.dev/ comes in—despite its apparent simplicity, it can do everything we need.

Installing mise itself

By default, the documentation suggests the following installation method:

curl https://mise.run | sh
Enter fullscreen mode Exit fullscreen mode

For those who do not like this installation method, alternative options are available: https://mise.jdx.dev/installing-mise.html

You will also need to activate mise in your shell, which allows mise to function similarly to direnv. I have not tested the instructions in this article without this one-time activation.

For bash:

echo 'eval "$(mise activate bash)"' >> ~/.bashrc
Enter fullscreen mode Exit fullscreen mode

For fish:

echo 'mise activate fish | source' >> ~/.config/fish/config.fish
Enter fullscreen mode Exit fullscreen mode

For zsh:

echo 'eval "$(mise activate zsh)"' >> "${ZDOTDIR-$HOME}/.zshrc"
Enter fullscreen mode Exit fullscreen mode

And don't forget to restart your terminal for these settings to take effect.

Basic Capabilities

If desired, mise allows you to install software globally; the list of available packages can be checked with the mise registry command.

mise use -g bun deno go java gradle
Enter fullscreen mode Exit fullscreen mode

But let's not dwell on the basics. How can we use mise to simply download my project—let's say https://github.com/lunardoesdev/raytris—and build it for Android, without having anything on our system other than mise itself? Let's clone the project (if you don't have git, you can just download the archive from GitHub's website):

satori@fedora ~ [1]> git clone --depth=1 'https://github.com/lunardoesdev/raytris'
Cloning into 'raytris'...
remote: Enumerating objects: 33, done.
remote: Counting objects: 100% (33/33), done.
remote: Compressing objects: 100% (24/24), done.
remote: Total 33 (delta 0), reused 27 (delta 0), pack-reused 0 (from 0)
Receiving objects: 100% (33/33), 1.39 MiB | 1.02 MiB/s, done.
satori@fedora ~> cd raytris/
mise ERROR error parsing config file: ~/raytris/mise.toml
mise ERROR Config files in ~/raytris/mise.toml are not trusted.
Trust them with `mise trust`. See https://mise.en.dev/cli/trust.html for more information.
mise ERROR Version: 2026.7.2 linux-x64 (2026-07-07)
mise ERROR Run with --verbose or MISE_VERBOSE=1 for more information
Enter fullscreen mode Exit fullscreen mode

mise warns that it will not automatically install dependencies and add them to your PATH when entering the directory without your permission, which you grant using the mise trust command. After running this command, you can immediately run the mise apk task defined in my mise.toml and build the APK! Yes, it's that simple.

Breakdown of the Reproducible Environment

Let's look at the mise.toml itself (below, I will show snippets from this file and explain what they do):

[tools]
android-sdk = "latest"
"github:Genymobile/scrcpy" = "4.0"
"github:cesarferreira/byedroid" = "0.9.0"
gradle = "9.6.1"
java = "26.0.1"
zig = "0.15.1"

[env]
_.path = {tools = true, path = [
 "${ANDROID_HOME}/platform-tools",
 "${ANDROID_HOME}/build-tools/36.0.0",
 ]}
CPM_SOURCE_CACHE = "${HOME}/.cache/cpm-source-cache"

[settings]
env_shell_expand = true

[tasks.accept-android-licenses]
sources = ['settings.gradle.kts']
run = """
  yes | sdkmanager --licenses
  yes | sdkmanager "cmake;4.1.2"
  yes | sdkmanager "platform-tools"
"""

[tasks.debug-apk]
depends = ["accept-android-licenses"]
sources = [
  'build.gradle.kts',
  'gradle.properties',
  'src/**',
  'settings.gradle.kts',
  'android-sdk-packages.txt',
  'CMakeLists.txt'
]
run = "gradle assembleDebug"
alias = "apk"

[tasks.debug-native]
sources = [
  'src/**/*',
  '*.txt'
]
run = """
  mkdir -p build/debug
  cd build/debug
  cmake ../..
  make
"""

[tasks.debug]
depends = ['debug-native']
run = '''
  ./build/debug/raytris
'''
alias = 'debug'

[tasks.build-windows]
sources = [
  'src/**',
  '*.txt'
]
run = '''
  mkdir -p build/windows
  cd build/windows
  cmake -DCMAKE_TOOLCHAIN_FILE=cmake/zig-toolchain.cmake \
   -DZIG_TARGET=x86_64-windows \
   ../..
  make
'''
Enter fullscreen mode Exit fullscreen mode

Let's go in order. The [tools] section describes the packages that mise will install.

[tools]
android-sdk = "latest"
"github:Genymobile/scrcpy" = "4.0"
"github:cesarferreira/byedroid" = "0.9.0"
gradle = "9.6.1"
java = "26.0.1"
zig = "0.15.1"
Enter fullscreen mode Exit fullscreen mode

Note that you can install not only packages defined in the mise registry, but also download them directly from GitHub releases. For example, you can globally install a decent build system like xmake like this:

mise use -g github:xmake-io/xmake[rename_exe=xmake]
Enter fullscreen mode Exit fullscreen mode

You can read about rename_exe and other options and their values on the mise website, for example, for their GitHub "backend": https://mise.jdx.dev/dev-tools/backends/github.html#rename-exe

Next is [env].

[env]
_.path = {tools = true, path = [
 "${ANDROID_HOME}/platform-tools",
 "${ANDROID_HOME}/build-tools/36.0.0",
 ]}
CPM_SOURCE_CACHE = "${HOME}/.cache/cpm-source-cache"
Enter fullscreen mode Exit fullscreen mode

_.path is a special way to override the PATH. tools = true means we first install the tools from the [tools] section and then override this variable. $ANDROID_HOME is defined by the android-sdk package; you don't need to do this manually.

CPM_SOURCE_CACHE is a variable for CMake CPM, a package manager for the CMake build system that I use to install raylib in my project. It prevents downloading the sources over and over again if you delete the build directory or build in different locations for different platforms, as I do.

Moving on. The [settings] section.

[settings]
env_shell_expand = true
Enter fullscreen mode Exit fullscreen mode

env_shell_expand allows you to do things like this in [env]:

[env]
FOO = "hello"
BAR = "$FOO-world"        # "hello-world"
BAZ = "${FOO}_suffix"     # "hello_suffix"
QUX = "${UNDEF:-fallback}" # "fallback"
Enter fullscreen mode Exit fullscreen mode

That is, our environment variables are expanded to their values... which is exactly how it should be, in my opinion.

Next is the [tasks] section, where we define tasks, their file dependencies, and task dependencies. mise is a powerful task runner with many options for tasks. If you're interested, check out the available options in its documentation: https://mise.jdx.dev/tasks/

[tasks.accept-android-licenses]
sources = ['settings.gradle.kts']
run = """
  yes | sdkmanager --licenses
  yes | sdkmanager "cmake;4.1.2"
  yes | sdkmanager "platform-tools"
"""
Enter fullscreen mode Exit fullscreen mode

Here, in the accept-android-licenses task, we accept SDK component licenses and install the components we need, which Gradle does not always install reliably. In this example, notice that I use a specific version of CMake, which is also specified in my Gradle files. This ensures that exact version is used, as I had issues with CPM or raylib when building with an older version of CMake (which is installed if you simply choose "cmake" instead of "cmake;4.1.2"). It took some trial and error, but in the end, the system installs the required CMake version, and Gradle picks it up even if other CMake versions are installed. I added that this task depends on the settings.gradle.kts file so that it doesn't re-run on every build.

And here is the task responsible for the mise apk command:

[tasks.debug-apk]
depends = ["accept-android-licenses"]
sources = [
  'build.gradle.kts',
  'gradle.properties',
  'src/**',
  'settings.gradle.kts',
  'android-sdk-packages.txt',
  'CMakeLists.txt'
]
run = "gradle assembleDebug"
alias = "apk"
Enter fullscreen mode Exit fullscreen mode

It depends on the previous task and builds the APK using Gradle. I am not entirely sure about src/**—the correct glob syntax might be src/**/*—but overall, the build works for me.

The alias = "apk" allows us to run our debug-apk task simply as mise apk. Note that you should not create aliases named "run" or "watch", as they conflict with mise's own subcommands.

Next, tasks for native builds, running the native game, and building for Windows are defined in a similar manner. There are no new documentation elements here, but you can appreciate the elegance of this solution, which builds a single codebase for different operating systems.

mise is a great tool; I really enjoyed working with it. Best regards.

Top comments (0)