Qt 6.9 - Android Updates

Qt 6.9 brings some useful new features to improve the development process for developers targeting the Android platform. Keep in mind that the following list is not exhaustive of all changes around Qt for Android, and some other features might get their own blog.

Support for Uncompressed Native Libraries

Android 6 and above produces uncompressed native libraries that are only part of the APK by default. However, Qt had this behavior explicitly disabled with the following setting under build.gradle:

android {
...
   packagingOptions.jniLibs.useLegacyPackaging true
...
}

Or via the now deprecated extractNativeLibs manifest flag, because Qt didn't support loading libraries directly from the APK. With this release, such support for reading and loading shared libraries directly from the APK without having them extracted to disk but rather, map those shared libraries to memory. Qt apps and APIs such as QLibrary and QPluginLoader should work the same as before and iterate libraries under the native libraries' directory.

There are few things to consider when this mode is enabled (it's enabled by default on 6.9+). For example, QCoreApplication::applicationDirPath() would now return a path that points to a shared library filename that's inside the app's APK, usually in the form:

/data/data/package-path/base.apk!/lib/arm64-v8a/libmyapp_arm64_v8a.so

Paths returned by similar API calls might have previously returned a writable path, after this however, the returned paths won't be writable.

Enabling this might increase slightly the total size of produced APKs, but saves on disk space after installation and also on update sizes from the Play Store and slightly faster startups. For more information, see Improvements for smaller app downloads on Google Play.

Apps with the older way using compressed libraries still work as before if the relevant flag is explicitly enabled as mentioned above.

New Command-Line App/Test Runner

When developing for Android, you're expected for the most part to be using an IDE that handles the build and deployment and running the app. That process doesn't need to be that complicated, because of that we've added wrapper scripts that handle that job for you. Especially, on CI environments or if you're one of the people who can get by using a lightweight code editor and a terminal for development, this can be quite handy for you. All you need to do is build your project's APK and run the app as follows:

cd build
qt-cmake -S .. -B . -GNinja
cmake --build . --target apk
MY_ENV_VAR=value ./my_app --install --my_arg value

This last command would handle all the underlying adb commands behind the scenes by installing the app to the device, starting it and printing the logcat of the app, making it a more seamless experience and hassle free. For Windows, the runner has the .bat file extension.

You can pass environment variables directly from your shell so they end up being passed to the app's runtime on the device. The same applies for command line arguments, where arguments not reserved by the runner are passed as app's arguments. For all parameters that the wrapper accepts, call it with --help.

The same applies for auto tests, you would be able to simply do the following:

cd build
QTEST_FUNCTION_TIMEOUT=900000 ./tst_android test_case_1

And that would simply handle everything with androidtestrunner under the hood. In this case, you don't need to manually issue the APK build command because androidtestrunner takes care of that.

CMake Android APIs

We keep improving the integration of Android builds with CMake to make it easier to manage and maintain Android-specific requirements. Here’s what’s new:

Add App Permissions

Managing permissions for Android apps often requires manual edits to the AndroidManifest.xml. The new qt_add_android_permission() function removes this hassle by letting you declare permissions directly within your CMakeLists file. This function still allows auto inclusion of Qt modules' managed permissions. This approach simplifies project management, making it more straightforward by keeping project configurations in one place.

Setting an App's Name and Icon

Setting the app's name is now as simple as specifying it with QT_ANDROID_APP_NAME in your CMake configuration. No more manual setting of the app's name in the AndroidManifest.xml file. Similarly, you can now define your app's icon drawable/mipmap in your project's CMake configuration with QT_ANDROID_APP_ICON. This expects the icon drawables to be under the appropriate Android resource directory hierarchy and the use of QT_ANDROID_PACKAGE_SOURCE_DIR.

Setting Java/Kotlin Compile SDK Level

The new property QT_ANDROID_COMPILE_SDK_VERSION allows you to specify the Android SDK version for compiling Java code. With this property, you can ensure your project is always built against the desired API level.

Improved Background Event Management

Background processes, particularly those involving UI updates, can be a source of performance bottlenecks if not managed properly. To address this, now it's possible for developers to set a maximum limit for queued background UI events by setting the new environment variable QT_ANDROID_BACKGROUND_ACTIONS_QUEUE_SIZE.

This enhancement prevents potential memory overload caused by an excessive number of tasks waiting in the queue. By defining a limit, developers can ensure smoother performance and prevent lagging or unresponsive behavior in their apps.


That's all from me this time! As always, we continue to improve Qt for Android, and we welcome your feedback and suggestions on this blog post or over bugreports.qt.io.

 


Blog Topics:

Comments