QtJenny : Générer des classes proxy C++ pour accéder aux API Android
Démonstration de l'utilisation de QtJenny.

Vue d'ensemble
Cette démo présente l'utilisation de QtJenny et l'utilise pour générer des classes proxy C++ afin d'accéder aux API Android à partir d'un code C++. Les classes C++ générées sont utilisées dans l'application d'interface utilisateur de cette démo pour effectuer des actions telles que le réglage du volume et de la luminosité, l'activation et la désactivation des verrous de réveil, l'envoi de notifications et le déclenchement de vibrations. Ces actions font partie des API d'Android que Qt n'implémente pas.
La génération de classes C++ à l'aide de QtJenny élimine la nécessité d'écrire manuellement du code JNI.
Comment fonctionne QtJenny ?
La démo contient deux parties distinctes, l'une est l'application UI, c'est-à-dire le projet Qt Quick appelé qtjenny_consumer qui utilise le code généré par QtJenny, et l'autre est une combinaison de trois projets Gradle différents appelés qtjenny_general, qtjenny_callback et qtjenny_baseclass qui gèrent ensemble la génération de code à l'aide de QtJenny. Chacun des trois projets Gradle contient des annonces de classes et des configurations Gradle pour la génération de code QtJenny.
La génération de code QtJenny est déclenchée automatiquement lors de la configuration CMake du projet qtjenny_consumer par l'exécution de la tâche kaptReleaseKotlin gradle dans chacun des projets qtjenny_general, qtjenny_callback et qtjenny_baseclass gradle.
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()L'exécution du projet qtjenny_consumer lance l'application de l'interface utilisateur.
Génération des en-têtes C
L'exécution de la tâche kaptReleaseKotlin dans les projets gradle déclenche un processeur d'annotations qui traite les annotations déclarées dans GenerateCppCode.kt.
Extrait de code du fichier 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])Dans le cas de qtjenny_general, le processeur d'annotation génère les en-têtes C++ dans le répertoire qtjenny_output. Ces en-têtes C++ contiennent le code JNI boilerplate nécessaire pour accéder aux API Android utilisées dans le fichier qtjenny_consumer.
Le script build.gradle au niveau de l'application dans qtjenny_general spécifie les arguments pour kapt que QtJenny implémente. Ces arguments sont analysés par le compilateur de QtJenny et utilisés dans le processus de génération.
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
Le site qtjenny_general se charge de générer des wrappers pour les classes Java, afin de permettre la construction d'objets Java et l'invocation de méthodes sur ces objets. Ces wrappers enveloppent les appels de méthodes habituels, et pour les callbacks, les qtjenny_baseclass et qtjenny_callback sont utilisés.
qtjenny_baseclass
Le site qtjenny_baseclass permet d'étendre la classe Java ContentObserver en code C++, en utilisant une combinaison de la génération de la classe de base et de la génération de la fonction de rappel.
qtjenny_callback
L'adresse qtjenny_callback permet d'implémenter une interface Java en C++. L'extension de la classe qtjenny_baseclass utilise également ce mécanisme.
Pour implémenter une interface, une classe Java Proxy est construite, utilisant un InvocationHandler qui effectue des appels de fonctions virtuelles dans la hiérarchie de classes C++ générée.
Pour l'extension d'une classe de base, la classe étendue générée effectue des appels de fonctions virtuelles dans la hiérarchie de classes C++ générée.
Utilisation des en-têtes C++ générés dans l'application Qt Quick
L'application qtjenny_consumer est l'application Qt Quick qui utilise les en-têtes C++ générés par qtjenny_general. Nous incluons les en-têtes générés dans le fichier backend.h et les utilisons dans backend.cpp pour accéder à diverses API Android.
L'interface utilisateur de l'application consiste en un fichier Main.qml, qui est connecté à la classe BackEnd à l'aide des macros Q_INVOKABLE et Q_PROPERTY.
L'interface utilisateur contient les contrôles et actions suivants.
Réveiller les serrures
Vous pouvez activer et désactiver les verrous de réveil complets ou partiels à l'aide de Switches. Ces commutateurs déclenchent les fonctions Q_INVOKABLE correspondantes de la classe Backend, qui activent le verrou de réveil et définissent le texte d'état du verrou de réveil qui sera affiché à l'utilisateur dans l'interface utilisateur.
if (checked) { myBackEnd.setFullWakeLock() if (partialWakeLock.checked) partialWakeLock.click() mainWindow.wakeLockStatus = "Full WakeLock active"
Le réglage du verrouillage partiel du réveil utilise la classe WakeLockProxy qui se connecte à l'API Android PowerManager.WakeLock. Le verrouillage complet se fait à l'aide de la classe WindowProxy qui se connecte à l'API Android Window.
Vibreur
Vous pouvez déclencher une vibration à l'aide de la fonction BackEnd::vibrate(), qui utilise les classes VibrationEffectProxy, VibratorManagerProxy et VibratorProxy pour créer la vibration.
Notifications
L'envoi d'une notification est géré par la fonction BackEnd::notfy() dans Backend, qui utilise la classe NotificationManagerProxy.
La notification est déjà créée lors de l'initialisation de la classe Backend dans la fonction BackEnd::createNotification().
Réglage de la luminosité
Le réglage de la luminosité à l'aide du curseur de luminosité dans l'interface utilisateur déclenche un changement de propriété dans la classe Backend qui sera traité dans la fonction BackEnd::setBrightness(). La luminosité du système y est ajustée à l'aide des classes SettingsProxy, SystemProxy, ContextProxy, LayoutParamsProxy et WindowProxy.
Le curseur de luminosité est synchronisé dynamiquement avec la luminosité du système, de sorte que si la luminosité du système est modifiée depuis l'extérieur de l'application, le curseur de luminosité s'ajuste pour refléter la luminosité actuelle du système.
Si l'application n'a pas la permission d'écrire les paramètres du système, une page Activity est lancée avec l'intention ACTION_MANAGE_WRITE_SETTINGS. Après le démarrage de Activity, l'utilisateur doit manuellement autoriser l'application à écrire les paramètres du système.
Réglage du volume
Le réglage du volume à l'aide du curseur de volume dans l'interface utilisateur déclenche un changement de propriété dans la classe Backend qui sera traité dans la fonction BackEnd::setVolume(). Le volume du système y est ajusté à l'aide de la classe AudioManagerProxy.
Le curseur de volume est synchronisé dynamiquement avec le volume de la musique du système. Ainsi, si le volume de la musique du système est modifié depuis l'extérieur de l'application, le curseur de volume s'ajuste pour refléter le volume actuel de la musique du système.
© 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.