 Porting KDE apps to Android and why we care. My agenda for today is, first I want to explain why we care about Android, because after all, we're writing our own Android competitor. Why do we care about Android? Where are we now with supporting KDE software on Android? How hard is porting things to Android? And most importantly how it is done. Why do we care? Android has definitely more than one billion, maybe even more than two billion users. That's a lot. That's about a billion times more than we do. And this includes most of us at the moment. And porting our apps to Android is a very good opportunity for us to be able to actually test our own applications in a day-to-day usage, which is a very important part of developing them. And it's also a good way of growing the number of users that maybe don't even want to use Plasma Mobile, but still want to use cool privacy respecting applications on Android. And every user is in some way a potential contributor, so we also grow the number of potential contributors. Where are we now? We have 28 applications built for Android on the binary factory. Actually it's 29 because I didn't count Krita, because Krita being Krita does its own weird thing and it doesn't show up in our usual Android view. But apparently it works on Android. Seven of them are on Google Play already, and three of them are on Android. So before anyone tells me that, why are we so much more on Google Play than on Android? Android is much better. Yes, I agree, but it's also having things on Android, getting things there is a bit more involved, because on Google Play we just create an APK and upload it there, and be done with it. On Android it's a bit more complicated because they do all those nasty things of wanting to check that your application is actually built from your source, and that it's trusted, and this kind of thing. So what they do is they build all of the applications themselves, and what you need to do is provide a kind of build recipe to them, where these steps for building these apps are defined, which is usually pretty easy for the usual Java gradle-based builds, but it's actually really tricky to do for our Qt-based applications that have a lot of dependencies, but it's certainly possible. I have uploaded Ktrip there. Build script is only like 100 lines of bash. It's awesome. Yeah, I really need to do something about that. Okay, anyway, how hard is porting to Android? The answer clearly is it depends on what your application is doing. There are some things that make porting hard. Those are Qt widgets. Qt widgets are not a problem on Android themselves. They usually just don't make very touch and mobile friendly UIs, but if you have a widgets application that works on a phone form factor, then you can also port it to Android. The second thing that makes things hard with debuzz, because debuzz does not exist on Android, and apps that inherently make use of or require debuzz are probably not going to be runable on Android. Our Android build is a bit weird because it actually does provide debuzz with a giant hack, but it's not really useful because you can do anything with it. And so you usually need to make sure that you have if-deft-out or debuzz usage. Another thing that is tricky, but usually it doesn't appear that much in KT-E stuff, is things that are specific to G-Lib C, because Android does not use G-Lib C. It uses Bionic, so sometimes things can go wrong there, but since there are other distributions that don't use G-Lib C, it's usually not a problem on our software. Something else that makes it hard is weird build systems. Our stuff is usually fine. It's mostly third-party dependencies that can be a bit of a pain, especially you need to be able to cross-compile things, which some build systems make harder than others. And what's also usually a non-starter is esoteric multi-process architectures, because on Android things are typically constrained to a single process. And usually also it's very focused on the application is only running when it's on the screen. There are ways to run in the background, which gets increasingly hard to do. But yeah, then how it is done, it's actually really easy. You just need to call CMake with the correct arguments. Thanks for coming to my TED Talk. It is easy in theory, but in practice it can be very tricky. If you want to check out the K-Trip, it shows every single command that is needed to get it built for Android. And it's horrible, because it's very repetitive. You need to do like the same five or six commands for every framework's dependency. And that's why we have a different solution for that. And like all the cool things, it's built on Docker, or is Docker even still cool? Anyway, yeah, all right. So let's start this Docker container. It's basically, it's called KDE org slash Android SDK. I have some volumes defined here, so that I have my source code on my host system and just expose that to the Docker container. So the way I build an application is there's a bunch of helper scripts in Octopers. The most important one is the build-generic one. And here you just pass an application name, so for example K-Trip, and then it works kind of similar like KDE source build, so it downloads all the dependencies and builds them. That can take quite a long time on the initial build. In that case it should be a bit faster because I've already built it. But yeah, let me, yeah, maybe we can wait until it's finished. So basically what this script does is first it checks the source code of your application for which executable is actually going to be built. So it does start by invoking the script called getAPKRx, which checks your Android manifest for a key where you define your executable. So if you have a project that defines multiple executables, you need to pick which one should get converted into the application. And what it does is it generates some CMake arguments for that that are getting passed to CMake. Then it's calling the KDE build metadata for getting the dependencies. So this script only works with KDE applications and then it builds them with the right CMake argument, installs them into some place, and then it builds the actual application. All that doing, all compiling is done with the compiler from the Android native development kit. And once that's done it's calling the actual apk creation step, which is as easy as calling make create dash apk. And in the end there's an apk falling out that you can then install your device and have fun with it. So this container is very much only designed to work on existing KDE applications, but you often also want to start a new application that is not yet on KDE. And there are ways in which you can get that working too. I will show you that in a minute once this is finished, or yeah let me just interrupt that. So does the container deal with external dependencies for which the CI needs the custom JSON blob? Yeah, those scripts are part of the container, right? The way external dependencies work usually is when you are, when they are CMake-based it's really easy because there's a helper script called octalpers-build-cmake, and then you pass in a project name like for example the mical, which is used for kicking on the core, and then you pass in url to the repository, like https-github.com slash lib-icl, then that works. What you also can do is pull the framework like a kcore add-ons framework, and that's what the the build-generic script is calling internally. So some dependencies are a bit more tricky, for example open SSL or others. For those we usually have wrapper scripts. So for example we have a build-popular script, which is just a batch script that does all the necessary steps to compile popular. And if you want to use a dependency that that we don't have a script for, you are encouraged to add a script, and then in the binary factory job configuration you need to tell it which scripts to run for your application. So actually in theory the Docker container is very easy if you just want to get an application, which is just get an apk, it's just running the Docker container and then in the end the apk falls out. So for KDE applications that are already set up it's really really easy to get an apk. It gets a bit more tricky if you want to make new apps and also have it in a way that's easier to hack on the source code. Also the way the dependency specification works is in the JSON thing you have this thing called dependencies and they just write and opt help us build popular and then automatically when Ocular is built popular gets built as well. All right so let's assume we have our own application that we want to build that is not yet on KDE. So what I usually do is I call the opt help us get apk arcs on some existing app which okay just ignore the fail that's not a failure gives you these two arguments and then you replace ktrip with your own executable name then you copy that and then you can just call the opt help us build CMake thing with your app git and then can paste those op parameters at the end and then it should build your app and then what you also need to do is go into the other then it builds everything but the apk and then you can go to the build directory and manually invoke make create apk which doesn't work right now because I canceled the build earlier but in theory that should output your apk to somewhere in the build directory and then you can either have a volume that automatically puts it on your disk or docacp it out of the container and run it on your phone. Okay let's go back to representation yeah the whole article on the docker container could use a bit of extension for all the tricks I just showed you. Okay so now you want to port a new app there's a few steps you need to do always and then there's a few things you need to take care of if you're using certain patterns or things what you always need to have is an android manifest.xml where technically you can do without but yeah you you don't really uh usually I just copy that from some other project and then just replace the names because it's mostly boilerplate. There is a thing inside which sets the android.app.lib name thing and that must match your executable name and I usually put the android manifest into a subfolder called android you can name that anything you like but that's one of those parameters that gets set or gets extracted from this get apk args thing so if you do that manually you need to check that this is pointing to the right directory and in the same folder as the android manifest you also put the android specific javasource files if you have any and your resource files like your app icon which you need to put into android slash res slash drawable and then you can reference it from the android manifest with add drawable slash the file name. What you also need to do is go to your main method and mark that as exported because else android can't find it and you do that by just putting a q decal export in front of it. So when you start it up now it hopefully shows up but you will notice that it doesn't have any icons at all which is bad but luckily there isn't there's a fix and so that's when you're loading your icons from the icon theme and to do to make that possible you actually need to bundle your icons into your apk this is done with the kirigami package breeze icon cmake macro which yes this automatically includes the icons that kirigami use internally i think and then you you put that into somewhere in your cmake usually with an if android around it and here is the a bit ugly part where you need to specify every icon that your app uses in some way and that should be bundled inside. It's a bit ugly but i don't really know how it would be done better because you don't want to bundle all breeze icons because then your apk size would be huge and what you also need to take care of is actually including the qt svg lib yourselves your svg icons wouldn't be able to be rendered and that's done by linking your application against qt 5 svg manually which you usually don't need to do on the desktop but need to do here so that android deploy qt that's the tool that convert that makes your apk knows that it's important and needed so what else needs to be done some applications or libraries use plugin systems and to make them work you need to tell android deploy qt that the plugins should be bundled into the apk so one example where this is done is k people where it needs to bundle the data source plugins and this is done by first defining k people dash android dash dependencies dot xml file where in the file you describe which plugins from which folders will be included and then that file needs to be installed into the library location and then android deploy qt will pick up those files so two examples as i said k people makes use of it k people currently has an issue which i discovered while preparing for this talk but i wasn't able to fix it yet but the fix is quite simple is that with qt 5 14 the way this is done changed a bit and k notifications actually does the right thing so check the source code on that on how it's done something else that can be tricky is file paths because um usually sometimes we assume files are present in a certain location on the desktop but it's not true on the on android because on android usually you can only see the the on private the on private file storage but to access the the general file storage you need to get consent from the user to do that and this is especially tricky with q standard paths generic data location which is not accessible by default unless you request the permission so consider always using app data location for this kind of things and if you have files like an image for the default avatar then you shouldn't rely on that thing being present in the file system but consider bundling those things in your resources sometimes you might need to write an code that is specific to android or you have code that shouldn't be run on android in cmake you can use if android or if not android to guard android specific code from c++ there's the qos android defined that you can check for before using android specific code or if def qos android for code that shouldn't be compiled for android just a cube module called qt android extras that provides some useful api for some basic things for example dealing with the android permission system there are cube wrappers for that and for some things you will need to call the android java api with the java native interface which is really ugly usually qt android extras has some wrappers for this kind of things that make it a bit less ugly but it's still not really pretty we have solutions for some problems like creating notifications inside k notifications and we're looking into expanding the capabilities of rke frameworks on android and if you have any solutions for these kind of problems that fit into the scope of kd frameworks then we are very happy to receive contributions for that so a few resources um yeah the code is documentation enough obviously that's uh i'm only half joking because i learned most of what i know about putting things to android by looking at how itinerary does it and you can get quite far with that and out the cute has a lot of documentation on running cute apps on android there's unfortunately not that much documentation about kte specifics and we also have a matrix channel with all the people interested in cute on android so consider joining that first k android extras will it become a standalone library at some point yes assuming there's interest in that so but yeah that's the general idea so if you if there is something in there you want to use then talk to folker and he can extract that all right questions what kind of things are you talking about exactly because usually for like some things in itinerary where we have android specific code is things like brightness control screen lock inhibition for that we have frameworks that do those kind of things on the desktop so that would be a natural place to put it there if it's really just generic android things then k android extras could make sense um what i usually do is adb install and then the apk there's also a target in the make file that is called make install apk or some or something like that which should send it to the phone automatically