경축! 아무것도 안하여 에스천사게임즈가 새로운 모습으로 재오픈 하였습니다.
어린이용이며, 설치가 필요없는 브라우저 게임입니다.
https://s1004games.com

[JNI] 안드로이드 JNI 환경에서 C++과 Java 간의 한글 데이터 전송 문제

[출처] http://snowbora.tistory.com/371



지금은 잠깐 쉬고 있지만, 예전에 안드로이드 ndk 환경에서 프로그래밍을 하던 때가 있었습니다.
그 때, JNI 인터페이스를 통해 Native단의 C++과 Application단의 Java와의 데이터를 주고 받아야 하는 API들을
만들었었는데, 그 중 문자열 전송과 관련해서 한글이 죄다 깨져서 전송되는 현상이 있었습니다.

Java 단에서는 UTF-8 방식을 이용하고, C++에서는 KSC5601 방식의 문자열이었기 때문에 발생하는 문제였습니다.
그래서 구글링을 통해 C++과 Java간의 한글 변환 관련 코드를 확보 및 컨버팅을 했습니다.


C++과 Java간의 한글 변환 코드는 다음과 같습니다. 다음은 헤더 파일입니다.

01.#ifndef _STRING_CONVERTER_FOR_JNI_
02.#define _STRING_CONVERTER_FOR_JNI_
03. 
04.#include <jni.h>
05.#include <stdio.h>
06.#include <string.h>
07. 
08.#ifdef __cplusplus
09.extern "C"
10.{
11.#endif
12. 
13.    char *jbyteArray2cstr( JNIEnv *env, jbyteArray javaBytes );
14.    jbyteArray cstr2jbyteArray( JNIEnv *env, const char *nativeStr);
15.    jbyteArray javaGetBytes( JNIEnv *env, jstring str );
16.    jbyteArray javaGetBytesEncoding( JNIEnv *env, jstring str, const char *encoding );
17.    jstring javaNewString( JNIEnv *env, jbyteArray javaBytes );
18.    jstring javaNewStringEncoding(JNIEnv *env, jbyteArray javaBytes, const char *encoding );
19. 
20.    jstring javaNewStringChar(JNIEnv* env, const char* nativeStr);
21. 
22.#ifdef __cplusplus
23.}
24.#endif
25. 
26.#endif //_STRING_CONVERTER_FOR_JNI_
27.</string.h></stdio.h></jni.h>

그리고 다음은 C++ 소스 코드입니다.
001.#include "StringConverter_For_JNI.h"
002. 
003.static jclass class_String;
004.static jmethodID mid_getBytes, mid_getBytesEncoding;
005.static jmethodID mid_newString, mid_newStringEncoding;
006. 
007.char *jbyteArray2cstr( JNIEnv *env, jbyteArray javaBytes )
008.{
009.    size_t len = env->GetArrayLength(javaBytes);
010.    jbyte *nativeBytes = env->GetByteArrayElements(javaBytes, 0);
011.    char *nativeStr = (char *)malloc(len+1);
012.    strncpy( nativeStr, (const char*)nativeBytes, len );
013.    nativeStr[len] = '

[JNI] 안드로이드 JNI 환경에서 C++과 Java 간의 한글 데이터 전송 문제

[출처] http://snowbora.tistory.com/371



지금은 잠깐 쉬고 있지만, 예전에 안드로이드 ndk 환경에서 프로그래밍을 하던 때가 있었습니다.
그 때, JNI 인터페이스를 통해 Native단의 C++과 Application단의 Java와의 데이터를 주고 받아야 하는 API들을
만들었었는데, 그 중 문자열 전송과 관련해서 한글이 죄다 깨져서 전송되는 현상이 있었습니다.

Java 단에서는 UTF-8 방식을 이용하고, C++에서는 KSC5601 방식의 문자열이었기 때문에 발생하는 문제였습니다.
그래서 구글링을 통해 C++과 Java간의 한글 변환 관련 코드를 확보 및 컨버팅을 했습니다.


C++과 Java간의 한글 변환 코드는 다음과 같습니다. 다음은 헤더 파일입니다.

01.#ifndef _STRING_CONVERTER_FOR_JNI_
02.#define _STRING_CONVERTER_FOR_JNI_
03. 
04.#include <jni.h>
05.#include <stdio.h>
06.#include <string.h>
07. 
08.#ifdef __cplusplus
09.extern "C"
10.{
11.#endif
12. 
13.    char *jbyteArray2cstr( JNIEnv *env, jbyteArray javaBytes );
14.    jbyteArray cstr2jbyteArray( JNIEnv *env, const char *nativeStr);
15.    jbyteArray javaGetBytes( JNIEnv *env, jstring str );
16.    jbyteArray javaGetBytesEncoding( JNIEnv *env, jstring str, const char *encoding );
17.    jstring javaNewString( JNIEnv *env, jbyteArray javaBytes );
18.    jstring javaNewStringEncoding(JNIEnv *env, jbyteArray javaBytes, const char *encoding );
19. 
20.    jstring javaNewStringChar(JNIEnv* env, const char* nativeStr);
21. 
22.#ifdef __cplusplus
23.}
24.#endif
25. 
26.#endif //_STRING_CONVERTER_FOR_JNI_
27.</string.h></stdio.h></jni.h>

그리고 다음은 C++ 소스 코드입니다.
001.#include "StringConverter_For_JNI.h"
002. 
003.static jclass class_String;
004.static jmethodID mid_getBytes, mid_getBytesEncoding;
005.static jmethodID mid_newString, mid_newStringEncoding;
006. 
007.char *jbyteArray2cstr( JNIEnv *env, jbyteArray javaBytes )
008.{
009.    size_t len = env->GetArrayLength(javaBytes);
010.    jbyte *nativeBytes = env->GetByteArrayElements(javaBytes, 0);
011.    char *nativeStr = (char *)malloc(len+1);
012.    strncpy( nativeStr, (const char*)nativeBytes, len );
013.    nativeStr[len] = '\0';
014.    env->ReleaseByteArrayElements(javaBytes, nativeBytes, JNI_ABORT);
015. 
016.    return nativeStr;
017.}
018. 
019.jbyteArray cstr2jbyteArray( JNIEnv *env, const char *nativeStr)
020.{
021.    jbyteArray javaBytes;
022.    int len = strlen( nativeStr );
023.    javaBytes = env->NewByteArray(len);
024.    env->SetByteArrayRegion(javaBytes, 0, len, (jbyte *) nativeStr );
025. 
026.    return javaBytes;
027.}
028. 
029.jbyteArray javaGetBytes( JNIEnv *env, jstring str )
030.{
031.    if ( mid_getBytes == 0 )
032.    {
033.        if ( class_String == 0 )
034.        {
035.            jclass cls = env->FindClass("java/lang/String");
036.            if ( cls == 0 )
037.            {
038.                return 0;
039.            }
040. 
041.            class_String = (jclass)env->NewGlobalRef(cls);
042.            env->DeleteLocalRef(cls);
043.            if ( class_String == 0 )
044.            {
045.                return 0;
046.            }
047.        }
048. 
049.        mid_getBytes = env->GetMethodID(class_String, "getBytes", "()[B");
050.        if (mid_getBytes == 0)
051.        {
052.            return 0;
053.        }
054.    }
055. 
056.    return (jbyteArray)env->CallObjectMethod(str, mid_getBytes );
057.}
058. 
059.jbyteArray javaGetBytesEncoding( JNIEnv *env, jstring str, const char *encoding )
060.{
061.    if ( mid_getBytesEncoding == 0 )
062.    {
063.        if ( class_String == 0 )
064.        {
065.            jclass cls = env->FindClass("java/lang/String");
066.            if ( cls == 0 )
067.            {
068.                return 0;
069.            }
070. 
071.            class_String = (jclass)env->NewGlobalRef(cls);
072.            env->DeleteLocalRef(cls);
073.            if ( class_String == 0 )
074.            {
075.                return 0;
076.            }
077.        }
078. 
079.        mid_getBytesEncoding = env->GetMethodID(class_String, "getBytes", "(Ljava/lang/String;)[B");
080.        if (mid_getBytesEncoding == 0)
081.        {
082.            return 0;
083.        }
084.    }
085. 
086.    jstring jstr = env->NewStringUTF(encoding);
087.    jbyteArray retArray = (jbyteArray)env->CallObjectMethod(str, mid_getBytesEncoding, jstr);
088.    env->DeleteLocalRef(jstr);
089.     
090.    return retArray;
091.}
092. 
093.jstring javaNewString( JNIEnv *env, jbyteArray javaBytes )
094.{
095.    if ( mid_newString == 0 )
096.    {
097.        if ( class_String == 0 )
098.        {
099.            jclass cls = env->FindClass("java/lang/String");
100.            if ( cls == 0 )
101.            {
102.                return 0;
103.            }
104. 
105.            class_String = (jclass)env->NewGlobalRef(cls);
106.            env->DeleteLocalRef(cls);
107.            if ( class_String == 0 )
108.            {
109.                return 0;
110.            }
111.        }
112. 
113.        mid_newString = env->GetMethodID(class_String, "<init>", "([B)V");
114.        if ( mid_newString == 0 )
115.        {
116.            return 0;
117.        }
118.    }
119. 
120.    return (jstring)env->NewObject(class_String, mid_newString, javaBytes );
121.}
122. 
123.jstring javaNewStringEncoding(JNIEnv *env, jbyteArray javaBytes, const char *encoding )
124.{
125.    int len;
126.    jstring str;
127.    if ( mid_newString == 0 )
128.    {
129.        if ( class_String == 0 )
130.        {
131.            jclass cls = env->FindClass("java/lang/String");
132.            if ( cls == 0 )
133.            {
134.                return 0;
135.            }
136. 
137.            class_String = (jclass)env->NewGlobalRef(cls);
138.            env->DeleteLocalRef(cls);
139.            if ( class_String == 0 )
140.            {
141.                return 0;
142.            }
143. 
144.        }
145. 
146.        mid_newString = env->GetMethodID(class_String, "<init>", "([BLjava/lang/String;)V");
147.        if ( mid_newString == 0 )
148.        {
149.            return 0;
150.        }
151.    }
152. 
153.    jstring jstr = env->NewStringUTF(encoding);
154.    str = (jstring)env->NewObject(class_String, mid_newString, javaBytes, jstr);
155.    env->DeleteLocalRef(jstr);
156. 
157.    return str;
158.}
159. 
160.jstring javaNewStringChar(JNIEnv* env, const char* nativeStr)
161.{
162.    jbyteArray byteArray = cstr2jbyteArray(env, nativeStr);
163.    jstring jstr = javaNewString(env, byteArray);
164.    env->DeleteLocalRef(byteArray);
165. 
166.    return jstr;
167.}
168.</init></init>


이 함수들을 이용해서 실제로 사용한 예제는 다음과 같습니다.
C++의 string을 Java용 jstring으로 변환하는 부분
1.jstring jstrValue;
2.jfieldID fieldID;
3.jmethodID methodID;
4. 
5.methodID = env->GetMethodID( cProgramInfo, "ProgramName","(Ljava/lang/String;)V");
6.jstrValue = javaNewStringChar(env, strProgramName);
7.env->CallVoidMethod( jElement, methodID, jstrValue);
8.env->DeleteLocalRef(jstrValue);

 Java용 jstring를 C++의 string으로 변환하는 함수

01.string      title_;
02.jmethodID methodID;
03. 
04.methodID = env->GetMethodID( cProgramInfo, "ProgramTitle","()Ljava/lang/String;");
05.jstring jstrTitle = (jstring)env->CallObjectMethod(jElement, methodID);
06.if(jstrTitle)
07.{
08.    pszTitle = (char*)env->GetStringUTFChars(jstrTitle, &iscopy);
09.    title_ = pszTitle;
10.    env->ReleaseStringUTFChars(jstrTitle, pszTitle);
11.    env->DeleteLocalRef(jstrTitle); 
12.}

';
014.    env->ReleaseByteArrayElements(javaBytes, nativeBytes, JNI_ABORT);
015. 
016.    return nativeStr;
017.}
018. 
019.jbyteArray cstr2jbyteArray( JNIEnv *env, const char *nativeStr)
020.{
021.    jbyteArray javaBytes;
022.    int len = strlen( nativeStr );
023.    javaBytes = env->NewByteArray(len);
024.    env->SetByteArrayRegion(javaBytes, 0, len, (jbyte *) nativeStr );
025. 
026.    return javaBytes;
027.}
028. 
029.jbyteArray javaGetBytes( JNIEnv *env, jstring str )
030.{
031.    if ( mid_getBytes == 0 )
032.    {
033.        if ( class_String == 0 )
034.        {
035.            jclass cls = env->FindClass("java/lang/String");
036.            if ( cls == 0 )
037.            {
038.                return 0;
039.            }
040. 
041.            class_String = (jclass)env->NewGlobalRef(cls);
042.            env->DeleteLocalRef(cls);
043.            if ( class_String == 0 )
044.            {
045.                return 0;
046.            }
047.        }
048. 
049.        mid_getBytes = env->GetMethodID(class_String, "getBytes", "()[B");
050.        if (mid_getBytes == 0)
051.        {
052.            return 0;
053.        }
054.    }
055. 
056.    return (jbyteArray)env->CallObjectMethod(str, mid_getBytes );
057.}
058. 
059.jbyteArray javaGetBytesEncoding( JNIEnv *env, jstring str, const char *encoding )
060.{
061.    if ( mid_getBytesEncoding == 0 )
062.    {
063.        if ( class_String == 0 )
064.        {
065.            jclass cls = env->FindClass("java/lang/String");
066.            if ( cls == 0 )
067.            {
068.                return 0;
069.            }
070. 
071.            class_String = (jclass)env->NewGlobalRef(cls);
072.            env->DeleteLocalRef(cls);
073.            if ( class_String == 0 )
074.            {
075.                return 0;
076.            }
077.        }
078. 
079.        mid_getBytesEncoding = env->GetMethodID(class_String, "getBytes", "(Ljava/lang/String;)[B");
080.        if (mid_getBytesEncoding == 0)
081.        {
082.            return 0;
083.        }
084.    }
085. 
086.    jstring jstr = env->NewStringUTF(encoding);
087.    jbyteArray retArray = (jbyteArray)env->CallObjectMethod(str, mid_getBytesEncoding, jstr);
088.    env->DeleteLocalRef(jstr);
089.     
090.    return retArray;
091.}
092. 
093.jstring javaNewString( JNIEnv *env, jbyteArray javaBytes )
094.{
095.    if ( mid_newString == 0 )
096.    {
097.        if ( class_String == 0 )
098.        {
099.            jclass cls = env->FindClass("java/lang/String");
100.            if ( cls == 0 )
101.            {
102.                return 0;
103.            }
104. 
105.            class_String = (jclass)env->NewGlobalRef(cls);
106.            env->DeleteLocalRef(cls);
107.            if ( class_String == 0 )
108.            {
109.                return 0;
110.            }
111.        }
112. 
113.        mid_newString = env->GetMethodID(class_String, "<init>", "([B)V");
114.        if ( mid_newString == 0 )
115.        {
116.            return 0;
117.        }
118.    }
119. 
120.    return (jstring)env->NewObject(class_String, mid_newString, javaBytes );
121.}
122. 
123.jstring javaNewStringEncoding(JNIEnv *env, jbyteArray javaBytes, const char *encoding )
124.{
125.    int len;
126.    jstring str;
127.    if ( mid_newString == 0 )
128.    {
129.        if ( class_String == 0 )
130.        {
131.            jclass cls = env->FindClass("java/lang/String");
132.            if ( cls == 0 )
133.            {
134.                return 0;
135.            }
136. 
137.            class_String = (jclass)env->NewGlobalRef(cls);
138.            env->DeleteLocalRef(cls);
139.            if ( class_String == 0 )
140.            {
141.                return 0;
142.            }
143. 
144.        }
145. 
146.        mid_newString = env->GetMethodID(class_String, "<init>", "([BLjava/lang/String;)V");
147.        if ( mid_newString == 0 )
148.        {
149.            return 0;
150.        }
151.    }
152. 
153.    jstring jstr = env->NewStringUTF(encoding);
154.    str = (jstring)env->NewObject(class_String, mid_newString, javaBytes, jstr);
155.    env->DeleteLocalRef(jstr);
156. 
157.    return str;
158.}
159. 
160.jstring javaNewStringChar(JNIEnv* env, const char* nativeStr)
161.{
162.    jbyteArray byteArray = cstr2jbyteArray(env, nativeStr);
163.    jstring jstr = javaNewString(env, byteArray);
164.    env->DeleteLocalRef(byteArray);
165. 
166.    return jstr;
167.}
168.</init></init>


이 함수들을 이용해서 실제로 사용한 예제는 다음과 같습니다.
C++의 string을 Java용 jstring으로 변환하는 부분
1.jstring jstrValue;
2.jfieldID fieldID;
3.jmethodID methodID;
4. 
5.methodID = env->GetMethodID( cProgramInfo, "ProgramName","(Ljava/lang/String;)V");
6.jstrValue = javaNewStringChar(env, strProgramName);
7.env->CallVoidMethod( jElement, methodID, jstrValue);
8.env->DeleteLocalRef(jstrValue);

 Java용 jstring를 C++의 string으로 변환하는 함수

01.string      title_;
02.jmethodID methodID;
03. 
04.methodID = env->GetMethodID( cProgramInfo, "ProgramTitle","()Ljava/lang/String;");
05.jstring jstrTitle = (jstring)env->CallObjectMethod(jElement, methodID);
06.if(jstrTitle)
07.{
08.    pszTitle = (char*)env->GetStringUTFChars(jstrTitle, &iscopy);
09.    title_ = pszTitle;
10.    env->ReleaseStringUTFChars(jstrTitle, pszTitle);
11.    env->DeleteLocalRef(jstrTitle); 
12.}

본 웹사이트는 광고를 포함하고 있습니다.
광고 클릭에서 발생하는 수익금은 모두 웹사이트 서버의 유지 및 관리, 그리고 기술 콘텐츠 향상을 위해 쓰여집니다.
번호 제목 글쓴이 날짜 조회 수
30 Java XML Parse, Java XML 파싱 샘플 졸리운_곰 2015.03.03 814
29 Java Inner class 자바 중첩(내부)클래스 졸리운_곰 2015.03.03 886
28 IzPack으로 GUI 설치 프로그램 만들기 file 졸리운_곰 2015.02.15 638
27 [Java],[AWT],[Layout],[AWT Layout], file 졸리운_곰 2015.02.13 368
26 [Java],[AWT],[SWING], Java GUI file 졸리운_곰 2015.02.13 922
25 [Java][AWT 개요] file 졸리운_곰 2015.02.13 463
24 javac 로 컴파일 시 유니코드(utf-8) 한글 소스 코드 컴파일 문제 졸리운_곰 2015.02.02 1133
23 [스프링] 스프링 Java 어노테이션 file 졸리운_곰 2014.06.11 960
22 [스프링] 스프링 MVC 졸리운_곰 2014.06.11 532
21 [스프링] 어노테이션 졸리운_곰 2014.06.11 1032
20 인코딩 - 8859_1의 비밀(?) file 졸리운_곰 2014.05.06 581
» [JNI] 안드로이드 JNI 환경에서 C++과 Java 간의 한글 데이터 전송 문제 졸리운_곰 2014.05.06 597
18 자바 암호화 복호화 file 졸리운_곰 2014.04.08 2495
17 파일 존재 여부 판단, 디렉토리 있는지 확인 함수; File Directory Exist 졸리운_곰 2014.03.03 1215
16 NetStat call and get result text in Java 졸리운_곰 2014.02.25 903
15 [Spring] @Autowired 와 Java Spring 졸리운_곰 2014.01.29 1332
14 Java Static 변수 졸리운_곰 2014.01.28 1102
13 Properties 클래스 사용하기. 졸리운_곰 2014.01.28 1024
12 Java => Thread 졸리운_곰 2014.01.28 834
11 [Spring] 내가 Spring을 사랑하는 다섯 가지 이유 file 가을의 곰을... 2013.12.22 970
대표 김성준 주소 : 경기 용인 분당수지 U타워 등록번호 : 142-07-27414
통신판매업 신고 : 제2012-용인수지-0185호 출판업 신고 : 수지구청 제 123호 개인정보보호최고책임자 : 김성준 sjkim70@stechstar.com
대표전화 : 010-4589-2193 [fax] 02-6280-1294 COPYRIGHT(C) stechstar.com ALL RIGHTS RESERVED