이 페이지에서

QtJenny: Android API에 접근하기 위한 C++ 프록시 클래스 생성

QtJenny 사용법을 보여주는 데모.

볼륨, 밝기 및 웨이크 잠금 제어 기능이 포함된 QtJenny 데모 애플리케이션

개요

이 데모는 QtJenny의 사용법을 보여주며, 이를 통해 C++ 코드에서 Android API에 접근하기 위한 C++ 프록시 클래스를 생성합니다. 생성된 C++ 클래스는 이 데모의 UI 애플리케이션에서 볼륨 및 밝기 조절, 웨이크 잠금 활성화 및 비활성화, 알림 전송, 진동 작동 등의 작업을 수행하는 데 사용됩니다. 이러한 작업들은 Qt에서 구현하지 않는 Android API의 일부입니다.

QtJenny를 사용하여 C++ 클래스를 생성하면 JNI 코드를 수동으로 작성할 필요가 없습니다.

작동 원리

이 데모는 두 가지 뚜렷한 부분으로 구성되어 있습니다. 하나는 QtJenny가 생성한 코드를 사용하는 UI 애플리케이션, 즉 Qt Quick 프로젝트인 qtjenny_consumer 이며, 다른 하나는 qtjenny_general, qtjenny_callback, qtjenny_baseclass 라는 세 개의 서로 다른 Gradle 프로젝트로, 이 프로젝트들이 함께 QtJenny를 사용하여 코드 생성을 처리합니다. 이 세 개의 Gradle 프로젝트에는 각각 QtJenny 코드 생성을 위한 클래스 어노테이션과 Gradle 구성이 포함되어 있습니다.

QtJenny 코드 생성은 qtjenny_consumer 프로젝트의 CMake 구성 과정에서 qtjenny_general, qtjenny_callback 및 qtjenny_baseclass Gradle 프로젝트 각각에서 kaptReleaseKotlin 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()

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 의 경우, 어노테이션 프로세서는 qtjenny_output 디렉터리에 C++ 헤더 파일을 생성합니다. 이 C++ 헤더 파일에는 qtjenny_consumer 에서 사용되는 Android API에 접근하는 데 필요한 JNI 보일러플레이트 코드가 포함되어 있습니다.

qtjenny_general 에 있는 앱 레벨 build.gradle 스크립트는 QtJenny가 구현하는 kapt의 인수를 지정합니다. 이러한 인수는 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 클래스의 상속 역시 이 메커니즘을 사용합니다.

인터페이스를 구현하기 위해, 생성된 C++ 클래스 계층 구조 내에서 가상 함수 호출을 수행하는 InvocationHandler를 사용하여 Java 프록시 클래스가 생성됩니다.

기초 클래스를 상속할 경우, 생성된 상속 클래스는 생성된 C++ 클래스 계층 구조 내에서 가상 함수 호출을 수행합니다.

Qt Quick 애플리케이션에서 생성된 C++ 헤더 사용

qtjenny_consumer 은 qtjenny_general 에서 생성된 C++ 헤더를 사용하는 Qt Quick 애플리케이션입니다. 생성된 헤더를 backend.h 파일에 포함시키고, backend.cpp 에서 이를 사용하여 다양한 Android API에 접근합니다.

이 앱의 UI는 하나의 Main.qml 파일로 구성되어 있으며, 이 파일은 Q_INVOKABLE 및 Q_PROPERTY 매크로를 통해 BackEnd 클래스와 연결되어 있습니다.

UI에는 다음과 같은 컨트롤과 액션이 포함되어 있습니다.

웨이크 잠금

Switches 를 사용하여 전체 또는 부분 웨이크 락을 활성화하거나 비활성화할 수 있습니다. 이 스위치들은 Backend 클래스의 해당 Q_INVOKABLE 함수를 호출하며, 이 함수들은 웨이크 락을 활성화하고 UI에서 사용자에게 표시될 웨이크 락 상태 텍스트를 설정합니다.

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

부분 웨이크 락을 설정할 때는 PowerManager.WakeLock Android API와 연동되는 WakeLockProxy 클래스를 사용합니다. 전체 웨이크 락을 설정할 때는 Window Android API와 연동되는 WindowProxy 를 사용합니다.

진동

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 클래스를 사용하여 시스템 볼륨이 조절됩니다.

볼륨 슬라이더는 시스템 음악 볼륨과 동적으로 동기화되므로, 애플리케이션 외부에서 시스템 음악 볼륨이 변경되면 볼륨 슬라이더가 현재 시스템 음악 볼륨을 반영하도록 조정됩니다.

예제 프로젝트 @ 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.