Simple example을 통해서 JNI를 이용하여 C/C++함수를 호출하는 방법에 대해 간략히 정리 하였다.
이제 Java module과 C/C++ module사이에 parameter를 통하여 정보를 주고 받는 방법을 알아보자
우선 기본적으로 Java와 C/C++사이의 type을 매핑 시키기 위해 jni.h에 보면 다양한 Java의 변수 type에 대해 C/C++에서 사용할 수 있도록 정의해두었다.
자세한건 다른 잘 정리된 사이트를 참고하고 여기서는 내가 사용한 String type을 넘기고 받는 부분에 대해 알아 보자
Java Source
public class HelloWorld {
static {
System.loadLibrary("HelloWorld");
}
String test1;
public native void printHelloWorld(String name);
public static void main(String[] args) {
HelloWorld hw = new HelloWorld();
hw.printHelloWorld("C/C++ module");
System.out.println("Java : " + hw.test1);
}
}
Java Compile
javac HelloWorld.java
javah -jni HelloWorld
C/C++ Source
JNIEXPORT void JNICALL Java_HelloWorld_printHelloWorld(JNIEnv *env, jobject obj, jstring name)
{
jclass cls;
jfieldID jFieldId;
jstring test1;
jboolean iscopy;
#ifdef __cplusplus
const char *sentence = (env)->GetStringUTFChars(name, &iscopy);
printf("C/C++ : %s\n", sentence);
(env)->ReleaseStringUTFChars(name, sentence);
cls = (env)->GetObjectClass(obj);
jFieldId = (env)->GetFieldID(cls, "test1", "Ljava/lang/String;");
if(jFieldId == 0) {
printf("test1 - Field strVal not Found in Hello class\n");
return;
}
test1 = (env)->NewStringUTF("Java module");
(env)->SetObjectField(obj, jFieldId, test1);
#else
const char *sentence = (*env)->GetStringUTFChars(env, name, &iscopy);
printf("C/C++ : %s\n", sentence);
(*env)->ReleaseStringUTFChars(env, name, sentence);
cls = (*env)->GetObjectClass(env, obj);
jFieldId = (*env)->GetFieldID(env, cls, "test1", "Ljava/lang/String;");
if(jFieldId == 0) {
printf("test1 - Field strVal not Found in Hello class\n");
return;
}
test1 = (*env)->NewStringUTF(env, "Java module");
(*env)->SetObjectField(env, obj, jFieldId, test1);
#endif
return;
}
C/C++ Compile 및 실행은 Simple example과 동일
참고 사항
1.
public native void printHelloWorld(String name) : Java module에서 정의한 method
JNIEXPORT void JNICALL Java_HelloWorld_printHelloWorld(JNIEnv *env, jobject obj, jstring name) 위 java method에 해당하는 C module
양쪽 parameter의 type을 맞추기 위해 jni.h에 보면 Java type에 해당하는 C type이 정의되어 있다.
예를들어 위 예제에서와 같이 Java의 String type은 C의 jstring type으로 정의 되어 있다.
2.
jstring과 같은 type은 C에서 그대로 사용할 수 없고 C에사 사용가능한 char type으로 변환 시켜줘야한다.
각 object나 array type에 맞게 이러한 역할을 하는 함수가 있다.
String같은 경우, const char *sentence = (env)->GetStringUTFChars(name, &iscopy) 이처럼 char pointer type의 sentence로 저장한다.
3.
C module에서 Java module로 값을 넘겨줄때, return type을 이용할 수도 있고, Java class의 variable을 직접 access할 수 도 있다. 위 예제는 java class의 variable에 직접 값을 넣는 방법을 알아봤다.
cls = (env)->GetObjectClass(obj);
jFieldId = (env)->GetFieldID(cls, "test1", "Ljava/lang/String;");
java class정보를 얻기위해 GetObjectClass를 이용하였다. 이후, GetFieldID를 이용하여 class안의 field에 대한 정보를 구한다. 예제에서는 test1 은 variable name, Ljava/lang/String은 variable type을 나타낸다. 각각의 type 에 따라 지정된 값이 있다. 예를들면 I : int, F : float 등등 (다른 reference 참고)
4.
test1 = (env)->NewStringUTF("Java module");
(env)->SetObjectField(obj, jFieldId, test1);
UTF encoding을 사용하는 String객체를 생성한다. 여기서 test1은 당연히 jstring type 이어야 한다.
그후 jField정보를 이용하여 test1 (jstring type)을 class의 특정 field에 넣는다.
5.
C와 C++에 따라서 함수 호출 방법이 조금다르다.
예를 들어 C++에서는 (env)->NewStringUTF("Java module"); 와 같이 호출하는 반면, C에서는 (*env)->NewStringUTF(env, "Java module"); 와 같이 호출한다. 이건 jni.h에 가서 JNIEnv 정의된걸 보면 알 수 있다.
'Android 개발 > Android NDK / JNI' 카테고리의 다른 글
안드로이드 JNI 환경에서 C++과 Java 간의 한글 데이터 전송 문제 (0) | 2011.05.30 |
---|---|
jni.h 소스 파일 (0) | 2011.05.30 |
jni.h File Reference (0) | 2011.05.30 |
JNI 기술 (0) | 2011.05.19 |
Android NDK Windows setup (0) | 2011.05.18 |