Qt for Android better than ever before What's new in Qt 5.14 for Android
As you already know KDAB is the largest independent contributor to Qt code. Of course we didn’t get lazy and we’ve added a lot of cool stuff to Qt 5.14.
In this article I’m going to write about the super cool stuff that we’ve added to Qt 5.14 for Android.
Android multi arch build in one go
Folks, this is the biggest feature added to Qt on Android since I made the Qt on Android port! I dreamt on this change for a very loong time! I found that is possible to add such support to qmake by mistake :). I had to do some work on Windows (which is not my platform of choice) and there I found that debug and release builds are different on Windows, the makefiles generated by qmake will build twice your source files.
This was exactly what I needed to add multi abi for Android! A few days later I had a WIP patch and, with the help of The Qt Company people, we landed the change in Qt 5.14 alpha!
Let’s see what is new:
- First and foremost from Qt 5.14 there will be a single Qt for Android SDK. Same as the Android NDK, the Qt for Android SDK contains the libs & plugins built for all Android platforms (armv7a, arm64-v8a, x86, x86_64). If you’re building Qt from sources and you want to build only for e.g. arm architectures, you can filter them using the new -android-abis configure parameter:
./configure -android-abis armv7a,arm64-v8a -developer-build -xplatform android-clang -android-ndk /home/bogdan/android/ndk-bundle -android-sdk /home/bogdan/android
- If not specified otherwise, your application will be built by default for all these platforms in one go. You can filter which ABI(s) you want to build for using the ANDROID_ABIS qmake variable, this is useful while you develop your application, to cut the build time.
Build only for arm64-v8a
qmake ANDROID_ABIS="arm64-v8a"
Build only for armv7a and arm64-v8a
qmake ANDROID_ABIS="armeabi-v7a arm64-v8a"
Yes, we changed Qt Creator to make it easier to choose which platforms you want to build for, check the next image:
In order to support this super cool feature we had to change a few things:
- All the .so files produced by qmake are suffixed with the android abi. If you’re using Qt library/plugins classes you don’t need to take any actions, otherwise qmake sets QT_ARCH variable for the ABI you’re
currently building, so you can use it to know which suffix you need to add e.g:
# ... android: DEFINES += LIBS_SUFFIX='\\"_$${QT_ARCH}.so\\"' # ...
Then you can use LIBS_SUFFIX macro in your srcs.
- Because on android we have only one libs folder level, we must rename all the [qml] plugins to make sure we don’t have any name clashes. We use the following naming scheme:
lib + "plugin/path".replace('/','_') + {plugin_name} + _$${QT_ARCH}.so.
If you have a plugin which uses ANDROID_LIB_DEPENDENCIES qmake variable make sure you use the previous naming scheme. Here https://codereview.qt-project.org/c/qt/qtgamepad/+/273676/2/src/gamepad/gamepad.pro you can see how we did it for Qt Gamepad module. Initially I did the renaming from androiddeployqt, but soon I found that this breaks the plugins debugging, as the gdb won’t find the renamed files on the Qt folders, and for me not being able to debug my precious plugins was unacceptable.
Android App Bundles (aab)
I’m going to tell you a secret, Android App Bundles were the main reason for doing the multi arch build in one go :). Without multi arch build in one go you can’t have aab, well at least not without a lot of work, pain and sorrow. Because I’m a happy, lazy person, I don’t like to work more than I must, therefore I had to find a solution to make our life easier. In Qt 5.14, it’s very easy to build an .aab file:
$ make aab
it’s all you need to run on a terminal to build it!
Same as above, I added a new option to Qt Creator to enable .aab packages with a single check box, see the following image:
Load Qt plugins directly from android libs folder
Since Qt 5.14, the Qt plugins were stored to android assets and then extracted to your home folder at the very first start. There are two problems with this approach:
- The very first startup time needed more time to extract all the files
- It occupies more disk space
Starting with 5.14, instead of bundling the plugins and QML resources in assets and extracting them on first start, Qt now creates an .rcc file and registers it before invoking the main function.
Other pretty nice changes
- Same as above, in Qt 5.14 you can easily create an apk from the command line:
$ make apk
is all you need to type on your terminal to create it.
- Reworked assets support – the new version fixes QDirIterators, also it lists all the files and folders.
- NDK r20+ is needed as I updated the clang mkspecs to follow https://android.googlesource.com/platform/ndk/+/ndk-release-r20/docs/BuildSystemMaintainers.md guide. With this change, let’s hope we’ll have less issues with newer NDK versions, as you probably noticed Google folks are restless and they are doing their best to break other tools from time to time :).
- Drop gcc support – this was a change that personally I didn’t like to do it, but I had to, mostly because it was quite challenging to support NDK r10e (the recommended NDK for gcc).
- Last but not least, an easy way to run tests on Android:
$ make check
It’s all you need. For more details and tweaks about it, you can come to my Qt World Summit presentation ;-).
- See more about KDAB Talks at Qt World Summit
Was this work done mostly for qmake projects or is there a CMake alternative available?
Either way, great work!
Only qmake fully supports this feature. It’s also possible to add it to qbs, as it has first class multi abi support.
Cmake is limited to only one ABI. Cmakes doesn’t support at all multi abi, and according to https://gitlab.kitware.com/cmake/cmake/issues/18450 there are no good news for the future…
This means that without quite some magic in QtCreator to spawn cmake for each ABI needed to hide the cmake limitation, it will be impossible have multi abi .apk/.aab support for cmake projects. See https://codereview.qt-project.org/c/qt-creator/qt-creator/+/270196/8#message-59b94fa5dc631c0ec1bfd484ff261a102a12e172 for more info on this matter.
I pretty much like these changes in Qt – I bet they will make deploying to Android much easier, especially since with AAB you only have one build artifact to upload and deploy 🙂
Regarding your notes on the cmake support: I understand that cmake itself does not support multiple archs in one go (which is a shame, but we have to take it for granted right now). However:
* My understanding is, that with Qt 6, Qt itself will migrate to cmake and – while qmake based builds will still be supported – qmake will probably be deprecated and as a consequence I’d assume it would be better to migrate to cmake latest then. Do you have a forecast for us on how things might evolve in the further development of Qt?
* I have an app which currently uses cmake as build system. With the changes coming in Qt 5.14, it seems tempting to migrate back to qmake. On the other side, I have dependencies to some other libraries (basically, KF5 based ones) which in turn use cmake. What would be the best way to integrate such libraries with qmake based application? Do you have any recommendations?
* Finally, how to deal with ANDROID_EXTRA_LIBS in qmake? Would you just add all libraries for all architectures and Qt itself takes care for the rest?
* Sadly in this moment we are all puzzled by TQC decision regarding Qt 6 build system. For sure I’ll discuss this matter at Qt Contributors Summit.
* the best way to add any libs to a qmake project for android is to add them to ANDROID_EXTRA_LIBS. If you think it’s acceptable to change your project files you can try Cristian’s approach (check the comment below).
* you add all your external libs (yes, for all abis) to ANDROID_EXTRA_LIBS qmake variable. androiddeployqt checks every single library and it will copy it to the right abi folder.
Hey Bog, Super happy about this implementation! When I see these kinds of progress, I still think when we started porting – me on the Qt-complex QML architecture side – the first versions of Qt on the old Androids. Then the rest is story. Great appreciation 🙂
Cheers, Enrico (aka Alicemirror)
CMake can easily do multi configuration builds in one go, you just need to know the right technique.
See https://cristianadam.eu/20191012/building-multiple-configurations-with-cmake-in-one-go/ for more details.
I’ve been on that road with your colleague, Alexandru Croitoru, and we found a few flows:
– there is no way to pass all user defined arguments to “ExternalProject_Ad”*. Please check with Alexandru for more info on this matter, IIRC he created a bug report for cmake folks on this matter.
– last but for sure not least: you are forcing people to change and tweak *their* project files, which for me doesn’t fall into easy, nor first class support at all.
For a qmake project you don’t need to change anything in your .pro/.pri files to enjoy multi abi for android, it just works! This is what *I* call an easy, professional & first class solution for multi abi builds in one go ;-).
For the arguments missing you can use an initial CMake pre cache file which you pass via -C, and then you have everything you need to give forward.
Regarding modifying user’s project files, CMake 3.15 introduced CMAKE_PROJECT_INCLUDE exactly for the purpose of controlling projects without modifying them.
Or you can use PreLoad.cmake which gets injected automatically, and works in older CMake versions.
Any other problems?
That’s great.
Can ANDROID_ABIS be specified from the .pro file itself? SO that when you open it the appropriate ABIs are checked in project settings page?
Yes, it can, but QtCreator won’t see it. It will show you wrong ABIs in the qmake abis list.
When this blog in a small screen the comments get cut with no visible scrollbar
Okay, I thought I understood how to edit my .pro file, but I can’t seem to include libcrypt or libssl in my project. Any chance someone can shed a little light on my issue?
Will this affect size of so libraries?
We already have to use ndk 10e gdb debugger in Qt Creator because anything higher (NDK 11 and up to NDK 20) cannot open our android debug 1+ GB symbols with Memory Exhausted error.
I’m having issues with the produced .aab files, see:
https://bugreports.qt.io/browse/QTCREATORBUG-23245
Did anyone do this successfully without crashes on 64bit when the produced .aab is distributed by google?
Thanks.
I upgraded to Qt14, ndk20. Now when I open QtCreator, it shows errors in tab “General messages”:
/home/xxxx/android/android-ndk-r20/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/bin/arm-linux-androideabi-g++: not found
/bin/sh: 1: /home/xxx/android/android-ndk-r20/toolchains/x86-4.9/prebuilt/linux-x86_64/bin/i686-linux-android-g++: not found
QtCreator seems to be looking for g++ instead of clang++, how can I change this ? But in Tools->Options the compilers and kits all look good as they use clang/clang++.
When compiling a project I gets errors:
FAILURE: Build failed with an exception.
* Where:
Build file ‘/home/xxxx/qt5projects/build-projetName-Android_for_armeabi_v7a_arm64_v8a_x86_x86_64_Clang_Qt_5_14_0_for_Android-Release/android-build/build.gradle’ line: 3
* What went wrong:
A problem occurred evaluating root project ‘android-build’.
> Could not find method google() for arguments [] on repository container of type org.gradle.api.internal.artifacts.dsl.DefaultRepositoryHandler.
Can you also please confirm if the recommended linux open jdk version is still 8 ?
Thanks
With Android automotive, do you plan to support android “car-api” on qt ?
If so, do you have a roadmap for it?
Hi Sebastion,
I’m a doc eng for QTC working on the QtAA product.
I believe the answer is yes!
See https://doc.qt.io/QtAndroidAutomotive-6.2/qtaa-overview.html for the current status of what it can do, and https://doc-snapshots.qt.io/qtandroidautomotive/index.html for the future state. (subject to change)
Note it’s a commercial-only module, see https://www.qt.io/pricing for more info.
The way I see it, you basically broke qt-build system for android, to say the list: https://bugreports.qt.io/browse/QTBUG-81249 .
For example: how you link QT against openssl in this workflow??
No good deed goes unpunished …
See https://bugreports.qt.io/browse/QTBUG-80862 for linking against ssl.
Hi,
How do you open the terminal to input this command “$ make aab” ?
I cannot see any terminal in the qt creator itself ?
Please help as i am trying to publish my app to play store.
QtCreator has no built in terminal, but why don’t you use QtCreator to build the .aab? Please read carefully the “Android App Bundles (aab)” section from this article.
Please search the internet for more info about terminals (e.g. https://en.wikipedia.org/wiki/Terminal_emulator , https://en.wikipedia.org/wiki/Terminal_(macOS) , etc.)
Awesome work, QtCreator aab generation integration is really easy to use.
I’m working on music creation app running on linux and android, so targeting lowest latency.
For now QAudioOutput on Android seems to exclusively rely on OpenSLES.
I recently discovered Oboe (from google team) wich use new AAudio backend when possible for better latency and falls back to OpenSLES for Android < 8.1.
Do you know if AAudio or Oboe backend is planned in Qt audio for Android ?
For Qt 5.XX for sure we’ll not use AAudio because it needs API 26+, but please use https://bugreports.qt.io/ to create a new task as for Qt6 we’ll bump the minimum required API version.
I recommend you to use Oboe directly from your Android application (you’ll probably have to add a few #ifdefs here are there to keep it compatible with all OSes).
I am having a problem when i have to create apk “14650669 lib/armeabi-v7a/libplugins_qmltooling_qmljava.lang.UnsupportedClassVersionError: com/android/apksigner/ApkSignerTool has been compiled by a more recent version of the Java Runtime (class file version 53.0), this version of the Java Runtime only recognizes class file versions up to 52.0
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClass(ClassLoader.java:763)
at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
at java.net.URLClassLoader.defineClass(URLClassLoader.java:467)
at java.net.URLClassLoader.access$100(URLClassLoader.java:73)
at java.net.URLClassLoader$1.run(URLClassLoader.java:368)
at java.net.URLClassLoader$1.run(URLClassLoader.java:362)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:361)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
at sun.launcher.LauncherHelper.checkAndLoadMain(LauncherHelper.java:495)
Error: A JNI error has occurred, please check your installation and try again”
I have tried everything and i am stuck with Qt 5.14.1 windows
It looks like your setup has some problems, please try to use OpenJDK 8 (newer version are not supported by all android tools).
I am having issues with ‘make aab’ for a subdir project where the subdirs are static libs. The generated make file seems to start the deployment with androiddeployqt for the static libs as well, instead of only for the executable. Am I doing something wrong?
First of all: Thank you so much for making Qt for android so beautiful!
I am experiencing an android specific bug that maybe has to be fixed in the qt sources (QTBUG-86394).
Unfortunately I don’t get it to work to debug into the qt sources with the android device attached. Debugging into the sources when compiling for macOS works fine.
Preferences -> Debugger -> Source Paths Mapping is set to:
* Source path: /Users/qt/work/qt
* Target path:
Do you know any good tutorial that describes what to do to be able to step through the qt source code when compiling for android and running the application on an AVD or a real device?
I’m passing `-developer-build` to configure script.
Is there any chance to build Qt for multiple android ABIs against openssl multiple ABIs with -android-abis and – openssl options in one hop?
Sadly no, because there is no way to specify where are the libs for each architecture.
What you can do is the build Qt for multiple ABIs and use openssl dynamically.
I do not understand this. I want to build separate apks for each architecture because I don’t want the apk to be larger than necessary. I chose only one architecture in the build configuration, arm64-v8a and verified that the effective qmake said ANDROID_ABIS=”arm64-v8a”, but the apk built still contains all available architectures.
What QT version are you using? It seems it’s a regression, please report this issue to https://bugreports.qt.io/