티스토리 뷰
JNI 고급과정
JNI초급 과정에서 JNI header파일을 이용한 JNI를 배웠다. 그러나 JNI methods가 여러개 이면 어떻게 할까? 생각만 복잡해 보인다. 그래서 복잡한 JNI에서는 JNI_OnLoad같은 API를 사용하여 수동으로 native method를 등록한다. 먼저 java파일을 보자. 초급과정에서는 간단한 sum메소드를 구현해 봤는데 이번엔 추가로 String을 리턴해 주는 기능도 구현해 보자.
ackage com.example.testjni; import android.app.Activity; import android.os.Bundle; import android.util.Log; import android.view.Menu; public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); int sum = add (2, 3); Log.v("TEST", "sum = " + sum); Log.v("TEST", "sum = " + stringFromJni()); } static { System.loadLibrary("testjni"); } native int add(int a, int b); native String stringFromJni(); }
Native C++
JNI초급과정에서는 C로 했었는데.. 고급과정에서는 CPP로 하겠다. 이유는 JNI c++코드가 더 편해서다. 다음 소스를 봐라.. 아래 코드에는 동일한 코드를 C버전, C++버전으로 작성해 봤다. 어떤 코드가 더 쉬운가? C++이 더 편하고, 짧다. NDK가 C, C++ 용 API를 모두 제공하고 있으나. 난 c++이 좋다. env를 매번 아규먼트로 넘기는게 좀.. 그렇다.
jstring Java_stringFromJNI (JNIEnv* env, jobject thiz) { (*env)->NewStringUTF(env, "hello"); // c코드 env->NewStringUTF("hello"); // c++코드 }
Header File
JNI_OnLoad와 registerNativeMethods 를 쓸거면 header파일이 필요없다. library가 인스톨될때 수동적으로 등록을 한다 앞에서 말했듯이 native code가 c++이다. Frameworks JNI과정처럼 JNINativeMethods 구조체에 함수들을 정의하고 registerNativeMethods를 통해서 등록을한다. 그리고 등록은 so library가 처음 load될때 등록이 된다#define LOG_TAG "native.cpp" #include "log.h" #include <stdio.h> #include "jni.h" jstring stringFromJNI(JNIEnv* env, jobject thiz) { return env->NewStringUTF("hello"); } static jint add(JNIEnv *env, jobject thiz, jint a, jint b) { int result = a + b; LOGI("%d + %d = %d", a, b, result); return result; } static const char *classPathName = "com/example/testjni/MainActivity"; static JNINativeMethod methods[] = { {"stringFromJni", "()Ljava/lang/String;", (void*)stringFromJNI}, {"add", "(II)I", (void*)add }, }; static int registerNativeMethods(JNIEnv* env, const char* className, JNINativeMethod* gMethods, int numMethods) { jclass clazz; clazz = env->FindClass(className); if (clazz == NULL) { LOGE("Native registration unable to find class '%s'", className); return JNI_FALSE; } if (env->RegisterNatives(clazz, gMethods, numMethods) < 0) { LOGE("RegisterNatives failed for '%s'", className); return JNI_FALSE; } return JNI_TRUE; } static int registerNatives(JNIEnv* env) { if (!registerNativeMethods(env, classPathName, methods, sizeof(methods) / sizeof(methods[0]))) { return JNI_FALSE; } return JNI_TRUE; } /* * This is called by the VM when the shared library is first loaded. */ jint JNI_OnLoad(JavaVM* vm, void* reserved) { jint result = -1; JNIEnv* env = NULL; LOGI("JNI_OnLoad"); if (vm->GetEnv((void**)&env, JNI_VERSION_1_4) != JNI_OK) { LOGE("ERROR: GetEnv failed"); goto bail; } if (registerNatives(env) != JNI_TRUE) { LOGE("ERROR: registerNatives failed"); goto bail; } result = JNI_VERSION_1_4; bail: return result; }
Android.mk
make파일을 다음과 같다.. 간단하다..
OCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := libtestjni LOCAL_SRC_FILES := native.cpp LOCAL_LDLIBS += -llog LOCAL_LDLIBS += -landroid include $(BUILD_SHARED_LIBRARY)
지금까지 JNI고급과정을 배웠다.. 그리고 LOG를 간편하게 하기 위해서 log.h파일을 첨부한다. #include"log.h"만하고 LOGV, LOGE를 막쓰면 된다.
'Android > JNI, AIDL' 카테고리의 다른 글
Secure Sharing a Service between two application (0) | 2013.08.19 |
---|---|
Remote Service using AIDL (0) | 2013.06.04 |
Android Service (0) | 2013.01.21 |
[NDK] JNI 초급 (0) | 2012.12.27 |
댓글