Робота в Android
Вступ
Qt має чудову підтримку Android, проте для належної роботи програм на цій платформі потрібна значна кількість змін.
Потрібно декілька речей:
- План Craft
- Встановлення qqc2-breeze-style
- Піктограми, які пов'язано із програмою
- Маніфест Android
- Необов'язковий файл збирання Gradle
- Необов'язковий файл XML вікна вітання
- Функція CMake для пакування для Android
План Craft потрібен для пов'язування усіх залежностей з програмою для створення пакунка APK для Android.
qqc2-breeze-style — це альтернатива qqc2-desktop-style, розроблена спеціально для мобільних платформ, таких як Android та Plasma Mobile.
У сценарії Craft програми потрібен умовний код, щоб стилі для настільних і мобільних версій не змішувалися; водночас у коді на C++ слід бути особливо уважним, аби не застосувати невідповідну конфігурацію для того чи іншого типу пристроїв. У файлах CMake також може знадобитися умовний код, хоча цього можна й уникнути.
Включення необхідних для роботи програми піктограм здійснюється за допомогою додаткових модулів CMake від KDE (extra-cmake-modules), інструментів Qt для об’єднання ресурсів, а також функцій CMake із бібліотек Kirigami та Kirigami Addons.
Маніфест Android оголошує метадані та додаткові файли, які мають бути включені до складу програми для Android.
Файл збирання Gradle потрібен, якщо ви використовуєте інтеграцію з extra-cmake-modules для перенесення наявних метаданих вашої програми (наприклад, версії програми) у процес збірки для Android, або якщо вам потрібні особливі параметри збирання.
Файл XML вікна вітання потрібен, якщо ви хочете додати вікно вітання з нетиповою піктограмою, фоном і розташуванням.
План Craft
Встановлення qqc2-breeze-style
To start using qqc2-breeze-style, you will need to add it to Craft. Because it is only used for Android, it will require a conditional clause, especially if the application is already set up to build on Windows and/or Linux using qqc2-desktop style. This requires importing the CraftCore module:
from CraftCore import CraftCore
# ...
def setDependencies(self):
# ...
if not CraftCore.compiler.isAndroid:
self.runtimeDependencies["kde/frameworks/tier1/breeze-icons"] = None
self.runtimeDependencies["kde/frameworks/tier3/qqc2-desktop-style"] = None
else:
self.runtimeDependencies["kde/plasma/qqc2-breeze-style"] = NoneA similar "if not Android, use qqc2-desktop-style, else use qqc2-breeze-style" logic needs to be applied to CMake as well, in case either method of finding qqc2-desktop-style is used:
if (NOT ANDROID)
find_package(KF6QQC2DesktopStyle REQUIRED)
ecm_find_qmlmodule(org.kde.desktop REQUIRED)
endif()Conditional code is also required in C++.
On Android, KDE applications do not use QApplication, but rather QGuiApplication. In addition to setting qqc2-breeze-style only for Android, the initialization order needs to be dealt with in the very likely case that your application is already compatible with the desktop. This can be achieved like so:
int main(int argc, char* argv[])
{
KIconTheme::initTheme();
#ifdef Q_OS_ANDROID
QGuiApplication app(argc, argv);
QQuickStyle::setStyle("org.kde.breeze");
#else
QIcon::setFallbackThemeName("breeze");
if (qEnvironmentVariableIsEmpty("QT_QUICK_CONTROLS_STYLE"))
{
QQuickStyle::setStyle("org.kde.desktop");
}
QApplication app(argc, argv);
// ...
#endif
}KirigamiAppDefaults usage
If you use KirigamiAppDefaults::Apply(), the above C++ code is already managed for you.Додавання піктограм
Перше, що потрібно зробити, щоб програма використовувала піктограми Breeze, це включити KIconThemes до вашого проєкту.
Може виникнути потреба у додаванні декількох команд CMake для пакування піктограми вашої програми разом із програмою.
Lastly, an extra CMake command coming from Kirigami can be used to bundle Kirigami icons into your application (and optionally Kirigami Addons icons).
KIconThemes
This can be done by:
- Додавання її як залежності у Craft:
def setDependencies(self):
self.runtimeDependencies["kde/frameworks/tier3/kiconthemes"] = None- Додавання її як залежності у CMake:
find_package(KF6 REQUIRED COMPONENTS IconThemes)
# ...
target_link_libraries(kirigami-hello
PRIVATE
# ...
KF6::IconThemes
)- Використання її у коді C++, у файлі
main.cpp:
#include <KIconTheme>
// ...
int main(int argc, char* argv[])
{
KIconTheme::initTheme();
QApplication app(argc, argv);
// ...
}Зауважте, що хоча у назві проєкту та виклику CMake використано множину (KIconThemes, KF6IconThemes), виклик C++ використовує однину (KIconTheme).
KIconThemes має бути ініціалізовано до самої програми.
KirigamiAppDefaults usage
If you use KirigamiAppDefaults::Apply(), the above KIconThemes initialization in C++ code is already managed for you.Піктограма програми
Якщо у вашої програми є піктограма, її слід додати до вашого проєкту як ресурс QML і як частину встановлення піктограм.
Зазвичай у Linux піктограму програми можна просто встановити у відповідний каталог, і, якщо потрібно, програма її отримає. Зазвичай піктограма програми складається з основної піктограми у форматі SVG, поєднаної з піктограмами у форматі PNG декількох розмірів.
Встановлення піктограми SVG виконується ось так у CMake:
install(FILES ${CMAKE_SOURCE_DIR}/icons/org.kde.myapp.svg
DESTINATION ${KDE_INSTALL_FULL_ICONDIR}/hicolor/scalable/apps)А встановлення піктограм PNG виконується десь так:
ecm_install_icons(ICONS
16-apps-myapp.png
24-apps-myapp.png
32-apps-myapp.png
48-apps-myapp.png
64-apps-myapp.png
128-apps-myapp.png
256-apps-myapp.png
512-apps-myapp.png
DESTINATION share/icons)При встановленні піктограми у Linux, піктограма у форматі PNG, наприклад 48-apps-myapp.png, встановлюється до ${INSTALL_PREFIX}/share/icons/hicolor/48x48/apps/myapp.png, а піктограма SVG встановлюється до ${INSTALL_PREFIX}/share/icons/hicolor/scalable/apps/org.kde.myapp.svg, де ${INSTALL_PREFIX} зазвичай є каталогом /usr, /usr/local або ~/.local. Зауважте, як у випадку PNG назва піктограми перетворюється на шлях, за яким її буде збережено у файловій системі.
Після встановлення піктограми таким чином у коді QML її можна викликати просто за допомогою myapp або org.kde.myapp, як це було б з QIcon::fromTheme(). Цим можна скористатися у будь-якому елементі керування QML, який має властивість icon.name.
В Android немає такого стандартного каталогу, і встановлення піктограми ні на що не вплине; піктограму слід включити до програми. Для цього файл PNG можна записати до власного каталогу встановлення за допомогою ecm_add_app_icon(), а файл PNG або SVG можна вбудувати в програму як файл ресурсів Qt за допомогою ecm_add_qml_module() або ecm_target_qml_sources().
Піктограма програми PNG встановлюється за допомогою такого коду:
ecm_add_app_icon(myapp ICONS ${PROJECT_SOURCE_DIR}/icons/256-apps-myapp.png)А основну піктограму програми можна додати до пакета як ресурс Qt, ось так:
ecm_add_qml_module(myapp URI org.kde.myapp)
ecm_target_qml_sources(myapp SOURCES Main.qml RESOURCES ../icons/org.kde.myapp.svg)Це зробить піктограму програми доступною у формі ресурсу Qt у файлі qrc:/qt/qml/org/kde/myapp/org.kde.myapp.svg. Цим можна скористатися з будь-яким елементом керування QML, який має властивість icon.source.
Шлях RESOURCES залежить від місця зберігання піктограм. Традиційно для зберігання усіх піктограм створюють теку icons/ у кореневому каталозі проєкту, оскільки система не вважає їх справжніми файлами початкового коду.
Після встановлення піктограм (для Linux) та їхнього включення до комплекту (для Windows та Android) ви можете налаштувати їх у коді. У коді QML, для сумісності як з Windows, так і з Android, слід використовувати піктограму, яка входить до комплекту; у коді C++, зокрема під час налаштування піктограми вікна, можна використовувати типову піктограму теми, а піктограму, яка входить до комплекту, як резервний варіант для QGuiApplication::setWindowIcon():
QGuiApplication::setWindowIcon(QIcon::fromTheme("org.kde.myapp", QIcon(":/qt/qml/org/kde/myapp/org.kde.myapp.svg")));Піктограми Kirigami
Хоча в Android немає стандартного каталогу для встановлення піктограм з теми піктограм, є можливість скомпонувати необхідні піктограми Breeze із вашою програмою Android.
Для цього потрібно дві речі:
- Prepare the project with KIconThemes
- Include breeze-icons in your Craft blueprint
- kirigami_package_breeze_icons()
Щодо налаштовування KIconThemes, див. розділ вище щодо KIconThemes.
Щоб додати breeze-icons як залежність для вашого проєкту, додайте цей код до вашого плану Craft:
def setDependencies(self):
# ...
self.runtimeDependencies["kde/frameworks/tier1/breeze-icons"] = NoneBecause of the way the Android build is done, it is not possible for Craft to automatically do the icon bundling. Kirigami thus provides a CMake function kirigami_package_breeze_icons() which, at build time, clones and prepares the icons for bundling. This command needs to come before the step detailed in CMake function to package for Android.
The CMake command kirigami_package_breeze_icons() does not need to be wrapped behind a conditional, as it only ever runs when on Android.
Additionally, if you are using Kirigami Addons in your application, you may pass the ${KIRIGAMI_ADDONS_ICONS} variable to also ship the necessary icons for components such as FormCard.AboutPage and similar.
kirigami_package_breeze_icons(ICONS
org.kde.myapp insert-image-symbolic kde application-exit-symbolic
edit-clear-all-symbolic edit-undo-symbolic document-save-symbolic
applications-development-symbolic system-user-list donate-symbolic
${KIRIGAMI_ADDONS_ICONS}
)Android manifest
An Android manifest is an XML file describing the application to the Android build tools, operating system, and stores. The file must be called AndroidManifest.xml.
Qt uses the Android manifest and supports additional configuration to call the necessary tools to build an APK that can be installed on Android.
KDE apps keep the manifest stored in an android/ directory at the root of the project.
An Android manifest might look like this:
<?xml version='1.0' encoding='utf-8'?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.kde.myapp"
android:installLocation="auto">
<application android:name="org.qtproject.qt.android.bindings.QtApplication" android:label="MyApp" android:usesCleartextTraffic="true" android:icon="@drawable/myapp">
<activity android:configChanges="orientation|uiMode|screenLayout|screenSize|smallestScreenSize|layoutDirection|locale|fontScale|keyboard|keyboardHidden|navigation"
android:name="org.qtproject.qt.android.bindings.QtActivity"
android:label="MyApp"
android:windowSoftInputMode="adjustResize"
android:launchMode="singleTop"
android:exported="true">
<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="myapp"/>
</activity>
</application>
<uses-permission android:name="android.permission.INTERNET" />
<supports-screens android:largeScreens="true" android:normalScreens="true" android:anyDensity="true" android:smallScreens="true"/>
</manifest>It is mostly boilerplate and can be copied and modified to an existing project, but it is worth learning what parts need to be accounted for.
In the <manifest> tag, the package corresponds to the name that identifies the application internally by Android. It needs to use reverse DNS notation. It should match the application ID specified in code.
In the <application> and <activity> tags, the android:label should be the user-facing name of the application. In the tag <meta-data>, android:value should match the target name as specified in CMake.
In the <application> tag, the android:icon="@drawable/myapp" should be an icon stored in android/res/drawable/, without the file extension. In this example, the file would be android/res/drawable/myapp.png. The res folder stands for "resources". If not specified, the default Android placeholder icon will be shown in the app menu and on the installation prompt instead.
An Activity stands for what the application will do in different states. For example, it might perform certain actions while on the foreground and other actions while on the background. Typically a Qt/KDE application has only one activity.
Each Activity can have one or more Intent Filters. An Intent is something the activity is able to do, which in the case of a KDE application is usually an action, but can also be a service. For example, if the application intends to launch, then it needs to signal to Android that this Activity is the entrypoint for the app (android.intent.action.MAIN) and that the intent is of type LAUNCHER to show up on the app menu screen and be able to launch. This should generally be sufficient for most KDE applications.
The <meta-data> tag can be repeated multiple times and have multiple purposes, and special Qt-specific configurations can be used. The android.app.lib_name metadata is required.
The <uses-permission> tag is straightforward and allows the application to request permission to perform a specific action. A Permission is different from an Intent in that the Intent requests another component to perform an action related to the activity, while a permission is a request for access to functionality that is by default not available.
The <supports-screens> tag specifies which form factors (screen sizes and pixel densities, phones or tablets) the application supports. Because QML applications are convergent, "any size" should be a reasonable default.
The only parts of the above example that are not required are android:icon="@drawable/myapp" (used only if your application already has an icon) and <uses-permissions> (which should only be added when actually needed).
Splash screen
A Splash Screen is an optional screen containing a static image or animation that shows up when launching an application to allow a few seconds for the app to initialize. When no splash screen is specified, the application will be shown as soon as it is opened, even if not ready.
To add it to your application, you will need to specify it in the AndroidManifest.xml metadata:
<meta-data android:name="android.app.splash_screen_drawable" android:resource="@drawable/splash"/>In turn, an android/res/drawable/splash.xml file must exist:
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:width="128dp" android:height="128dp" android:gravity="center">
<bitmap
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:scaleType="fitXY"
android:src="@drawable/myapp"/>
</item>
</layer-list>This simple example commonly used in KDE applications centers the application icon in an empty background, and so an application icon residing in android/res/drawable/ is required.
Приготування APK
The last step needed to actually allow building an APK for Android is a simple CMake function that uses the files in the android/ directory:
ecm_add_android_apk(myapp
ANDROID_DIR ${PROJECT_SOURCE_DIR}/android
)Збирання
To build your application on Android, follow Building applications for Android.
Збирання у CI
Якщо проєкт належним чином налаштовано для збирання у Windows, і у ньому використано інфраструктуру KDE для розміщення коду (KDE Invent), можна налаштувати завдання Android CI/CD.
Для цього вам потрібно буде додати відповідні шаблони CI для Windows за допомогою файла .gitlab-ci.yaml та перелічити ваші залежності у файлі .kde-ci.yaml, як зазначено у підручнику щодо Системи безперервної інтеграції.