Skip to main content
Ir para o conteúdo

Configuração no Android

Preparando sua aplicação C++ para o Android

Introdução

O Qt oferece um excelente suporte ao Android, mas os aplicativos exigem uma quantidade considerável de modificações para funcionar corretamente no Android.

Algumas coisas são necessárias:

O blueprint Craft é necessário para agrupar todas as dependências com o aplicativo para gerar um pacote APK do Android.

O qqc2-breeze-style é uma alternativa ao qqc2-desktop-style, voltada especialmente para plataformas móveis, como o Android e o Plasma Mobile.

O blueprint do Craft para o aplicativo requer código condicional para evitar a mistura de estilos para desktop e dispositivos móveis, enquanto o código em C++ exigirá cuidado especial para não utilizar configurações inadequadas para cada um desses ambientes. O código do CMake também pode, opcionalmente, precisar de trechos condicionais, embora isso possa ser evitado.

O empacotamento dos ícones necessários para o funcionamento do aplicativo é realizado com o auxílio dos extra-cmake-modules do KDE, das ferramentas de empacotamento de recursos do Qt, bem como das funções CMake do Kirigami e do Kirigami Addons.

O manifesto do Android declara os metadados e os arquivos adicionais que precisam ser incluídos no pacote do aplicativo Android.

O arquivo de compilação do Gradle é necessário caso você utilize a integração com o extra-cmake-modules para aplicar metadados existentes do seu aplicativo à compilação para Android — como a versão do aplicativo —, ou caso deseje definir opções de compilação específicas.

O arquivo XML da tela de apresentação é necessário caso você queira adicionar uma tela de apresentação com ícone, plano de fundo e posicionamento personalizados.

Blueprint Craft

Configurando o qqc2-breeze-style

Para começar a usar o qqc2-breeze-style, você precisará adicioná-lo ao Craft. Como ele é utilizado apenas no Android, será necessária uma cláusula condicional, especialmente se o aplicativo já estiver configurado para ser compilado no Windows e/ou Linux usando o qqc2-desktop-style. Isso exige a importação do módulo CraftCore:

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"] = None

Uma lógica semelhante — "se não for Android, use qqc2-desktop-style; caso contrário, use qqc2-breeze-style" — também precisa ser aplicada ao CMake, para o caso de qualquer um dos métodos de localização do qqc2-desktop-style ser utilizado:

if (NOT ANDROID)
    find_package(KF6QQC2DesktopStyle REQUIRED)
    ecm_find_qmlmodule(org.kde.desktop REQUIRED)
endif()

Código condicional também é necessário em C++.

No Android, os aplicativos KDE não utilizam QApplication, mas sim QGuiApplication. Além de definir o qqc2-breeze-style especificamente para o Android, é preciso cuidar da ordem de inicialização, considerando a grande probabilidade de que seu aplicativo já seja compatível com a versão para desktop. Isso pode ser feito da seguinte maneira:

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
}

Empacotando os ícones

A primeira coisa necessária para que o aplicativo use os ícones do Breeze é incluir KIconThemes em seu projeto.

Alguns comandos CMake são necessários para incluir o ícone do seu aplicativo no pacote do app.

Por fim, um comando CMake adicional, proveniente do Kirigami, pode ser utilizado para incorporar ícones do Kirigami à sua aplicação (e, opcionalmente, ícones do Kirigami Addons).

KIconThemes

Isso pode ser feito por meio de:

  • Adicionando-o como uma dependência no Craft:
def setDependencies(self):
    self.runtimeDependencies["kde/frameworks/tier3/kiconthemes"] = None
  • Adicionando-o como uma dependência no CMake:
find_package(KF6 REQUIRED COMPONENTS IconThemes)

# ...

target_link_libraries(kirigami-hello
    PRIVATE
    # ...
    KF6::IconThemes
)
  • Utilizando-o em código C++, no arquivo main.cpp:
#include <KIconTheme>

// ...
int main(int argc, char* argv[])
{
    KIconTheme::initTheme();
    QApplication app(argc, argv);
    // ...
}

Observe que, embora o nome do projeto e a chamada do CMake usem o plural (KIconThemes, KF6IconThemes), a chamada do C++ usa o singular (KIconTheme).

O KIconThemes precisa ser inicializado antes da aplicação.

Ícone do aplicativo

Se o seu aplicativo tiver um ícone, ele precisa ser adicionado ao seu projeto tanto como um recurso QML quanto como parte da instalação do ícone.

Normalmente, no Linux, o ícone do aplicativo pode ser simplesmente instalado no diretório correto e será buscado pelo aplicativo quando necessário. Geralmente, o ícone do aplicativo consiste em um ícone SVG principal, combinado com vários tamanhos de ícones PNG.

A instalação do ícone SVG é feita da seguinte forma no CMake:

install(FILES ${CMAKE_SOURCE_DIR}/icons/org.kde.myapp.svg
    DESTINATION ${KDE_INSTALL_FULL_ICONDIR}/hicolor/scalable/apps)

E a instalação dos ícones PNG é feita da seguinte forma:

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)

Quando o ícone do aplicativo é instalado no Linux, um ícone PNG como 48-apps-myapp.png é instalado em ${INSTALL_PREFIX}/share/icons/hicolor/48x48/apps/myapp.png, e um ícone SVG é instalado em ${INSTALL_PREFIX}/share/icons/hicolor/scalable/apps/org.kde.myapp.svg, onde ${INSTALL_PREFIX} geralmente representa /usr, /usr/local ou ~/.local. Observe como, no caso dos PNGs, o nome do ícone se traduz no caminho que ele terá no sistema de arquivos.

Uma vez que o ícone esteja instalado dessa forma, ele pode ser referenciado no código QML simplesmente como meuapp ou org.kde.meuapp, da mesma maneira que seria chamado por meio de QIcon::fromTheme(). Isso pode ser utilizado com qualquer componente QML que possua uma propriedade icon.name.

O Android não possui um diretório padrão como esse, e instalar o ícone não tem efeito; ele precisa ser incluído no aplicativo. Para isso, o PNG pode ser enviado para seu próprio diretório de instalação ecm_add_app_icon() e um arquivo PNG ou SVG pode ser incorporado ao aplicativo como um arquivo de recurso Qt em ecm_add_qml_module() ou ecm_target_qml_sources().

O ícone PNG do aplicativo é instalado com:

ecm_add_app_icon(myapp ICONS ${PROJECT_SOURCE_DIR}/icons/256-apps-myapp.png)

E o ícone principal do aplicativo é incluído como um recurso Qt com:

ecm_add_qml_module(myapp URI org.kde.myapp)
ecm_target_qml_sources(myapp SOURCES Main.qml RESOURCES ../icons/org.kde.myapp.svg)

Isso tornará o ícone do aplicativo disponível como um recurso Qt em qrc:/qt/qml/org/kde/myapp/org.kde.myapp.svg. Isso pode ser usado com qualquer controle QML que tenha uma propriedade icon.source.

O caminho RESOURCES depende do local onde os ícones estão instalados. Tradicionalmente, uma pasta icons/ é criada na raiz do projeto para armazenar todos os ícones, já que eles não são considerados arquivos de fonte.

Após os ícones serem instalados (para Linux) e empacotados (para Windows e Android), você pode defini-los no código. No código QML, para compatibilidade com Windows e Android, você deve usar o ícone empacotado; no código C++, principalmente ao definir o ícone da janela, você pode usar o ícone do tema por padrão e o ícone empacotado como alternativa para QGuiApplication::setWindowIcon():

QGuiApplication::setWindowIcon(QIcon::fromTheme("org.kde.myapp", QIcon(":/qt/qml/org/kde/myapp/org.kde.myapp.svg")));

Ícones do Kirigami

Embora o Android não tenha um diretório padrão para instalar ícones de um tema de ícones, é possível incluir os ícones Kirigami necessários junto com seu aplicativo Android.

Duas coisas são necessárias para que isso seja feito:

  • Prepare o projeto com o KIconThemes
  • Inclua breeze-icons no seu blueprint do Craft
  • kirigami_package_breeze_icons()

Para configurar os temas KIconThemes, consulte a seção acima KIconThemes.

Para adicionar os breeze-icons como uma dependência do seu projeto, adicione isto ao seu blueprint do Craft:

def setDependencies(self):
    # ...
    self.runtimeDependencies["kde/frameworks/tier1/breeze-icons"] = None

Devido à forma como a compilação para Android é realizada, não é possível que o Craft realize automaticamente o empacotamento dos ícones. Por isso, o Kirigami disponibiliza uma função do CMake kirigami_package_breeze_icons(), que, durante a compilação, clona e prepara os ícones para o empacotamento. Este comando deve ser executado antes da etapa detalhada na Função do CMake para empacotamento para Android.

O comando kirigami_package_breeze_icons() do CMake não precisa estar envolto em uma condicional, visto que ele só é executado quando o sistema é o Android.

Além disso, se você estiver utilizando o Kirigami Addons em seu aplicativo, pode passar a variável ${KIRIGAMI_ADDONS_ICONS} para também incluir os ícones necessários para componentes como FormCard.AboutPage e outros semelhantes.

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}
)

Manifesto Android

Um manifesto do Android é um arquivo XML que descreve o aplicativo para as ferramentas de compilação do Android, para o sistema operacional e para as lojas de aplicativos. O arquivo deve se chamar AndroidManifest.xml.

O Qt utiliza o manifesto do Android e oferece suporte a configurações adicionais para acionar as ferramentas necessárias à criação de um APK que possa ser instalado no Android.

Os aplicativos do KDE mantêm o manifesto armazenado em um diretório android/ na raiz do projeto.

Um manifesto do Android pode ser assim:

<?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>

Trata-se, em grande parte, de um modelo padrão que pode ser copiado e adaptado a um projeto existente; no entanto, vale a pena entender quais elementos precisam ser levados em consideração.

Na etiqueta <manifest>, o atributo package corresponde ao nome que identifica o aplicativo internamente no Android. Ele deve utilizar a notação de DNS reverso. Além disso, deve coincidir com o ID do aplicativo especificado no código.

Nas etiquetas <application> e <activity>, o atributo android:label deve corresponder ao nome do aplicativo que será exibido ao usuário. Na etiqueta <meta-data>, o atributo android:value deve corresponder ao nome de destino especificado no CMake.

Na etiqueta <application>, o atributo android:icon="@drawable/myapp" deve referenciar um ícone armazenado em android/res/drawable/, sem a extensão do arquivo. Neste exemplo, o arquivo seria android/res/drawable/myapp.png. A pasta res significa "recursos". Caso não seja especificado, o ícone padrão do Android será exibido no menu do aplicativo e na tela de instalação.

Uma Atividade representa o que o aplicativo fará em diferentes estados. Por exemplo, ele pode executar determinadas ações enquanto está em primeiro plano e outras ações enquanto está em segundo plano. Normalmente, um aplicativo Qt/KDE possui apenas uma atividade.

Cada Atividade pode ter um ou mais Filtros de Intent. Uma Intent representa algo que a Atividade é capaz de realizar — no caso de um aplicativo KDE, trata-se geralmente de uma ação, mas também pode ser um serviço. Por exemplo, se o aplicativo tem a intenção de ser iniciado, ele precisa sinalizar ao Android que aquela Atividade é o ponto de entrada do aplicativo (android.intent.action.MAIN) e que essa Intent é do tipo LAUNCHER, permitindo que ele apareça na tela do menu de aplicativos e possa ser executado. Em geral, isso deve ser suficiente para a maioria dos aplicativos KDE.

A etiqueta <meta-data> pode ser repetida várias vezes e ter diversas finalidades; além disso, é possível utilizar configurações específicas do Qt. O metadado android.app.lib_name é obrigatório.

A etiqueta <uses-permission> é simples e permite que o aplicativo solicite permissão para realizar uma ação específica. Uma permissão difere de uma Intent pelo fato de que a Intent solicita a outro componente a execução de uma ação relacionada à atividade, enquanto uma permissão é uma solicitação de acesso a uma funcionalidade que, por padrão, não está disponível.

A etiqueta <supports-screens> especifica quais formatos (tamanhos de tela e densidades de pixels, celulares ou tablets) o aplicativo suporta. Como os aplicativos QML são convergentes, "qualquer tamanho" deve ser um padrão razoável.

As únicas partes do exemplo acima que não são obrigatórias são android:icon="@drawable/myapp" (utilizada apenas se o seu aplicativo já possuir um ícone) e <uses-permissions> (que deve ser adicionada somente quando for realmente necessária).

Tela de apresentação

Uma tela de apresentação é uma tela opcional, contendo uma imagem estática ou uma animação, que aparece ao iniciar um aplicativo, permitindo que ele tenha alguns segundos para ser inicializado. Quando nenhuma tela de apresentação é definida, o aplicativo é exibido assim que é aberto, mesmo que ainda não esteja pronto.

Para adicioná-la ao seu aplicativo, você precisará especificá-la nos metadados do AndroidManifest.xml:

<meta-data android:name="android.app.splash_screen_drawable" android:resource="@drawable/splash"/>

Por sua vez, um arquivo android/res/drawable/splash.xml deve existir:

<?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>

Este exemplo simples, comumente utilizado em aplicativos KDE, centraliza o ícone do aplicativo em um fundo vazio; por isso, é necessário que um ícone de aplicativo esteja presente em android/res/drawable/.

Preparando um APK

O último passo necessário para, de fato, permitir a criação de um APK para Android é uma função simples do CMake que utiliza os arquivos presentes no diretório android/:

ecm_add_android_apk(myapp
    ANDROID_DIR ${PROJECT_SOURCE_DIR}/android
)

Compilação

Para compilar seu aplicativo no Android, siga Compilando aplicativos para Android.

Compilações CI

Se o projeto foi configurado corretamente para compilar no Windows e está usando a infraestrutura do KDE para hospedagem de código (KDE Invent), é possível configurar tarefas de CI/CD para Android.

Para fazer isso, você precisará adicionar os modelos de CI relevantes para Windows com um arquivo .gitlab-ci.yaml e listar suas dependências em um arquivo .kde-ci.yaml, como mencionado em Sistema de Integração Contínua.