QtJenny:生成用于访问 Android API 的 C++ 代理类
展示 QtJenny 使用方法的演示。

概述
本演示展示了QtJenny的使用方法,并利用它生成 C++ 代理类,以便从 C++ 代码访问 Android API。 生成的 C++ 类用于本演示的 UI 应用程序中,以执行诸如调节音量和亮度、启用和禁用唤醒锁、发送通知以及触发振动等操作。这些操作属于 Qt 未实现的 Android API 功能。
使用 QtJenny 生成 C++ 类,可免去手动编写JNI代码的麻烦。
工作原理
该演示包含两个不同的部分:其一是用户界面应用程序,即名为qtjenny_consumer 的Qt Quick 项目,该项目使用 QtJenny 生成的代码;其二是由三个不同的 Gradle 项目(qtjenny_general 、qtjenny_callback 和qtjenny_baseclass )组成的组合,这些项目共同负责使用 QtJenny 进行代码生成。 这三个 Gradle 项目中,每个都包含用于 QtJenny 代码生成的类注解和Gradle 配置。
在qtjenny_consumer 项目的CMake配置过程中,通过在qtjenny_general 、qtjenny_callback 和qtjenny_baseclass 这三个Gradle项目中分别执行kaptReleaseKotlin Gradle任务,会自动触发QtJenny的代码生成。
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()运行qtjenny_consumer 项目即可启动 UI 应用程序。
生成 C++ 头文件
在 Gradle 项目中运行kaptReleaseKotlin 任务会触发一个注解处理器,该处理器会处理在GenerateCppCode.kt 中声明的注解。
以下是qtjenny_general 中GenerateCppCode.kt 文件的代码片段:
@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])对于qtjenny_general ,注解处理器会将生成的C++头文件写入qtjenny_output 目录。这些C++头文件包含了访问qtjenny_consumer 中使用的Android API所需的JNI模板代码。
位于qtjenny_general 中的应用级build.gradle 脚本指定了kapt的参数,而 QtJenny 实现了该工具。这些参数将在 QtJenny 编译器中进行解析,并用于代码生成过程。
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 负责为 Java 类生成包装器,以便构建 Java 对象并调用其方法。这些包装器封装了常规的方法调用;对于回调,则使用 qtjenny_baseclass 和 qtjenny_callback。
qtjenny_baseclass
qtjenny_baseclass 通过结合基类生成和回调生成功能,实际上允许在 C++ 代码中扩展 Java 类 ContentObserver。
qtjenny_callback
qtjenny_callback 实际上允许在 C++ 中实现 Java 接口。继承自该类的qtjenny_baseclass 类同样采用了这一机制。
为了实现一个接口,会构建一个 Java 代理类,该类使用 InvocationHandler 来执行虚拟函数调用,并将调用传递给生成的 C++ 类层次结构。
对于基类的继承,生成的派生类会向生成的 C++ 类层次结构中发出虚函数调用。
在Qt Quick 应用程序中使用生成的C++头文件
qtjenny_consumer 是Qt Quick 应用程序,它使用由qtjenny_general 生成的C++头文件。我们将生成的头文件包含在backend.h 文件中,并在backend.cpp 中使用它们来访问各种Android API。
该应用的用户界面由一个Main.qml 文件组成,该文件通过Q_INVOKABLE 和Q_PROPERTY 宏与BackEnd 类相连。
该用户界面包含以下控件和操作。
唤醒锁
您可以使用Switches 来启用或禁用完全或部分唤醒锁。这些开关会触发Backend 类中的相应Q_INVOKABLE 函数,这些函数会激活唤醒锁,并设置将在用户界面中显示给用户的唤醒锁状态文本。
if (checked) {
myBackEnd.setFullWakeLock()
if (partialWakeLock.checked)
partialWakeLock.click()
mainWindow.wakeLockStatus = "Full WakeLock active"设置部分唤醒锁需使用WakeLockProxy 类,该类连接到PowerManager.WakeLock Android API。设置完整唤醒锁则需使用WindowProxy 类,该类连接到Window Android API。
振动
您可以通过BackEnd::vibrate() 函数触发振动,该函数利用VibrationEffectProxy 、VibratorManagerProxy 和VibratorProxy 类来生成振动。
通知
发送通知由位于Backend 中的BackEnd::notfy() 函数处理,该函数使用NotificationManagerProxy 类。
通知已在BackEnd::createNotification() 函数中Backend 类的初始化过程中创建完毕。
调整亮度
通过 UI 中的亮度滑块调整亮度会触发Backend 类的属性变更,该变更将在BackEnd::setBrightness() 函数中进行处理。在此处,系统会通过SettingsProxy 、SystemProxy 、ContextProxy 、LayoutParamsProxy 和WindowProxy 类来调整系统亮度。
亮度滑块会与系统亮度进行动态同步,因此如果从应用程序外部更改了系统亮度,亮度滑块会随之调整以反映当前的系统亮度。
如果应用程序没有写入系统设置的权限,则会通过ACTION_MANAGE_WRITE_SETTINGS 意图启动一个Activity 。该Activity 启动后,用户必须手动授予应用程序写入系统设置的权限。
调节音量
通过 UI 中的音量滑块调节音量会触发Backend 类中的属性变更,该变更将在BackEnd::setVolume() 函数中进行处理。在此处,系统将通过AudioManagerProxy 类来调节系统音量。
音量滑块会与系统音乐音量进行动态同步,因此如果从应用程序外部更改了系统音乐音量,音量滑块会相应调整以反映当前的系统音乐音量。
© 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.