반응형

 

Keyboard라는 싱글돈 객체가 있다. 아래와 같이 호출 구조를 따르는 경우에 대해서, 코드를 작성해 본다.

 

 

MainActivity.java

public class MainActivity extends AppCompatActivity {
	...
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        ...
        Log.i(TAG, "Keyboard instance = Keyboard.getInstance();");
        Keyboard instance = Keyboard.getInstance();
        Log.i(TAG, "instance.onClick();");
        instance.onClick();
        ...
    }
...

 

 

Keyboard.java

package edu.gatech.seclass.sdpencryptor;

import android.util.Log;

public class Keyboard {

    static {
        System.loadLibrary("native-lib");
    }

    private static String TAG = "TEST123";

    private static Keyboard sMe = null;

    private Keyboard() { }

    public static Keyboard getInstance() {
        if (sMe == null) {
            sMe = new Keyboard();
        }
        return sMe;
    }

    public void onNotified(String type, byte[] data) {
        Log.i(TAG, "onClick. type: " + type + ", data: " + new String(data));
    }

    public native void onClick();
}

 

 

cpp/native-lib.cpp

#include <jni.h>
#include <string>
#include <android/log.h>
#include <stdio.h>
#include <string.h>

static JavaVM* gJavaVm;
static jclass gKeyboardClass;

#define LOG_TAG "TEST123"
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)

JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved __attribute__((unused))) {
    JNIEnv *env;

    if (vm->GetEnv((void **) &env, JNI_VERSION_1_6) != JNI_OK) {
        LOGE("Failed to get JNI environment");
        return -1;
    }

    gJavaVm = vm;

    gKeyboardClass = env->FindClass("edu/gatech/seclass/sdpencryptor/Keyboard");

    if (gKeyboardClass == NULL) {
        return -1;
    }
    gKeyboardClass = (jclass) env->NewGlobalRef(gKeyboardClass);

    // 반드시 return을 해주어야 한다. 그렇지 않으면 에러 발생한다.
    return JNI_VERSION_1_6;
}


extern "C" JNIEXPORT jstring JNICALL
Java_edu_gatech_seclass_sdpencryptor_MainActivity_stringFromJNI(JNIEnv* env, jobject /* this */) {
    std::string hello = "Hello from C++";
    return env->NewStringUTF(hello.c_str());
}

extern "C"
JNIEXPORT void JNICALL
Java_edu_gatech_seclass_sdpencryptor_Keyboard_onClick(JNIEnv *env, jobject thiz) {

    // 1. 정적 메서드 ID 얻기
    jmethodID getInstanceMethod = env->GetStaticMethodID(gKeyboardClass, "getInstance",
                                                         "()Ledu/gatech/seclass/sdpencryptor/Keyboard;");

    if (getInstanceMethod == NULL) {
        printf("Failed to get getInstance method ID\n");
        return; // 메서드가 존재하지 않으면 종료
    }

    // 2. 정적 메서드 호출 (객체를 얻기 위해)
    jobject keyboardInstance = env->CallStaticObjectMethod(gKeyboardClass,
                                                           getInstanceMethod);
    if (keyboardInstance == NULL) {
        printf("Failed to call getInstance method\n");
        return; // 메서드 호출 실패 시 종료
    }

    // 여기 까지 Single 객체 얻는 것이 완료.
    // ---- ---- ---- ---- ---- ---- ---- ----

    // 4. 해당 객체에서, onNotified 메서드 ID 얻기
    jmethodID onNotifiedMethod = env->GetMethodID(gKeyboardClass, "onNotified", "(Ljava/lang/String;[B)V");
    if (onNotifiedMethod == NULL) {
        printf("Failed to get onNotified method ID\n");
        return; // 메서드가 존재하지 않으면 종료
    }

    // type에 "SHIFT" 문자열 전달
    jstring type = env->NewStringUTF("SHIFT");

    // data에 "hello world" 문자열 바이트 배열로 전달
    const char* helloWorld = "hello world";
    jbyteArray data = env->NewByteArray(strlen(helloWorld));
    env->SetByteArrayRegion(data, 0, strlen(helloWorld), (const jbyte*)helloWorld);

    // onNotified 메서드 호출
    env->CallVoidMethod(keyboardInstance, onNotifiedMethod, type, data);

    // 예외 체크
    if (env->ExceptionCheck()) {
        env->ExceptionDescribe();
        env->ExceptionClear();
    }
}

 

 

출력 결과화면

2024-08-09 00:57:58.899 29312-29312 TEST123                 edu.gatech.seclass.sdpencryptor      I  Keyboard instance = Keyboard.getInstance();
2024-08-09 00:57:58.900 29312-29312 TEST123                 edu.gatech.seclass.sdpencryptor      I  instance.onClick();
2024-08-09 00:57:58.900 29312-29312 TEST123                 edu.gatech.seclass.sdpencryptor      I  onClick. type: SHIFT, data: hello world

 

반응형