이 페이지에서

QtJenny: 안드로이드 API에 액세스하기 위한 C++ 프록시 클래스 생성하기

QtJenny의 사용법을 보여주는 데모입니다.

개요

이 데모는 QtJenny를 사용하여 C++ 코드에서 안드로이드 API에 액세스하기 위한 C++ 프록시 클래스를 생성하는 방법을 보여줍니다. 생성된 C++ 클래스는 이 데모의 UI 애플리케이션에서 볼륨 및 밝기 조정, 깨우기 잠금 활성화 및 비활성화, 알림 전송 및 진동 트리거와 같은 작업을 수행하는 데 사용됩니다. 이러한 동작은 Qt가 구현하지 않는 안드로이드 API의 일부입니다.

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

작동 방식

이 데모에는 두 가지 특징적인 부분이 있는데, 하나는 UI 애플리케이션, 즉 QtJenny에서 생성된 코드를 사용하는 qtjenny_consumer 이라는 Qt Quick 프로젝트이고, 다른 하나는 QtJenny를 사용하여 코드 생성을 함께 처리하는 qtjenny_general, qtjenny_callbackqtjenny_baseclass 이라는 세 가지 Gradle 프로젝트의 조합입니다. 세 개의 Gradle 프로젝트 각각에는 QtJenny 코드 생성을 위한 클래스 어노네이션과 Gradle 구성이 포함되어 있습니다.

qtjenny_general, qtjenny_callbackqtjenny_baseclass gradle 프로젝트에서 kaptReleaseKotlin gradle 작업을 실행하여 qtjenny_consumer 프로젝트의 CMake 구성 중에 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_generalGenerateCppCode.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 Qt Quick 애플리케이션은 에서 생성된 C++ 헤더를 사용합니다. 생성된 헤더를 파일에 포함시키고 에서 사용하여 다양한 Android API에 액세스합니다. qtjenny_general backend.h backend.cpp

앱의 UI는 Q_INVOKABLEQ_PROPERTY 매크로를 사용하여 BackEnd 클래스에 연결되는 하나의 Main.qml 파일로 구성됩니다.

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 클래스를 사용합니다.

진동

VibrationEffectProxy, VibratorManagerProxyVibratorProxy 클래스를 사용하여 진동을 생성하는 BackEnd::vibrate() 함수를 사용하여 진동을 트리거할 수 있습니다.

알림

알림 전송은 BackendBackEnd::notfy() 함수에서 NotificationManagerProxy 클래스를 사용하여 처리합니다.

알림은 BackEnd::createNotification() 함수의 Backend 클래스 초기화 중에 이미 생성됩니다.

밝기 조정하기

UI의 밝기 슬라이더로 밝기를 조정하면 BackEnd::setBrightness() 함수에서 처리될 Backend 클래스의 속성 변경이 트리거됩니다. 여기서 시스템 밝기는 SettingsProxy, SystemProxy, ContextProxy, LayoutParamsProxyWindowProxy 클래스를 사용하여 조정됩니다.

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

애플리케이션에 시스템 설정 쓰기 권한이 없는 경우 ACTION_MANAGE_WRITE_SETTINGS 인텐트로 Activity 가 시작됩니다. 이 Activity 가 시작된 후에는 사용자가 애플리케이션에 시스템 설정 쓰기 권한을 수동으로 부여해야 합니다.

볼륨 조절하기

UI에서 볼륨 슬라이더로 볼륨을 조정하면 BackEnd::setVolume() 함수에서 처리할 Backend 클래스의 속성 변경이 트리거됩니다. 여기서 시스템 볼륨은 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.