Android/Framework

JNI(Java Native Interface) 개념 및 사용법

임베디드 친구 2025. 4. 4. 09:35
728x90
반응형

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) 를 통해 활용됩니다. 대표적인 활용 사례는 다음과 같습니다.

  1. 미디어 처리: OpenGL, OpenSL ES 등을 이용한 고성능 그래픽 및 오디오 처리를 위한 네이티브 코드 사용
  2. 머신 러닝: TensorFlow Lite와 같은 라이브러리 활용
  3. 암호화 및 보안: 네이티브 코드를 활용하여 중요한 보안 로직을 보호
  4. 기존 네이티브 라이브러리 재사용: 기존 C/C++로 작성된 라이브러리를 Android에서 사용

3. JNI를 사용한 Java ↔ C/C++ 통신

3.1 JNI 기본 구조

JNI를 이용한 Java와 C/C++ 간의 상호작용을 위해 기본적으로 다음과 같은 구조를 따릅니다.

  1. Java 클래스 작성: 네이티브 메서드 선언
  2. C/C++ 코드 작성: 네이티브 메서드 구현
  3. 네이티브 라이브러리 로드: 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의 함수 호출 과정은 다음과 같은 흐름으로 진행됩니다.

  1. Java에서 System.loadLibrary("native-lib")를 호출하여 네이티브 라이브러리를 로드
  2. Java의 네이티브 메서드(native String stringFromJNI()) 호출
  3. JNI 인터페이스(JNIEnv* env)를 통해 네이티브 코드에서 Java 객체 조작 및 반환
  4. 네이티브 코드에서 Java 문자열(NewStringUTF)을 생성하여 반환
  5. 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 애플리케이션의 성능을 극대화할 수 있습니다.

반응형