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.
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.
At the very top of levels, a Qt for Android application consists of two parts:
- The Qt application:
- An Android application launcher:
The latter consists of the following:
- A subclass of android.app.Application:
- A subclass of android.app.Activity:
- Interfaces for connecting to the Ministro service:
- Other meta-data
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:
- The platform plugins:
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:
- Bundle Qt libraries in APK:
- Use Ministro service to install Qt:
- Deploy local Qt libraries to temporary directory:
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!
See original article –