Anatomy of a Qt 5 for Android application

Published Tuesday July 23rd, 2013 | by

To those of you who were at the Contributor’s Summit, I said that I would write a few more technical blogs about Qt 5 for Android in the near future. This first blog accompanies my session at the CS quite well, as it will give some insight into how the different pieces in the Qt 5 for Android port fit together.

When developing platform ports of Qt, we’re doing our best to hide the piping, so that a developer using Qt can get as far as possible without even considering the target platforms of their application.

However, there are times when it’s useful to understand more about the inner workings of Qt, either if you want to contribute code to Qt itself, when there’s an error and you don’t understand why, or if your application requires a degree of platform integration which we have not yet been able to facilitate. In this blog, I’ll focus on the Qt for Android port in particular.

Prerequisites
It is outside the scope of this blog to explain how the Qt Platform Abstraction API (QPA) works. It is also outside the scope to give a detailed introduction to Android development, and the life span of Android applications. It should hopefully be both understandable and useful without any in-depth knowledge of either technology, however, and if you wish to know more, there is documentation and blogs on both topics to be found on the Internet.

Suffice it to say: Qt abstracts away the windowing system in an API called “QPA”, so that platform-dependent code can be isolated to a plugin. This plugin will handle everything from putting graphics on the screen to propagating events from the windowing system and into your Qt event loop. Android is one such platform, but different in many respects from the other platforms supported by Qt, as it is inherently a Java-based platform. Android applications are Java applications, running on a virtual machine called “Dalvik”. This poses some extra challenges when integrating with the C++ framework Qt.

Which brings us to the “Java Native Interface” (or JNI for short). This is the communication layer between Java and C, and is used by Qt when passing data back and forth between the operating system and the platform plugin. In Qt, we are working on some convenience APIs around the JNI APIs to help you combine Qt code with JNI code if you would like your code to interoperate with Java.

Cross Section
At the very top of levels, a Qt for Android application consists of two parts:

  • The Qt application:
  • This is the cross-platform code and resources that you, as the app developer, manage yourself, and which are summarized by your qmake .pro file.

  • An Android application launcher:
  • This is generated for you by Qt Creator the first time you connect your project to a Qt for Android Kit.

The latter consists of the following:

  • A subclass of android.app.Application:
  • This maintains bindings to Qt using Java’s Reflection API.

  • A subclass of android.app.Activity:
  • This is the application entry point. In Android, an application can consist of several activities, responding to different so-called intents. However, by default a Qt application will only consist of a single activity which can be launched from the Android application grid. Several system events are delivered to the main activity of your application and are then propagated to Qt by this subclass. The QtActivity class also handles loading the native binaries based on the selected deployment method, and launching the application’s main() function.

  • Interfaces for connecting to the Ministro service:
  • Ministro is a deployment mechanism where the Qt libraries are downloaded and maintained by an external service on the target device, and serves to minimize the amount of space used by each Qt application. The interfaces are used to communicate with the service in the case where this deployment mechanism is selected.

  • AndroidManifest.xml:
  • This is the heart of the application meta-data on Android. At some point you will have to edit this to set things such as your application name, package name, version code, icon, permissions, etc. and Qt Creator provides you with a convenient editor for the most common parts of the manifest. In Qt Creator 2.8 and up, you can simply click on the AndroidManifest.xml to open the editor. If you need to customize beyond the options in this editor, click on the XML Source tab in the top right corner.

  • Other meta-data
  • There are a set of extra files used to store additional information about your application. This is e.g. information on the selected deployment mechanism in Qt Creator, an Android layout used for showing a splash screen, translations of Ministro UI text, etc.

When Qt Creator sets up your project for a Qt 5 for Android Kit, it will copy these files from the directory $QT/src/android/java. It will then make modifications to the files based on your deployment settings, your target Android version, etc. When developing a regular Qt application, you don’t have to modify any of this yourself, with the exception of the AndroidManifest.xml, and even that can wait until you actually want to deploy your application to users or market places. At that point you will probably want to set some application specific data, such as the name and icon.

The final piece of the puzzle is the code which resides in Qt. It consists of the following:

  • QtActivityDelegate.java and other Java files:
  • This will set up the UI for your app (just a single SurfaceView which Qt can draw into), and take care of the communication back and forth between the Android OS and QPA. When your application’s activity receives events from the operating system, it will call functions in the QtActivityDelegate and these will propagate into Qt.

  • The platform plugins:
  • Yes, that’s a plural. There are two platform plugins in Qt for Android which cater to two different use cases. The first is a raster-based plugin, which is used for QtWidget-based apps which do not depend on OpenGL. This mimics some of the behavior in a traditional desktop windowing system which allows multiple top-level, non-full-screen windows that can be stacked. The other is GL-based, and used e.g. for Qt Quick 2 applications, which depend on OpenGL ES 2. This has limited support for multiple top-levels (they will all become full screen) so it does not suit the traditional desktop application UI equally well.

Start-up
When it’s started, the Qt for Android application will be just a regular Java application. The entry point will be in QtActivity.java which can be found under android/src/… in your project directory. This code will first check your project meta-data, which is contained in android/AndroidManifest.xml and android/res/values/libs.xml, to see which deployment mechanism has been selected. Qt Creator will update the meta-data based on your project settings. For more insight into the different values here, you can try selecting different deployment mechanisms in Qt Creator and running your application, subsequently browsing the meta-data to see what has changed.

There are three different deployment mechanisms supported, each of which has a slightly different start-up code path:

  1. Bundle Qt libraries in APK:
  2. At start-up, the application will have to copy some of the bundled files into a cache. This is necessary due to some limitations in Qt, and is something which will be improved in Qts to come.

  3. Use Ministro service to install Qt:
  4. If the Ministro service has not yet been installed on the device, your application will ask its user to install it, redirecting them to the market place. Once the service is available, your application will query it for the required Qt libraries and files, downloading anything that’s missing.

  5. Deploy local Qt libraries to temporary directory:
  6. The necessary files have already been deployed to a readable directory structure on the device’s internal storage by Qt Creator before launching the app, and no further preparation is necessary.

Once the preparation is done, the application will first explicitly load Qt (and other) libraries listed in android/res/values/libs.xml in the order given. When that is done, it will load the platform plugin, which serves as both the QPA plugin and the communication layer between Qt and Java. This plugin will first register a set of native callbacks that are called from Java as reactions to Android events and it will register its QPA interfaces. Once this is done, the application will load the final library: The one produced as your application binary. Regular “app” templates in qmake produce shared libraries when built for Android, since the application entry point is actually in Java. This shared library is loaded, and its main() function is then called on a new thread, so that the Android and Qt event loops are running in parallel.

At this point, your application takes over and can run in its thread with no regard to the origin of the input events it is getting.

Just a couple of notes at the end: Bug reports are very welcome, but please file them in the official bug report form, as reports that are entered in the comment field of this blog are very hard to track. In the wiki, there is also a list of devices on which Qt 5 has been tested and confirmed to work. If you are working on a device which is not already in the list, and if you have a moment to spare, we would be very thankful if you could add the device to the list.

Beyond that: If you have questions about Qt for Android, one way to get answers is to find us on IRC. The ones of us in Digia are usually on #necessitas on Freenode during Norwegian business hours. Thanks for reading!

Did you like this? Share it:
Bookmark and Share

Posted in Android, C++, cross-platform, integration, QPA, Qt, Qt in depth

41 comments to Anatomy of a Qt 5 for Android application

Jakub says:

Is it possible to make Android Widget with Qt?
What about Android system service?

Max says:

Thx for the article.

Two questions i have:

1.) Is it possible to integrate Ministro into the Qt application. Because for me it is a poor user experience to install serveral applications to run one.

2.) For commercial user who build Qt static do i need ministro? I would think not, or?

Eskil Abrahamsen Blomfeldt says:

1) Integrating Ministro in the application is not possible. Letting every Qt application manage the repository of native libraries which are shared with other apps would be a huge security hole, so that is not something we are going to support. If you do not wish to use Ministro, you can use the bundling option (which is the default in Qt 5) and you will get a stand-alone application package without any third-party dependencies.

2) No, Ministro is not required. It is an option for those who want to minimize the size of their apps.

Max says:

Perfect. I only used the N. Alpha. And there was no way around Ministro.

Cyttorak says:

So it is possible to create an “executable” (apk file?) totally stand alone? In that case Qt is a very viable option for Android development :)

Fabio says:

Yep! And this is really good!!

I found the android support in Qt5 is buggy for now, but in future versions, if the most annoying bugs will be fixed and the same quality of Qt4.x will be reached…

Another concern is the size of the apk file: ICU library are a little big.

david achitov says:

Love to hear that Ministro is not a mandatory requirement. With all respect to Bogdan ;)

Fabio says:

Very nice article, this will help to better understand the android directory added to the project. :)
Thank you.

I’ve ported a simple QWidget application that already work well on Windows Linux and MacOSX (Qt5.1) to Android.

The application use a QMainwindows qith QActions, some QMessagebox, QProgressDialog and some other basic QWidget.

It work on Android…but and it’s a shame because the main problems (blocking problems) are the windows size and refresh. What I would like to achieve, for example, is to start the QMainWindows full screen (but it became fullscreen rotating the android device and back to the original position) or to maximize a QMessagebox (but if I put a button in the message box, with the same size and position code, it became maximized)…..

I posted a message with some details of the windows flags an instruction I try on the relevant forum, but without luck:
http://qt-project.org/forums/viewthread/29854/

There is some weird bugs for QWidget on Android or I’m missing some requirement in the code?

Eskil Abrahamsen Blomfeldt says:

There are some limitations and bugs related to having multiple top-level windows on Android. Please make sure the problems you are seeing are reported in bugreports.qt-project.org, and we will try to fix as much as possible.

Robert says:

Gentlemen,
I believe that most issues referred by Fabio are already filed, e.g.:
QTBUG-32537 – Android: Wrap-Content Default Behavior Broken for QWidgets
QTBUG-32348 – Android: Heap Allocated Modal Dialog After Closing Prevents Input to QTextEdit
QTBUG-32297 – Android Modal Dialog without Sizes Set Crashes or Stacks Application
QTBUG-31026 – Repaint artifacts when using combo box on Android (raster plugin)
QTBUG-30143 – QWidget::showFullScreen() does not get right screen resolution in Android
and many others.

Android is growing from the phones to tablets and to desktops. Many folks would like to port their existing QWidget-rich applications from Windows, Mac and Linux to Android. If it does not go smoothly, not necessarily they jump to QML, but instead my prefer going native Android JAVA without Qt. Therefore, please try to set some priority for QWidget-based issues.

Thank you for the great job you are doing!

Fabio says:

Cannot quote enough!
+1++
;-)

Eskil Abrahamsen Blomfeldt says:

Please remember to also vote for the tasks :) That makes it easier for us to prioritize.

Thomas McGuire says:

Thanks for blogging about this, very interesting to hear about some of the implementation details. Looking forward to more!

Just one thing that was a bit unclear when reading:
A subclass of android.app.Application:
This maintains bindings to Qt using Java’s Reflection API.

What “bindings” do you mean? What does this subclass do exactly?

Eskil Abrahamsen Blomfeldt says:

As I mentioned, in the Ministro deployment case, the QtActivityDelegate class is not a part of your application, so it can be updated as part of a general Qt update. So to adjust to updates, we do dynamic look ups of even handlers in the delegate class and then delegate events to them *if* they are available. This is done and stored in the Application subclass since there’s a single QtActivityDelegate for the entire application (not a separate one for each activity).

Markus Franke says:

Excellent article as it brings some light into the android port, the integration with Qt Creator and all the glue logic that is needed. Looking forward to read more about this in the future!

Dídac Pérez says:

Congratulations! I think many developers like me were waiting for some such information. Please, keep this blog updated!! Cheers,

Samuele Catuzzi says:

Good, very usefull informations!
My crucial question is about total size of final application with the libraries that it need.
For example, a common application may need to use the gui to display and edit some informations, the graphic system to manage chart or animations and probably some alert sound “bip” ..how big (MBs) it become ?

Eskil Abrahamsen Blomfeldt says:

The size of a Qt Quick 2 “Hello World” application is around 10 MB. This can be tweaked, e.g. by removing plugins and QML imports which you know are not used by your application. We’d like to add more options in the UI to tweak the things included in your apk.

Samuele Catuzzi says:

good news!
also I hope that developing without Quick2 made the apps less heavy :)

Fabio says:

Questions:

*) Is there a way in QtCreator to deploy to
Android only a specific project, or subdirs-project?
I would like to open my top-level subdirs but i have
more than one subproject of type TEMPLATE=app
and I would like to generate apk only for those that
will run on Android.

*) Is there a way in QtCreator, to tell to only generate
apk file without attempt to upload it on an
android device ore simulator?

*) If in the .pro file you customize DESTDIR (and
OBJECTS_DIR) the apk creation will fail because it
seems that binaries are searched only in
OUT_PWD.

*) The automatically added “android” directory
Is created inside the project’s tree, and this
could be ok for the unvariants and manual
edited files. But is there a way in Qtcreator
to generate the .apk and all the intermediate
files in some other locations?
Hopefully a different path for each shadow build?

Thank you.

Eskil Abrahamsen Blomfeldt says:

*) Only a specific project. There’s no automation in place for subdirs projects. Work is being done on a QBS script which should make it easier to batch builds.

*) If you create a signed release package it will not be launched on a device, but that’s the only way currently. If you want to build a new debug apk without deploying, the only way at the moment is to cd into the android/ subfolder in a shell and run “ant debug” manually.

*) Please report any bugs in http://bugreports.qt-project.org so they don’t get lost.

*) We need to separate the generated files from the hand-modified files. Restructuring this will likely be a part of the QBS script I mentioned. At the moment this is not possible in Qt Creator, no.

Fabio says:

Thank you for answer, when I’ll have some time I’ll report the issues in the bugreport.

[...] is a nice article by Eskil Abrahamsen Blomfeldt on the digia qt blog explaining the anatomy of a Qt5 Android [...]

Marcin says:

Well written, thank you. I tested the two demos available on Google Play and it really looks promising. Is the source for those apps available somewhere?

One thing is very noticeable: even though the in-app performance is good, the startup times are terrible. Are you looking into optimizing this? Is there a way to at least display a splash screen while the app’s starting instead of as black screen for those 10 seconds?

Eskil Abrahamsen Blomfeldt says:

Qt 5 Everywhere demo:
http://qt.gitorious.org/qt-labs/qt5-everywhere-demo

Qt 5 Launch demo:
http://qt.gitorious.org/qt-labs/qt5-launch-demo

In the latter, we made some changes that were never upstreamed because we added some Android-specific content to it which didn’t necessarily make sense in that repository. But the main bulk of the code is there.

We are always aiming to optimize, and agree that start-up time is important. If the problem you are seeing is primarily with the Qt 5 Everywhere demo and happens each time you start the app (not just the first time after installation), then we are looking at it, yes. We currently suspect that the problem is the Android assets virtual file engine which does not handle file listing well when the assets consist of many files. The fix would then be to use qrc or some other resource mechanism instead, or to include a hardcoded list of files in the package.

You can monitor the progress of the splash screen bug here:
https://bugreports.qt-project.org/browse/QTBUG-30652

Here’s a task to add support for it in Qt Creator:
https://bugreports.qt-project.org/browse/QTCREATORBUG-8644

ferforje says:

very good. :) Congratulations!

Robert says:

My questions are how to:
- ensure that raster-based plugin is in use?
- force using of either raster-based or GL-based plugin?
- check in run-time which plugin is in use?

What are the performance diffs at most common arm and x86 targets between the plugins?

Thanks!

Eskil Abrahamsen Blomfeldt says:

- The raster-based plugin will be loaded automatically if your application binary does not (explicitly or implicitly) depend on either QtOpenGL or QtQuick libraries.

- The only way to force this currently would be to edit the Java code which loads the libraries and hardcode your selection there.

- That’s not a use case we’ve really considered. What do you want to achieve? This decision is made at compile-time, so a run-time check should really not be necessary.

- We haven’t done any benchmarks of that yet.

Robert says:

Thank you, Eskil.

Strky says:

Is it possible to add my QTtranslator file into the .apk file?

Eskil Abrahamsen Blomfeldt says:

Yes, you can add the .qm file to a .qrc resource bundle, and then it will be accessible in your application using the “:/” prefix.

Due to QTBUG-31651, you won’t be able to get the current locale using QLocale in Qt 5.1, but this is fixed in the Qt 5.2 branch.

men says:

Why Qt Environment is not easy to use.
MS Visual Studio vs Qt IDE ?

Nikolay says:

First congrats on Qt moving to more platforms.

Just one big issue for me. Why you wrap Qt port around Java instead of using Android NDK(C++)?
What is the point to go around Java when you have pure option with the Android C++ API?

Ray Donnelly says:

> you have pure option with the Android C++ API

To interact properly with Android you absolutely must go through Java.

An Android NDK NativeActivity application is just some Java that is hidden from you.

Nikolay says:

I’ve seen game engines that are C/C++ and are ported to Android without introducing Java. I guess that not all features can be accessed without Java but the more native the better. :)

Ray Donnelly says:

They do introduce Java, it’s just that Google have introduced NativeActivity to shield you from this fact.

Android is controlled by Dalvik VM. ‘Native’ code only executes because Dalvik runs it.

JeriX says:

Thanks for all your work on Qt out there!
Just one question:
Is it possible not to create Qt Window for build-deploy-debug native applications with QtCreator?
I’ve achieved only to start NativeActivity from Java code by creating custom Activity and inheriting it from QtActivity. With this method there are flashing empty Qt Window on app start and unnecessary Qt libraries embed in apk, but I don’t need them yet. What solution could be?
Thanks in advance!

Robert says:

Are there any HOWTOS available on accessing Android native services (via JNI) from Qt-based Android applications?

Are there any plans to make some kind of a Qt-class/framework to simplify such interaction with
Android native?

Thanks.

Eskil Abrahamsen Blomfeldt says:

We are working on some convenience APIs around JNI which simplify boiler plates like attaching to the thread, referencing the objects and caching IDs for methods and properties.

Currently we don’t have any documentation available on how to connect to other Android libraries and APIs, but when more of the structure around that is in place, we plan to write an example as well as a blog on it. If you have any ideas on what would be interesting to put into such an example, please let us know.

M.S. Babaei says:

@Eskil, thank you so much for the enlightening info. I was going to drop Qt as an option for mobile development due to two major reasons and stick to MoSync or Marmalade.

1. Ministro (Due to some extra steps that should be taken by the end-user)
2. Size

Currently, most cross platform mobile app development tools are immature and suck a lot. I have a high hope for Qt specially the upcoming Qt 5.2 to get my hands on.

Thank you and the Qt team, for all your efforts.

Commenting closed.