Building Android release packages with KDE Craft
One of the probably biggest gaps to make KDE Itinerary widely usable is the fact it is not available as a released package in any of the major APK stores such as F-Droid or Google Play. Unlike on Linux platforms there are no distributors handling this for us on Android-based platforms, we need to take care of that ourselves.
So far there’s only of a few KDE applications with release packages for Android, namely KDE Connect which is special in the technology and build system it uses compared to most other of out applications, and Krita, which uses a custom build script.
On the other hand we do have the nightly debug builds, provided via a spearate F-Droid repository, which are build by a common infrastructure for more than 25 apps. Besides tracking the latest development branches of the apps and their dependencies, those are fairly heavy packages due to all being based on a common base build and thus including a number of unnecessary content. At the same time those are not complete either and for example miss translations.
None of the above is immediately useful for getting to KDE Itinerary release APKs, so we need something else. Ideally this would:
Reuse as much as possible of already existing build infrastructure and build metadata, to minimize maintenance and scale easier to more KDE mobile apps in the future.
Provide full flexibility to fine-tune and tweak the build of the app and all its dependencies. This is necessary in order to strip out everything we don’t need to get the package to an acceptable size. For dependencies outside our control we might need the ability to apply patches on top of their official releases.
Since we want to reuse something we already have, let’s review the options:
The existing nightly debug APK infrastructure: already deployed and working for Android builds, but is very much focused on build the latest branches of everything. Support for using release tarballs, patches, etc would need to be added.
Adapting Krita’s solution: already working and offering sufficient flexibility for customization (it seems to bypass
androiddeployqtwhich in that regard is appealing), however there’s likely little room for generalizing things sufficiently for reuse without ending up with something entirely different.
kdesrc-build: well known in the community, works for Android builds and is driven by config files containing dependencies and their build configurations. However it’s primarily focused on building code from version control systems and no support for patches.
Craft: also well known in the community, and driving the existing release package builds for Windows, macOS and Linux AppImages. Can build release tarballs and version control system checkouts, patch those if necessary and can be configured in great detail, and a large set of relevant build recipes exist already. There
iswas however no support for Android yet, or any cross-compiled platform for that matter.
Yocto: the ultimate level of flexibility and cross-compilation support. That comes at a high complexity cost though and with a steep learning curve. It’s also primarily aimed at embedded Linux, whether adding Android as a target platforms would be feasible I don’t know.
Of course there’s a spoiler in the title already, based on those option I picked Craft as the first option to explore further.
Android Support for Craft
On its currently supported desktop platforms, Craft basically sets up the entire development environment from scratch, compiling missing host tools itself where necessary. Doing the same for Android (or any other cross-compiled platform) would be a massive task, basically reviewing every single platform check and every single build job whether it refers to the host or the target platform.
That’s why Craft for Android currently doesn’t do the complete setup, but assumes it’s running inside a properly set up environment with all required host tools, in particular the KDE Android SDK Docker image which we already have for this purpose. This simplifies the necessary changes on Craft considerably, from adding full cross-compilation support to merely adding yet another Unix-like platform.
All of the required changes have passed review by now, basically falling into two categories:
- Configuring build systems to pick up the desired cross-compilation toolchain. This has been done for CMake and Autotools builds so far, as well as some custom build systems relevant for us (OpenSSL, Qt).
- Adjusting package dependencies and build options for things not being available on Android, or being otherwise different there. These are typically very small and straightforward changes.
Additionally there were are number of changes to enable more fine-grained control over build options or to allow static builds. Those changes are generally useful and not specific to Android.
With all that done, I managed to build working APKs of at least KDE Itinerary and KTrip for four different architectures (ARM 32/64bit, x86 32/64bit), with working translations. Other applications likely need additional fixes, at least if they use additional dependencies.
Release Builds on Binary Factory
Being able to build a package locally isn’t good enough though, it needs to be automated on central infrastructure and work reliably there. For this we can however reuse a lot of parts on KDE’s Binary Factory:
The KDE Android SDK docker image provides us with a reproducible environment that has all the needed host tools installed, and that is in use for CI and nightly debug package builds. With that latest build it already contains everything we need for Craft-based release builds.
The orchestration of Windows, macOS and Linux AppImage builds on Binary Factory can be extended with minimal changes to cover additional platforms and configurations. Patches for this are currently in review.
For signing and publishing packages, we should be able to reuse the existing system for signing and publishing nightly debug packages, the necessary changes for this have yet to be implemented though.
Building and publishing packages is only part of the job though, we also need to review the packaged content, and where possible, remove unneeded things to keep the package sizes manageable. We also need to collect the required metadata for the app stores.
Since this is getting too long already, that’s going to be subject of another post next week then.