En esta página

QtJenny: Generación de clases proxy C++ para acceder a las API de Android

Demostración del uso de QtJenny.

Visión general

Esta demostración muestra el uso de QtJenny y lo utiliza para generar clases proxy C++ para acceder a las API de Android desde código C++. Las clases C++ generadas se utilizan en la aplicación de interfaz de usuario de esta demostración para realizar acciones como ajustar el volumen y el brillo, activar y desactivar bloqueos de despertador, enviar notificaciones y activar vibraciones. Estas acciones forman parte de las APIs de Android que Qt no implementa.

La generación de clases C++ mediante QtJenny elimina la necesidad de escribir código JNI manualmente.

Cómo funciona

La demo contiene dos partes diferenciadas, una es la aplicación de interfaz de usuario, es decir, el proyecto Qt Quick llamado qtjenny_consumer que utiliza el código generado por QtJenny, y la otra es una combinación de tres proyectos Gradle diferentes llamados qtjenny_general, qtjenny_callback y qtjenny_baseclass que juntos gestionan la generación de código utilizando QtJenny. Cada uno de los tres proyectos Gradle contiene anotaciones de clases y configuraciones Gradle para la generación de código QtJenny.

La generación de código QtJenny se activa automáticamente durante la configuración CMake del proyecto qtjenny_consumer mediante la ejecución de la tarea gradle kaptReleaseKotlin en cada uno de los proyectos gradle qtjenny_general, qtjenny_callback y qtjenny_baseclass.

if (ANDROID)
    if (CMAKE_HOST_SYSTEM_NAME STREQUAL "Windows")
        set (gradlew_cmd "gradlew.bat")
    else()
         set (gradlew_cmd "./gradlew")
    endif()
    set (gradlew_arg "--rerun-tasks")
    set (gradlew_task "kaptReleaseKotlin")
    execute_process(COMMAND ${gradlew_cmd} ${gradlew_arg} ${gradlew_task}
    WORKING_DIRECTORY "${PROJECT_SOURCE_DIR}/qtjenny_baseclass")
    execute_process(COMMAND ${gradlew_cmd} ${gradlew_arg} ${gradlew_task}
    WORKING_DIRECTORY "${PROJECT_SOURCE_DIR}/qtjenny_general")
    execute_process(COMMAND ${gradlew_cmd} ${gradlew_arg} ${gradlew_task}
    WORKING_DIRECTORY "${PROJECT_SOURCE_DIR}/qtjenny_callback")
else()
    message(FATAL_ERROR "Example only works on Android")
endif()

Al ejecutar el proyecto qtjenny_consumer se inicia la aplicación de interfaz de usuario.

Generación de las cabeceras C

La ejecución de la tarea kaptReleaseKotlin en los proyectos gradle lanza un procesador de anotaciones que procesa las anotaciones declaradas en GenerateCppCode.kt.

Fragmento de código del archivo GenerateCppCode.kt de qtjenny_general:

@NativeClass
@NativeProxy(allMethods = false, allFields = false)
@NativeProxyForClasses(namespace = "android::os", classes = [BatteryManager::class, VibratorManager::class,
    Vibrator::class, VibrationEffect::class, Context::class, PowerManager::class, PowerManager.WakeLock::class,
    Handler::class, Looper::class])
@NativeProxyForClasses(namespace = "android::view", classes = [Window::class, WindowManager.LayoutParams::class])
@NativeProxyForClasses(namespace = "android::media", classes = [AudioManager::class])
@NativeProxyForClasses(namespace = "android::drawable", classes = [android.R.drawable::class])
@NativeProxyForClasses(namespace = "android::app", classes = [Activity::class, Notification::class,
    Notification.Builder::class, NotificationChannel::class, NotificationManager::class])
@NativeProxyForClasses(namespace = "android::provider", classes = [Settings.Global::class, Settings.System::class,
    Settings::class])
@NativeProxyForClasses(namespace = "android::content", classes = [Intent::class, ContentResolver::class])

En el caso de qtjenny_general el procesador de anotaciones genera las cabeceras C++ al directorio qtjenny_output. Estas cabeceras C++ contienen el código JNI necesario para acceder a las APIs de Android utilizadas en qtjenny_consumer.

El script build.gradle a nivel de aplicación en qtjenny_general especifica los argumentos para kapt que QtJenny implementa. Estos argumentos se analizan en el compilador de QtJenny y se utilizan en el proceso de generación.

kapt {
    arguments {
        // pass arguments to jenny
        arg("jenny.outputDirectory", project.file("../../qtjenny_output"))
        arg("jenny.templateDirectory", project.file("../templates"))
        arg("jenny.headerOnlyProxy", "true")
        arg("jenny.useJniHelper", "false")
        arg("jenny.useTemplates", "true")
    }
}
qtjenny_general

qtjenny_general se encarga de generar envoltorios para clases Java, para permitir la construcción de objetos Java y la invocación de métodos sobre ellos. Estas envolturas envuelven las llamadas a métodos habituales, y para las devoluciones de llamada se utilizan qtjenny_baseclass y qtjenny_callback.

qtjenny_baseclass

qtjenny_baseclass permite ampliar la clase Java ContentObserver en código C++, utilizando una combinación de la generación de la clase base y la generación de callbacks.

qtjenny_callback

qtjenny_callback permite implementar una interfaz Java en código C++. La extensión de la clase qtjenny_baseclass también utiliza este mecanismo.

Para implementar una interfaz, se construye una clase Java Proxy, utilizando un InvocationHandler que realiza llamadas a funciones virtuales en la jerarquía de clases C++ generada.

Para extender una clase base, la clase extendida generada realiza llamadas a funciones virtuales en la jerarquía de clases C++ generada.

Utilización de las cabeceras C++ generadas en la aplicación Qt Quick

qtjenny_consumer es la aplicación Qt Quick que utiliza las cabeceras C++ generadas por qtjenny_general. Incluimos las cabeceras generadas en el archivo backend.h y las utilizamos en backend.cpp para acceder a varias APIs de Android.

La interfaz de usuario de la aplicación consta de un archivo Main.qml, que está conectado a la clase BackEnd mediante las macros Q_INVOKABLE y Q_PROPERTY.

La UI contiene los siguientes controles y acciones.

Despertar bloqueos

Puede activar y desactivar bloqueos de activación totales o parciales utilizando Switches. Estos interruptores activan las funciones correspondientes de Q_INVOKABLE de la clase Backend, que activan el bloqueo de activación y establecen el texto de estado de bloqueo de activación que se mostrará al usuario en la interfaz de usuario.

if (checked) {
    myBackEnd.setFullWakeLock()
    if (partialWakeLock.checked)
        partialWakeLock.click()
    mainWindow.wakeLockStatus = "Full WakeLock active"

La configuración del bloqueo parcial del despertador utiliza la clase WakeLockProxy que se conecta a la API de Android PowerManager.WakeLock. El bloqueo completo se realiza utilizando WindowProxy que se conecta a Window Android API.

Vibrar

Puedes activar una vibración utilizando la función BackEnd::vibrate(), que utiliza las clases VibrationEffectProxy, VibratorManagerProxy y VibratorProxy para crear la vibración.

Notificaciones

El envío de una notificación se gestiona en la función BackEnd::notfy() en Backend con el uso de la clase NotificationManagerProxy.

La notificación ya se ha creado durante la inicialización de la clase Backend en la función BackEnd::createNotification().

Ajuste del brillo

El ajuste del brillo con el control deslizante de brillo en la interfaz de usuario provoca un cambio de propiedad en la clase Backend que se gestionará en la función BackEnd::setBrightness(). Allí el brillo del sistema se ajusta con el uso de las clases SettingsProxy, SystemProxy, ContextProxy, LayoutParamsProxy y WindowProxy.

El deslizador de brillo se sincroniza dinámicamente con el brillo del sistema, por lo que si el brillo del sistema se cambia desde fuera de la aplicación, el deslizador de brillo se ajusta para reflejar el brillo actual del sistema.

Si la aplicación no tiene permiso para escribir la configuración del sistema, se inicia un Activity con la intención ACTION_MANAGE_WRITE_SETTINGS. Después de iniciar este Activity, el usuario tiene que dar permiso manualmente a la aplicación para que escriba los ajustes del sistema.

Ajustar el volumen

Ajustar el volumen con el deslizador de volumen en la interfaz de usuario provoca un cambio de propiedad en la clase Backend que se gestionará en la función BackEnd::setVolume(). Allí el volumen del sistema se ajusta con el uso de la clase AudioManagerProxy.

El deslizador de volumen se sincroniza dinámicamente con el volumen de la música del sistema, por lo que si el volumen de la música del sistema se cambia desde fuera de la aplicación, el deslizador de volumen se ajusta para reflejar el volumen actual de la música del sistema.

Proyecto de ejemplo @ code.qt.io

© 2026 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.