Getting started with Android on QT

2017-05-28

Chances are someone else also found QT installation notes for targetting android devices lacking. This article describes my setup.

Setup

  1. > avdmanager create avd -n "insert-device-name-here" -p "path/to/device-image" -k "image-name"
    
    This creates the image, and updates ~/.android
  2. (Skip) Install Android-studio

    This should be revisited — even though I couldn't get it working with avdmanager the first time, I think it should be possible.

    As of this writing, QT does not work with latest SDKs, and you must manually downgrade the SDK:

    1. Download 25.2.5 SDK
    2. Extract to $ANDROID_HOME/tools (replace existing tools directory completely.
  3. Install required packages (Fedora 24)
    # yum install SDL-devel glibc libgcc_s.so.1
    
  4. Install Apache Ant
  5. Install JDK. I chose openJDK (version 8)
    # yum install openjdk openjdk-devel
    
  6. For CPUs supporting virtualization, KVM is required.
    # yum install @virtualization
    
    Reboot and enable virtualization from BIOS, and start virtualization service
    # service libvirtd start
    
  7. (Through Android Studio) Install an Android API (example android-21) along with system image file.

    For x86 architecture, Intel ATOM is the one that worked.

  8. Install Qt (used 5.6.2)

Build

The easiest way of building out of the box is probably through QtCreator. You may need to manually add an Android compiler/debugger "kit" in QtCreator if it is missing.

Building from the command line is more tricky as I found it not very well documented. Below works on my system as of this writing. But note that it is only a matter of time before this will be deprecated as Android SDK/NDK and Qt continue to evolve.

We need to add a few environment variables. The structure we want to establish is as follows:

For example, for the ARM architecture, we may have

# Android
export ANDROID_HOME='/exampleDir/Android/Sdk'

# NDK
# Adjust as necessary
export ANDROID_NDK_ROOT='/exampleDir/Android/Sdk/ndk-bundle'
export ANDROID_NDK_TOOLCHAIN_PREFIX='arm-linux-androideabi'
export ANDROID_NDK_TOOLCHAIN_VERSION='4.9'
export ANDROID_NDK_HOST='linux-x86_64'
export ANDROID_NDK_TOOLS_PREFIX='arm-linux-androideabi'
export ANDROID_NDK_PLATFORM='android-21'

# SDK
export ANDROID_SDK_ROOT='/exampleDir/Android/Sdk'

# Ant
export ANT_ROOT_PATH='/exampleDir/apache-ant-1.10.1'

# Add to path
export PATH=$PATH:$ANDROID_HOME/tools:$ANT_ROOT_PATH/bin

Suppose that qmake_armv7 aliases the binary to ARMv7 qmake. Then we can run qmake_armv7 to generate a Makefile and the required deployment settings JSON file.

> qmake_armv7
Compile to a library file, and copy it to the build directory
> make
> BUILD_DIR=/path/to/your/build/dir
> make install INSTALL_ROOT=$BUILD_DIR

Deploy

> androiddeployqt --output $BUILD_DIR --input /path/to/jsonfile.json android-platform $ANDROID_NDK_PLATFORM --verbose

If all the relevant variables are set in the shell environment, then the build and deployment step can be combined into a simple script file taking a .pro file as input. For instance, for ARMv7, we can use

#!/bin/bash
# armv7_build.sh
# Build and deploy Qt application for armv7 arch
# Must have following evironment variables
#   ANDROID_NDK_ROOT
#   ANDROID_NDK_TOOLCHAIN_PREFIX
#   ANDROID_NDK_TOOLCHAIN_VERSION
#   ADNROID_NDK_HOST
#   ANDROID_NDK_TOOLS_PREFIX
#   ANDROID_NDK_PLATOFRM
#   ANDROID_HOME
#   ANDROID_SDK_ROOT
#   ANT_ROOT_PATH
#
# Must have following Qt binaries in path
#   androiddeployqt (armv7 build)
#   qmake_armv7 (an alias to armv7 qmake binary)

if [ "$#" -ne 2 ]
then
    echo "Usage $0 project.pro build_dir"
    exit 1
fi

# Add Android and ANT to path
export PATH=$PATH:$ANDROID_HOME/tools:$ANT_ROOT_PATH/bin

PRO_FILE=$1
BUILD_DIR=$2

# Create build directory
mkdir -p BUILD_DIR

# Build
qmake_armv7
make
make install INSTALL_ROOT=$BUILD_DIR

# Get target name from .pro file
TARGET=$(sed -n 's/^TARGET[[:space:]]\+=[[:space:]]\+//p' $PRO_FILE)
# Expected deployment-settings JSON file
JSON_FILE="android-lib${TARGET}.so-deployment-settings.json"

# Should have a deployment-settings file by now
if [! -f $JSON_FILE]
then
    echo "Could not find ${JSON_FILE}. Aborting"
    exit 1
fi

# Deploy
androiddeployqt --output $BUILD_DIR --input $JSON_FILE android-platform $ANDROID_NDK_PLATFORM --verbose
The above script requires the TARGET to have been set in the .pro file. Then to make and deploy, we can simply invoke
> ./build_armv7.sh my_project.pro my_build_dir

Deploying to AVD

I was not able to successfully deploy an application to an AVD from within QtCreator. QtCreator would successfully launch the AVD, but the application would never get installed in it. The workaround is to push it to an AVD manually

Install a virtual device using the AVD manager, and make sure that it can successfully open by itself. Names of all installed devices should show up under

> emulator -list-avds

You can launch the AVD from commandline using

> emulator [-gpu mode] -avd NAME_OF_AVD
I had to set the -gpu flag as either off or swiftshader for QT built applications to render on screen. I was getting a blank white screen when launching applications without this flag.

Once the device is up, install the app (and overwrite if already exists) using Android Device Bridge

> adb install -r PATH/TO/APK