JNI(Java Native Interface) 개념 및 사용법
1. 개요
Android 애플리케이션은 주로 Java 또는 Kotlin과 같은 언어로 작성됩니다. 그러나 경우에 따라 성능 최적화, 기존 C/C++ 라이브러리 재사용, 하드웨어 제어 등의 이유로 네이티브 코드(C/C++)를 사용해야 할 필요가 있습니다. 이를 가능하게 해주는 기술이 바로 JNI(Java Native Interface) 입니다.
JNI는 Java 코드에서 네이티브 코드를 호출하거나, 반대로 네이티브 코드에서 Java 코드를 호출할 수 있도록 하는 인터페이스입니다. Android에서는 JNI를 활용하여 NDK(Native Development Kit) 기반의 네이티브 모듈을 구현할 수 있습니다.
이 글에서는 JNI의 개념과 Android에서의 활용 사례, Java와 C/C++ 간 통신 방식, 그리고 JNI 함수 호출 흐름과 데이터 변환 방법에 대해 설명하겠습니다.
2. JNI 개념 및 Android에서 JNI 활용 사례
2.1 JNI란?
JNI는 Java 애플리케이션과 네이티브 코드(C/C++) 간의 상호작용을 가능하게 하는 표준 인터페이스입니다. 이를 통해 Java에서 네이티브 코드를 호출하거나 네이티브 코드에서 Java 객체를 조작할 수 있습니다.
JNI는 다음과 같은 경우에 유용하게 사용됩니다.
- 성능이 중요한 연산(예: 이미지 처리, 오디오/비디오 인코딩, 머신 러닝 등)
- 기존의 C/C++ 라이브러리를 활용해야 하는 경우
- 하드웨어 제어 및 네이티브 API 호출
- 보안 또는 DRM(Digital Rights Management) 등의 이유로 네이티브 코드에서 로직을 처리해야 하는 경우
2.2 Android에서 JNI 활용 사례
Android에서 JNI는 주로 NDK(Native Development Kit) 를 통해 활용됩니다. 대표적인 활용 사례는 다음과 같습니다.
- 미디어 처리: OpenGL, OpenSL ES 등을 이용한 고성능 그래픽 및 오디오 처리를 위한 네이티브 코드 사용
- 머신 러닝: TensorFlow Lite와 같은 라이브러리 활용
- 암호화 및 보안: 네이티브 코드를 활용하여 중요한 보안 로직을 보호
- 기존 네이티브 라이브러리 재사용: 기존 C/C++로 작성된 라이브러리를 Android에서 사용
3. JNI를 사용한 Java ↔ C/C++ 통신
3.1 JNI 기본 구조
JNI를 이용한 Java와 C/C++ 간의 상호작용을 위해 기본적으로 다음과 같은 구조를 따릅니다.
- Java 클래스 작성: 네이티브 메서드 선언
- C/C++ 코드 작성: 네이티브 메서드 구현
- 네이티브 라이브러리 로드:
System.loadLibrary()
호출
3.2 Java 코드에서 네이티브 메서드 선언
Java 코드에서 네이티브 메서드를 선언하는 방법은 다음과 같습니다.
public class NativeLib {
static {
System.loadLibrary("native-lib"); // 네이티브 라이브러리 로드
}
public native String stringFromJNI(); // 네이티브 메서드 선언
}
3.3 C/C++ 코드에서 네이티브 메서드 구현
위에서 선언한 stringFromJNI()
메서드를 C++ 코드에서 구현하려면 다음과 같이 작성합니다.
#include <jni.h>
#include <string>
extern "C" JNIEXPORT jstring JNICALL
Java_com_example_NativeLib_stringFromJNI(
JNIEnv* env,
jobject /* this */) {
std::string hello = "Hello from C++";
return env->NewStringUTF(hello.c_str());
}
3.4 CMake 파일 구성
Android에서 C++ 네이티브 코드를 빌드하려면 CMakeLists.txt
파일을 작성해야 합니다.
cmake_minimum_required(VERSION 3.4.1)
add_library(
native-lib
SHARED
native-lib.cpp)
find_library(
log-lib
log)
target_link_libraries(
native-lib
${log-lib})
4. JNI 함수 호출 흐름 및 데이터 변환
4.1 JNI 함수 호출 흐름
JNI의 함수 호출 과정은 다음과 같은 흐름으로 진행됩니다.
- Java에서
System.loadLibrary("native-lib")
를 호출하여 네이티브 라이브러리를 로드 - Java의 네이티브 메서드(
native String stringFromJNI()
) 호출 - JNI 인터페이스(
JNIEnv* env
)를 통해 네이티브 코드에서 Java 객체 조작 및 반환 - 네이티브 코드에서 Java 문자열(
NewStringUTF
)을 생성하여 반환 - Java에서 반환된 값을 사용
4.2 JNI 데이터 타입 변환
Java와 C/C++ 간의 데이터 변환이 필요할 경우, 아래 표를 참고하여 변환을 수행할 수 있습니다.
Java 타입 | JNI 타입 | C/C++ 타입 |
---|---|---|
boolean |
jboolean |
bool (C++) / unsigned char (C) |
byte |
jbyte |
char |
char |
jchar |
unsigned short |
short |
jshort |
short |
int |
jint |
int |
long |
jlong |
long long |
float |
jfloat |
float |
double |
jdouble |
double |
String |
jstring |
const char* |
JNI를 사용할 때, JNIEnv
객체를 활용하여 Java 객체를 조작하거나 변환할 수 있습니다. 예를 들어, Java 문자열을 C++ 문자열로 변환하는 방법은 다음과 같습니다.
const char* cstr = env->GetStringUTFChars(jstr, NULL);
std::string cppStr(cstr);
env->ReleaseStringUTFChars(jstr, cstr);
5. 결론
JNI는 Java와 네이티브 코드 간의 상호작용을 가능하게 하는 강력한 인터페이스입니다. Android에서 NDK와 함께 사용하면 성능이 중요한 작업을 효과적으로 수행할 수 있습니다. 본 글에서는 JNI의 개념과 Android에서의 활용 사례, Java와 C/C++ 간의 통신 방식, 그리고 JNI 함수 호출 흐름과 데이터 변환 방법을 설명하였습니다.
향후 JNI를 활용하여 더욱 복잡한 네이티브 코드와의 상호작용을 다룰 수 있으며, 이를 통해 Android 애플리케이션의 성능을 극대화할 수 있습니다.
'Android > Framework' 카테고리의 다른 글
Native 코드와 Android Framework 연동 (0) | 2025.04.06 |
---|---|
Android NDK(Native Development Kit) 개요 및 활용 (0) | 2025.04.05 |
Android Framework의 SSL 라이브러리 분석 (0) | 2025.04.03 |
Android WebKit 라이브러리 분석 (0) | 2025.04.02 |
Android Framework의 SQLite 라이브러리 분석 (0) | 2025.04.01 |