QtJenny: Generierung von C++-Proxy-Klassen für den Zugriff auf Android-APIs
Demo zur Veranschaulichung der Verwendung von QtJenny.

Übersicht
Diese Demo veranschaulicht die Verwendung von QtJenny und nutzt es, um C++-Proxy-Klassen zu generieren, die den Zugriff auf Android-APIs aus C++-Code ermöglichen. Die generierten C++-Klassen werden in der UI-Anwendung dieser Demo verwendet, um Aktionen wie das Anpassen der Lautstärke und Helligkeit, das Aktivieren und Deaktivieren von Wake-Locks, das Senden von Benachrichtigungen und das Auslösen von Vibrationen durchzuführen. Diese Aktionen sind Teil der Android-APIs, die Qt nicht implementiert.
Durch die Generierung von C++-Klassen mit QtJenny entfällt die Notwendigkeit, JNI-Code manuell zu schreiben.
So funktioniert es
Die Demo besteht aus zwei unterschiedlichen Teilen: Zum einen aus der UI-Anwendung, d. h. dem Projekt „ Qt Quick “ mit dem Namen „ qtjenny_consumer “, das den von QtJenny generierten Code verwendet, und zum anderen aus einer Kombination von drei verschiedenen Gradle-Projekten mit den Namen „ qtjenny_general “, „ qtjenny_callback “ und „ qtjenny_baseclass “, die gemeinsam die Codegenerierung mit QtJenny übernehmen. Jedes der drei Gradle-Projekte enthält Klassenannotationen und „ Gradle “-Konfigurationen für die QtJenny-Codegenerierung.
Die QtJenny-Codegenerierung wird während der CMake-Konfiguration des Projekts „ qtjenny_consumer “ automatisch ausgelöst, indem in jedem der Gradle-Projekte „ qtjenny_general “, „ qtjenny_callback “ und „ qtjenny_baseclass “ die Gradle-Aufgabe „ kaptReleaseKotlin “ ausgeführt wird.
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()Durch Ausführen des Projekts „ qtjenny_consumer “ wird die UI-Anwendung gestartet.
Erstellen der C++-Header
Durch das Ausführen der Aufgabe „ kaptReleaseKotlin “ in den Gradle-Projekten wird ein Annotationsprozessor ausgelöst, der die in „ GenerateCppCode.kt “ deklarierten Annotationen verarbeitet.
Codeausschnitt aus der Datei „ GenerateCppCode.kt “ unter 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])Im Fall von „ qtjenny_general “ generiert der Annotationsprozessor die C++-Header im Verzeichnis „ qtjenny_output “. Diese C++-Header enthalten den erforderlichen JNI-Boilerplate-Code für den Zugriff auf die Android-APIs, die in „ qtjenny_consumer “ verwendet werden.
Das Skript „ build.gradle “ auf App-Ebene im Verzeichnis „ qtjenny_general “ legt die Argumente für „kapt“ fest, die von QtJenny implementiert werden. Diese Argumente werden im QtJenny-Compiler analysiert und im Generierungsprozess verwendet.
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
Der „ qtjenny_general “ übernimmt die Generierung von Wrappern für Java-Klassen, um die Erstellung von Java-Objekten und den Aufruf von Methoden auf diesen zu ermöglichen. Diese Wrapper verpacken die üblichen Methodenaufrufe, und für Callbacks werden „qtjenny_baseclass“ und „qtjenny_callback“ verwendet.
qtjenny_baseclass
Die „ qtjenny_baseclass “ ermöglicht es effektiv, die Java-Klasse „ContentObserver“ im C++-Code zu erweitern, indem sie die Generierung von Basisklassen und Callbacks kombiniert.
qtjenny_callback
qtjenny_callback ermöglicht es, eine Java-Schnittstelle in C++ zu implementieren. Auch die Klasse „ qtjenny_baseclass “, die diese Schnittstelle erweitert, nutzt diesen Mechanismus.
Zur Implementierung einer Schnittstelle wird eine Java-Proxy-Klasse erstellt, die einen `InvocationHandler` verwendet, der Aufrufe virtueller Funktionen in die generierte C++-Klassenhierarchie durchführt.
Bei der Erweiterung einer Basisklasse führt die generierte erweiterte Klasse Aufrufe virtueller Funktionen in die generierte C++-Klassenhierarchie durch.
Verwendung der generierten C++-Header in der Anwendung „ Qt Quick “
Die „ qtjenny_consumer “ ist die „ Qt Quick “-Anwendung, die die vom „ qtjenny_general “ generierten C++-Header verwendet. Wir binden die generierten Header in die Datei „ backend.h “ ein und nutzen sie in „ backend.cpp “, um auf verschiedene Android-APIs zuzugreifen.
Die Benutzeroberfläche der App besteht aus einer „ Main.qml “-Datei, die über die Makros „ Q_INVOKABLE “ und „ Q_PROPERTY “ mit der Klasse „ BackEnd “ verknüpft ist.
Die Benutzeroberfläche enthält die folgenden Steuerelemente und Aktionen.
Wake-Locks
Sie können über „ Switches “ entweder vollständige oder teilweise Wake-Locks aktivieren und deaktivieren. Diese Schalter lösen die entsprechenden „ Q_INVOKABLE “-Funktionen der Klasse „ Backend “ aus, die das Wake-Lock aktivieren und den Wake-Lock-Statustext festlegen, der dem Benutzer in der Benutzeroberfläche angezeigt wird.
if (checked) {
myBackEnd.setFullWakeLock()
if (partialWakeLock.checked)
partialWakeLock.click()
mainWindow.wakeLockStatus = "Full WakeLock active"Zum Einrichten eines teilweisen Wake-Locks wird die Klasse ` WakeLockProxy ` verwendet, die eine Verbindung zur Android-API ` PowerManager.WakeLock ` herstellt. Das Einrichten eines vollständigen Wake-Locks erfolgt mithilfe der Klasse ` WindowProxy `, die eine Verbindung zur Android-API ` Window ` herstellt.
Vibrieren
Sie können eine Vibration mithilfe der Funktion ` BackEnd::vibrate() ` auslösen, die die Klassen ` VibrationEffectProxy`, ` VibratorManagerProxy ` und ` VibratorProxy ` verwendet, um die Vibration zu erzeugen.
Benachrichtigungen
Das Senden einer Benachrichtigung wird in der Funktion „ BackEnd::notfy() “ in „ Backend “ unter Verwendung der Klasse „ NotificationManagerProxy “ abgewickelt.
Die Benachrichtigung wird bereits bei der Initialisierung der Klasse „ Backend “ in der Funktion „ BackEnd::createNotification() “ erstellt.
Anpassen der Helligkeit
Das Anpassen der Helligkeit über den Helligkeitsregler in der Benutzeroberfläche löst eine Eigenschaftsänderung in der Klasse ` Backend ` aus, die in der Funktion ` BackEnd::setBrightness() ` verarbeitet wird. Dort wird die Systemhelligkeit mithilfe der Klassen ` SettingsProxy`, ` SystemProxy`, ` ContextProxy`, ` LayoutParamsProxy ` und ` WindowProxy ` angepasst.
Der Helligkeitsregler wird dynamisch mit der Systemhelligkeit synchronisiert. Wenn also die Systemhelligkeit außerhalb der Anwendung geändert wird, passt sich der Helligkeitsregler an die aktuelle Systemhelligkeit an.
Verfügt die Anwendung nicht über die Berechtigung zum Schreiben von Systemeinstellungen, wird ein „ Activity “ mit dem Intent „ ACTION_MANAGE_WRITE_SETTINGS “ gestartet. Nach dem Start dieses „ Activity “ muss der Nutzer der Anwendung manuell die Berechtigung zum Schreiben von Systemeinstellungen erteilen.
Anpassen der Lautstärke
Das Anpassen der Lautstärke über den Lautstärkeregler in der Benutzeroberfläche löst eine Eigenschaftsänderung in der Klasse „ Backend “ aus, die in der Funktion „ BackEnd::setVolume() “ verarbeitet wird. Dort wird die Systemlautstärke mithilfe der Klasse „ AudioManagerProxy “ angepasst.
Der Lautstärkeregler wird dynamisch mit der System-Musiklautstärke synchronisiert. Wenn also die System-Musiklautstärke von außerhalb der Anwendung geändert wird, passt sich der Lautstärkeregler an, um die aktuelle System-Musiklautstärke widerzuspiegeln.
© 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.