java. jni 정리

선언형식


c++ 코드 기본 템플릿입니다.
#include <jni.h>
 
extern "C" {
 
//WINDOWS 용 DLL 작성시는 메소드명은 _Java_ 로 시작합니다.
//
//그 이외 플랫폼에서 메소드명은 Java_ 로 시작합니다. 
//
//제일 앞에 언더바가 있고 없고의 차이가 있습니다.
//참고 : http://micropilot.tistory.com/entry/CDT-JNI-Project
//
//com.acidraincity.jnitest 패키지의 Test 클래스의 getTest 메소드는 다음과 같이 매핑됩니다.

JNIEXPORT jint JNICALL _Java_com_acidraincity_jnitest_Test_getTest( JNIEnv* env, jobject thiz ){
 return 1;
}//function
 
}//extern "C"


자바 객체 생성과 메소드 호출


다음과 같이 자바 객체를 C++ 코드에서 생성하고 메소드 호출할 수 있습니다.

jclass cls = env->FindClass( "some/your/SomeYourJavaClass" );
jmethodID mid = env->GetMethodID( cls, "<init>", "()V" );
jobject obj = env->NewObject( cls, mid );

mid = env->GetMethodID( cls, "someMethodName", "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;" );
jstring rtn = ( jstring ) env->CallObjectMethod( obj, mid, param1, param2 );

env->DeleteLocalRef( cls );
env->DeleteLocalRef( obj );


메소드 시그니쳐는 아래 레퍼런스를 참고하세요.

http://www.rgagnon.com/javadetails/java-0286.html

문자열 처리


문자열 처리에 관한 코드입니다.
//case1 : jstring → const char*

const char* str = env->GetStringUTFChars( someJstring, NULL );
//사용 후에 반드시 release 해야 합니다.
env->ReleaseStringUTFChars( someJstring, str );

//case2 : char* → jstring

char* str = "Happy New Year!!";
jstring jstr = env->NewStringUTF( str );


배열 처리


joubleArray 를 생성해서 리턴하는 코드 예제입니다.
jdoubleArray rtn;
rtn = env->NewDoubleArray( 4 );
jdouble* pRtnValues = env->GetDoubleArrayElements( rtn, NULL );
pRtnValues[ 0 ] = 1.0;
pRtnValues[ 1 ] = 2.0;
pRtnValues[ 2 ] = 3.0;
pRtnValues[ 3 ] = 4.0;
env->ReleaseDoubleArrayElements( rtn, pRtnValues, 0 );
return rtn;

배열 사이즈는 다음 메소드로 조회 가능합니다.
env->GetArrayLength( someArray );


자바와의 데이터 교환


네이티브 코드에서 동적할당한 메모리 데이터를 자바 NIO의 ByteBuffer 객체로 자바에 전달해 핸들링하게 할 수 있습니다.

struct {
  int intVal;
  short shortVal;
} SomeStruct;


SomeStruct* nativeData = new SomeStruct();
jobject jByteBuffer = env->NewDirectByteBuffer( ( void* ) nativeData, sizeof( SomeStruct ) );

//TODO 여기에 Java 메소드를 호출하며 jByteBuffer 객체를 전달하는 코드를 추가하면 됩니다.

SomeStruct* nativeData2 = ( SomeStruct* ) env->GetDirectBufferAddress( env, jByteBuffer ); 

//nativeData == nativeData2
//메모리는 할당한 곳에서 해지합니다.

delete nativeData;


자바 코드에서는 전달받은 ByteBuffer 객체의 구조체 데이터 항목을 다음과 같이 접근할 수 있습니다.

int intVal = jByteBuffer.getInt( 0 );
short shortVal = jByteBuffer.getShort( 4 );


다음과 같은 코드를 사용하면,
자바 힙 이외의 네이티브 메모리를 자바에서 할당해 사용할 수 있습니다.

//http://stackoverflow.com/a/9891217

JNIEXPORT jobject JNICALL Java_com_foo_allocNativeBuffer(JNIEnv* env, jobject thiz, jlong size)
{
    void* buffer = malloc(size);
    jobject directBuffer = env->NewDirectByteBuffer(buffer, size);
    return directBuffer;
}

JNIEXPORT void JNICALL Java_comfoo_freeNativeBuffer(JNIEnv* env, jobject thiz, jobject bufferRef)
{
    void *buffer = env->GetDirectBufferAddress(bufferRef);

    free(buffer);
}

//자바코드에의 사용 - 메모리 할당

ByteBuffer data = allocNativeBuffer( someSize );

//자바코드에서의 사용 - 메모리 해지

freeNativeBuffer( data );
data = null;


안드로이드에서의 jni 사용


다음 포스트를 참고하세요.

android. JNI 네이티브 코드에서 Android Java API 호출하기