Build for Android

Compile and deploy the applications to Android devices

Build the Android applications (Agent, Hub, Remote) with kiln, install them on a device and start them. This guide covers both Android targets:

  • arm64-v8a, which OctoMY™ ships for today: modern 64-bit Android phones, Android 9+, which is every device shipped since around 2020, including budget and rugged industrial tiers.
  • x86_64, the second Android target. It builds, and the hub runs on the API 35 emulator. Device tests and releases wait until we have x86_64 Android hardware. It is postponed, not dropped.

32-bit ARM (armv7 / armeabi-v7a) is a deliberate, permanent non-target. See the Android architecture support note below.

kiln is the only Android path on a development machine. It makes the package in its own process with the SDK's tools. There is no Gradle, and kiln does not use qbs's Android module. The qbs android-arm64 profile stays for the build farm, which patches its own qbs.


Prerequisites

Install the following before you build:

Component Version Notes
Qt for Android see integration/toolchain-requirements.json (qt.minimum) android_arm64_v8a, and android_x86_64 for the emulator. Not needed with the vendored Qt, see Without a Qt Android kit
Android SDK API 35+ Platform tools (adb), build tools and platforms/android-35
Android NDK r26 / r27+ r26.1.10909125 works; r28+ gains 16 KB page support
JDK 17+ javac and java on the path
Android OpenSSL ssl_3 The NDK does not ship OpenSSL. The root .kiln names its folder per ABI
kiln this tree See Build through the kiln queue

One-time setup

Tell kiln where the SDK, the NDK and the Qt Android kit are. These are machine settings, so they go in .kiln.local in the checkout root:

[os=android]
android.sdk = /home/me/Android/Sdk
android.ndk = /home/me/Android/Sdk/ndk/26.1.10909125
[os=android arch=arm64]
qt.qmake = /home/me/Qt/6.10.1/android_arm64_v8a/bin/qmake6
[os=android arch=x64]
qt.qmake = /home/me/Qt/6.10.1/android_x86_64/bin/qmake6

If adb devices lists more than one device, add android.device = <serial>. The kiln reference lists every android.* key.

Without a Qt Android kit

kiln can also build Qt for Android itself, from the pinned source, so you need no Qt for Android from Qt's installer. This is the vendored Qt of Build without a Qt installation, built for the device. You still need the SDK, the NDK, the JDK and Android OpenSSL from the table above.

  1. Say so in .kiln.local, and leave out the qt.qmake lines of the Android sections:

    qt.vendored.build = on
    qt.provider = vendored
    [os=android]
    android.sdk = /home/me/Android/Sdk
    android.ndk = /home/me/Android/Sdk/ndk/27.2.12479018
    [os=android arch=arm64]
    output.dir = /home/me/build/octomy-android-arm64
    [os=android arch=x64]
    output.dir = /home/me/build/octomy-android-x86_64
    

    Each ABI has its own output.dir, because each one builds all of Qt.

  2. Fetch Qt's source once with kiln vendor, if the checkout does not have it yet.

  3. Build and package as above:

    kiln package apk src/hub --arch arm64 --install --launch
    

    The first build runs Qt's configure for Android, builds the Qt modules that the application uses, and Qt's Java libraries with the JDK's javac. It also builds androiddeployqt and rcc for your machine. The build folder is then laid out as Qt's Android kit, and the package is made from it as it is from an installed kit.

javac must be on the path, because Qt's Java libraries are compiled in the build. The vendored Qt builds no QML, and the applications use none, so the package is made without qmlimportscanner.

Android architecture support

There are two Android targets, and both are 64-bit:

ABI Status
arm64 (arm64-v8a) Supported. Built, tested on devices and shipped. --arch arm64.
x86_64 A target that is postponed, not dropped. It builds today, and the hub runs on the x86_64 emulator, but device tests and releases wait until we have x86_64 Android hardware. --arch x64.
armv7, armeabi-v7a, any 32-bit ABI Never. A deliberate, permanent decision. kiln refuses it with a message that points to AGENTS.md.

Do not remove x86_64 from the build matrix or from kiln. The reasons, including why 32-bit is out for good (no 32-bit Android hardware in the target market, the Google Play 64-bit policy, and libnative's JIT being 64-bit by design), are in the project root AGENTS.md under "Android architecture support". Read that before you open an issue or a merge request that touches the Android ABIs.


Build, install and start

One command builds the application, makes its package, installs the package on the device and starts it:

kiln package apk src/hub --arch arm64 --install --launch
  • src/hub is the application. Use src/agent, src/remote or src/construct for the others.
  • --arch x64 builds for x86_64, for the API 35 emulator.
  • Without --install, kiln only makes the package. The path of the package is the line kiln writes to standard output. The package goes in <build root>/package/ as octomy-<application>_<version>_<abi>.apk.
  • --install runs adb install -r on the device. kiln asks adb for the device before the build, so a missing device does not cost a build.
  • --launch starts the launcher activity of the application's manifest with am start -W -n <package>/<activity>. Then kiln watches the process for 30 seconds. --launch-watch <seconds> changes the time, and --launch-watch 0 does not watch.
  • The build is a release build. --variant debug makes a debug build.

If the process dies while kiln watches it, kiln exits 1. It names the process that died and its process ID, and it prints the lines of logcat that come from that ID or name it. A native exit() leaves no signal and no tombstone, only a line from Zygote: Process <pid> exited cleanly (<status>). kiln prints that line too.

Run the tests on a device

The suites run on a device inside the tests-runner package:

kiln test --os android --arch arm64 test/testAddressBook

kiln builds the package with the suites, installs it, starts each suite and reads its result from logcat. If the runner's process ends without a result, the verdict names the process, its ID and the line of the log that says how it ended. See Run tests.


Release packages and signing

kiln signs with the SDK's debug key, ~/.android/debug.keystore, unless android.keystore in .kiln.local names another. The release keystore is integration/cicd/targets/android-arm64/certificates/android_release.keystore. Give its password and key with android.keystore_password and android.key_alias.

For Google Play, make the App Bundle:

kiln package aab src/hub --arch arm64

An App Bundle is for Google Play. A device installs an apk, so --install is refused for aab.


Troubleshooting

INSTALL_FAILED_NO_MATCHING_ABIS

The package is for an ABI the device does not support. Check the ABIs of the device:

adb shell getprop ro.product.cpu.abilist

Build again with the --arch that the list names: arm64 for arm64-v8a, x64 for x86_64.

no Android device answers

adb get-state did not say device. Start the emulator or connect a device with USB debugging on. If adb devices lists several devices, name one with android.device in .kiln.local.

--arch armv7 is a 32-bit ABI

32-bit Android is never a target. Use --arch arm64 or --arch x64. Read AGENTS.md, "Android architecture support", for the reasons.

The application dies at start

kiln prints the death report. To read more of the log yourself:

adb logcat -d -v brief | grep -E 'octomy|Zygote|ActivityManager|libc|DEBUG'

Common causes: a wrong android.app.lib_name in the manifest, a missing Qt plugin (for example no OpenGL ES), or a real runtime assertion.


See also

In this section
Topics
howto android build deployment mobile
See also