Let’s say you got a 64-bit ARM device running Android. For instance, the Tegra X1-based NVIDIA Shield TV. Now, let’s say you are also interested in the latest greatest content from the dev branch, for example to try out some upcoming Vulkan enablers from here and here, and want to see all this running on the big screen with Android TV. How do we get Qt, or at least the basic modules like QtGui, QtQuick, etc. up and running on there?
Our test device.
The Qt documentation and wiki pages document the process fairly well. One thing to note is that a sufficient MinGW toolchain is easily obtainable by installing the official 32-bit MinGW package from Qt 5.8. Visual Studio is not sufficient as of today.
Once MinGW, Perl, git, Java, Ant, the Android SDK, and the 32-bit Android NDK are installed, open a Qt MinGW command prompt and set some environment variables:
set PATH=c:\android\tools;c:\android\platform-tools; c:\android\android-ndk-r13b;c:\android\qtbase\bin; C:\Program Files\Java\jdk1.8.0_121\bin; c:\android\ant\bin;%PATH% set ANDROID_API_VERSION=android-24 set ANDROID_SDK_ROOT=c:\android set ANDROID_BUILD_TOOLS_REVISION=25.0.2
Adapt the paths as necessary. Here we assume that the Android SDK is in c:\android, the NDK in android-ndk-r13b, qtbase/dev is checked out to c:\android\qtbase, etc.
The Shield TV has Android 7.0 and the API level is 24. This is great for trying out Vulkan in particular since the level 24 NDK comes with the Vulkan headers, unlike level 23.
Now the fun part: configure. Note that architecture.
configure -developer-build -release -platform win32-g++ -xplatform android-g++ -android-arch arm64-v8a -android-ndk c:/android/android-ndk-r13b -android-sdk c:/android -android-ndk-host windows -android-ndk-platform android-24 -android-toolchain-version 4.9 -opensource -confirm-license -nomake tests -nomake examples -v
Once this succeeds, check the output to see if the necessary features (Vulkan in this case) are enabled.
Then build with mingw32-make -j8 or similar.
To get androiddeployqt, check out the qttools repo, go to src/androiddeployqt and do qmake and mingw32-make. The result is a host (x86) build of the tool in qtbase/bin.
For general information on androiddeployqt usage, check the documentation.
Here we will also rely on Ant. This means that Ant must either be in the PATH, as shown above, or the location must be provided to androiddeployqt via the –ant parameter.
Now, Qt 5.8.0 and earlier have a small issue with AArch64 Android deployments. Therefore, grab the patch from Gerrit and apply on top of your qtbase tree if it is not there already. (it may or may not have made its way to the dev branch via merges yet)
After this one can simply go to a Qt application, for instance qtbase/examples/opengl/qopenglwidget and do:
qmake mingw32-make install INSTALL_ROOT=bld androiddeployqt --output bld adb install -r bld/bin/QtApp-debug.apk
Now that a Qt application is installed, let’s launch it.
Except that it does not show up in the Android TV launcher.
One easy workaround could be to adb shell and do something like the following:
am start -n org.qtproject.example.qopenglwidget/org.qtproject.qt5.android.bindings.QtActivity
Then again, it would be nice to get something like this:
Therefore, let’s edit bld/AndroidManifest.xml:
<intent-filter> <action android:name="android.intent.action.MAIN"/> <!--<category android:name="android.intent.category.LAUNCHER"/>--> <category android:name="android.intent.category.LEANBACK_LAUNCHER" /> </intent-filter>
and reinstall by running ant debug install. Changing the category name does the trick.
Note that rerunning androiddeployqt overwrites the manifest file. A more reusable alternative would be to make a copy of the template, change it, and use ANDROID_PACKAGE_SOURCE_DIR.
Widget applications, including OpenGL, run fairly well:
Or something more exciting:
No, really. That clear to green is actually done via Vulkan.
And finally, the hellovulkantexture example using QVulkanWindow! (yeah, colors are a bit bad on these photos)
adb logcat is your friend, as usual. Let’s get some proof that our textured quad is indeed drawn via Vulkan:
qt.vulkan: Vulkan init (libvulkan.so) vulkan : searching for layers in '/data/app/org.qtproject.example.hellovulkantexture-2/lib/arm64' ... qt.vulkan: Supported Vulkan instance layers: QVector() qt.vulkan: Supported Vulkan instance extensions: QVector(QVulkanExtension("VK_KHR_surface" 25), QVulkanExtension("VK_KHR_android_surface" 6), QVulkanExtension("VK_EXT_debug_report" 2)) qt.vulkan: Enabling Vulkan instance layers: () qt.vulkan: Enabling Vulkan instance extensions: ("VK_EXT_debug_report", "VK_KHR_surface", "VK_KHR_android_surface") qt.vulkan: QVulkanWindow init qt.vulkan: 1 physical devices qt.vulkan: Physical device : name 'NVIDIA Tegra X1' version 361.0.0 qt.vulkan: Using physical device  qt.vulkan: queue family 0: flags=0xf count=16 qt.vulkan: Supported device layers: QVector() qt.vulkan: Enabling device layers: QVector() qt.vulkan: Supported device extensions: QVector(QVulkanExtension("VK_KHR_swapchain" 68), QVulkanExtension("VK_KHR_sampler_mirror_clamp_to_edge" 1), QVulkanExtension("VK_NV_dedicated_allocation" 1), QVulkanExtension("VK_NV_glsl_shader" 1)) qt.vulkan: Enabling device extensions: QVector(VK_KHR_swapchain) qt.vulkan: memtype 0: flags=0x1 qt.vulkan: memtype 1: flags=0x1 qt.vulkan: memtype 2: flags=0x7 qt.vulkan: memtype 3: flags=0xb qt.vulkan: Picked memtype 2 for host visible memory qt.vulkan: Picked memtype 0 for device local memory initResources uniform buffer offset alignment is 256 qt.vulkan: Creating new swap chain of 2 buffers, size 1920x1080 qt.vulkan: Actual swap chain buffer count: 2 qt.vulkan: Allocating 8847360 bytes for depth-stencil initSwapChainResources ...
Should you need validation layers, follow the instructions from the Android Vulkan docs and rebuild and redeploy the package after copying the libVkLayer* to the right location.
That’s all for now. Have fun experimenting. The basic Vulkan enablers, including QVulkanWindow are currently scheduled for Qt 5.10, with support for Windows, Linux/X11, and Android. (the list may grow later on)