Android

From KDE Community Wiki
Revision as of 10:19, 13 March 2016 by Cola (talk | contribs) (Link to build environment external pages)
 
Under Construction
This is a new page, currently under construction!


KDE software on Android

Android is currently the mobile platform regarding market share and number of provided applications. Hence, it is a platform very well suited to increase the availability and usage of applications by the KDE community. In the following, we give an overview of the technical steps required to setup a build system for cross-compiling a Qt5/KF5 based Android application, the necessary steps to deploy it, and a reference list of the porting steps by different applications/people.

Tutorial for Building Applications on Android

For building Qt applications on Android, some extra steps are required in comparison to building directly on Linux. The following instruction expects that KF5/Qt5 based applications can already be built and all necessary tools are installed (gcc, cmake, git,...). The main idea for the setup is that we use precompiled Qt libraries (named NDK and SDK), which are built for the ARM-based Android platform. All building then is done by using these libraries. Still the build-process itself will use the tools from your Linux system (in the following called "host system"; while the Android device is called "target system"). The additional tools mostly are the Java Development Kit and other tools for building Java applications.

Build Environment

There are different ways to setup a build environment:

  1. Use Ready-to-Build Docker Container
  2. Setup your Build Environment Manually

Building

Example: Building Marble

cd /opt/android
git clone kde:marble
mkdir marble/build
cd marble/build
cmake -DCMAKE_PREFIX_PATH=${Qt5_android} -DCMAKE_TOOLCHAIN_FILE=/PATH/TO/ECM/toolchain/Android.cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=../export  ..
make install/strip

Note:

  • /PATH/TO/ECM/toolchain/Android.cmake must be replaced with the actual path to toolchain/Android.cmake, if using the docker image it probably is at /opt/android/kde/install/share/ECM/toolchain/Android.cmake
  • make install/strip strips build symbols from the binaries and reduces sizes considerably

Building with KDESRC-BUILD

For building the below mentioned frameworks on Android, you can use the following kdesrc-buildrc config file:

cd /opt/android
git clone git://anongit.kde.org/scratch/cordlandwehr/kdesrc-conf-android.git
mkdir -p extragear/kdesrc-build
git clone git://anongit.kde.org/kdesrc-build extragear/kdesrc-build
ln -s extragear/kdesrc-build/kdesrc-build kdesrc-build
ln -s kdesrc-conf-android/kdesrc-buildrc kdesrc-buildrc
./kdesrc-build extra-cmake-modules frameworks-android

Packaging and Deployment of APKs

Note

See ECM Toolchain documentation, to be added here as example


Status of KDE Frameworks 5

The following frameworks can currently be used for Qt5/KF5 based applications. They are not (yet?) provided as precompiled libraries but can easily be compiled via kdesrc-build.

Built Successfully

  • kconfig (note: unit tests must be disabled)
  • kcompletion
  • kitemmodels
  • kitemviews
  • kcodecs
  • karchive
  • kguiaddons
  • kwidgetsaddons
  • attica
  • kdnssd
  • kapidox
  • kimageformats
  • kplotting
  • ki18n (libintl-lite is required, since BIONIC does not fully support gettext)

Current Blockers

The following frameworks cannot yet be built and block building of further Tier 1 frameworks:

  • kcoreaddons: unix specific backend not compatible with Android's libc

"Hello KWorld" example

Simple example how to create Qt-based apps for Android using CMake and ECM.

Take a simple "Hello world" example app using QtQuick2 with a resource file:

#include <QGuiApplication>
#include <QQmlApplicationEngine>

int main(int argc, char *argv[])
{
    QGuiApplication app(argc, argv);

    QQmlApplicationEngine engine;
    engine.load(QUrl(QStringLiteral("qrc:/main.qml")));

    return app.exec();
}

It's CMakeLists.txt files would be the same as for a normal/desktop application. All special setup for the target system is done via the toolchain file, which is passed via the cmake parameter on the commandline. Well, almost the same currently with ECM < 5.15.0, as some issues need work-arounds still to be done. See the section in the if in the toplevel CMakeLists.txt:

project(hellokandroid)

# AndroidToolchain needs it
cmake_minimum_required(VERSION 3.1.0)

set(QT_REQUIRED_VERSION 5.3.0)
find_package(Qt5Qml)
find_package(Qt5Quick)

if (CMAKE_SYSTEM_NAME STREQUAL Android)
    find_package(ECM)
    # TODO: possibly should be setup by toolchain one day
    set(QT_QMAKE_EXECUTABLE "$ENV{Qt5_android}/bin/qmake")
    # workaround until this fix is in released ECM
    if(ECM_VERSION VERSION_LESS "5.15.0")
        add_definitions(-DANDROID)
    endif()
endif()

add_subdirectory(src)

When creating the APK package, as with normal Android apps a manifest file is needed which describes what the package contains and needs, named AndroidManifest.xml. For a simple application that should appear on the app grid this would be the minimum needed with an Qt-based app:

<?xml version="1.0"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionName="0.0.3" package="org.kde.hellokandroid" android:installLocation="auto" android:versionCode="7">
        <application android:name="org.qtproject.qt5.android.bindings.QtApplication"
                     android:label="Hello KWorld"
                     android:icon="@drawable/kde">
                <activity android:name="org.qtproject.qt5.android.bindings.QtActivity"
                          android:label="Hello KWorld"
                          android:screenOrientation="unspecified"
                          android:configChanges="orientation|uiMode|screenLayout|screenSize|smallestScreenSize|locale|fontScale|keyboard|keyboardHidden|navigation">
                        <intent-filter>
                                <action android:name="android.intent.action.MAIN"/>
                                <category android:name="android.intent.category.LAUNCHER"/>
                        </intent-filter>
                        <meta-data android:name="android.app.lib_name" android:value="-- %%INSERT_APP_LIB_NAME%% --"/>
                        <meta-data android:name="android.app.qt_sources_resource_id" android:resource="@array/qt_sources"/>
                        <meta-data android:name="android.app.repository" android:value="default"/>
                        <meta-data android:name="android.app.qt_libs_resource_id" android:resource="@array/qt_libs"/>
                        <meta-data android:name="android.app.bundled_libs_resource_id" android:resource="@array/bundled_libs"/>
                        <!-- Deploy Qt libs as part of package -->
                        <meta-data android:name="android.app.bundle_local_qt_libs" android:value="-- %%BUNDLE_LOCAL_QT_LIBS%% --"/>
                        <meta-data android:name="android.app.bundled_in_lib_resource_id" android:resource="@array/bundled_in_lib"/>
                        <meta-data android:name="android.app.bundled_in_assets_resource_id" android:resource="@array/bundled_in_assets"/>
                        <!-- Run with local libs -->
                        <meta-data android:name="android.app.use_local_qt_libs" android:value="-- %%USE_LOCAL_QT_LIBS%% --"/>
                        <meta-data android:name="android.app.libs_prefix" android:value="/data/local/tmp/qt/"/>
                        <meta-data android:name="android.app.load_local_libs" android:value="-- %%INSERT_LOCAL_LIBS%% --"/>
                        <meta-data android:name="android.app.load_local_jars" android:value="-- %%INSERT_LOCAL_JARS%% --"/>
                        <meta-data android:name="android.app.static_init_classes" android:value="-- %%INSERT_INIT_CLASSES%% --"/>
                        <!--  Messages maps -->
                        <meta-data android:name="android.app.ministro_not_found_msg" android:value="@string/ministro_not_found_msg"/>
                        <meta-data android:name="android.app.ministro_needed_msg" android:value="@string/ministro_needed_msg"/>
                        <meta-data android:name="android.app.fatal_error_msg" android:value="@string/fatal_error_msg"/>
                </activity>
        </application>
        <supports-screens android:anyDensity="true" android:normalScreens="true" android:smallScreens="true" android:largeScreens="true"/>
        <uses-sdk android:minSdkVersion="9" android:targetSdkVersion="19"/>
</manifest>

"android:label" would be the display name of your app. For the icon to be used for your app, "android:icon" defines it. The value "@drawable/kde" refers to an icon in PNG format, that is to be found in a subdir "res/drawable" relative to the manifest file, in our case "res/drawable/kde.png".

Get the complete example code, incl. step-by-step build instructions with workarounds for current issues in ECM < 5.15.0, by git clone git://anongit.kde.org/scratch/kossebau/hellokandroid.git

Further References

References:

Application specific build instructions:

Blog posts about building for Android (careful: instructions may be outdated)

Current TODOS

  • add ported applications to kdesrc file -> CoLa