티스토리 뷰

Android/JNI, AIDL

[NDK] JNI 고급

이주성 2012. 12. 28. 14:57

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를 막쓰면 된다. 

SimpleJNI.tar.gz


log.h


'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
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함