본문 바로가기

프로그래밍/Android

안드로이드 ndk 테스트 코드

ndk 사용해야 하는데, 사용한지 너무 오래되어 다시한번 정리

Project/app/build.gradle

android {
    externalNativeBuild {
        cmake {
            path "CMakeLists.txt"
            cppFlags "-std=c++11"
        }
    }
}

 

Project/app/CMakeLists.txt

cmake_minimum_required(VERSION 3.6)
add_library(test-lib SHARED ./src/main/cpp/test.c)
include_directories(./src/main/cpp)

클라이언트

// kotlin
class Native {
    init {
        System.loadLibrary("test-lib")
    }

    external fun test(a:Int):void
}
// java
class Native {
    static {
        System.loadLibrary("test-lib")
    }
    
    static native void test(int a);
}

 


jni Primitive Type

typedef unsigned char   jboolean;       /* unsigned 8 bits */
typedef signed char     jbyte;          /* signed 8 bits */
typedef unsigned short  jchar;          /* unsigned 16 bits */
typedef short           jshort;         /* signed 16 bits */
typedef int             jint;           /* signed 32 bits */
typedef long long       jlong;          /* signed 64 bits */
typedef float           jfloat;         /* 32-bit IEEE 754 */
typedef double          jdouble;        /* 64-bit IEEE 754 */

 

jni ReferenceType

jobject
    jclass : java.lang.Class
    jstring : java.lang.String
    jarray
        jobjectArray
        jbooleanArray
        jbyteArray
        jcahrArray
        jshortArray
        jintArray
        jlongArray
        jfloatArray
        jdoubleArray
    jthrowable : java.lang.Throwable

 

C 함수 정의 : JNI_OnLoad에서 맵핑하므로 javah 형태의 선언은 필요 없음.

// 앞의 두 인자는 공통 사항
void test_c(JNIEnv* env, jclass type, jint num) {

}

 

맵핑

/*
typedef struct {
    char* name;
    char* signature;
    void* fnPtr;
} JNINativeMethod;

signature : (arg-types)ret-type
Z : boolean
B : byte
C : char
S : short
I : int
J : long
F : float
D : double
Lclass : package/class;
[type : type[]
V : void
*/

JNINativeMethod native_method[] = {
    {"test", "(I)V", (void*)test_c},
};
    

jint JNIEXPORT JNICALL JNI_OnLoad(JavaVM* jvm, void* reserved) {
    JNIEnv* env = NULL;
    
    if((*jvm)->GetEnv( jvm, (void**)&env, JNI_VERSION_1_6) != JNI_OK) {
        return -1;
    }
    
    jclass javaClass = (*env)->FindClass(env, "com/test/Native");
    if(javaClass == NULL) {
        return -1;
    }
    
    if((*env)->RegisterNatives(
                        env, 
                        javaClass,
                        native_method,
                        sizeof(native_method)/sizeof(JNINativeMethod))<0) {
        return -1;
    }
    
    return JNI_VERSION_1_6;
}

void JNIEXPORT JNICALL JNI_OnUnLoad(JavaVM* jvm, void* reserved) {
}

 


ByteBuffer 의 직접 조작

// Java function
public static native void sample( ByteBuffer data );

// C
static JNINativeMethod methods[]={
    {"sample","(Ljava/nio/ByteBuffer;)V",(void*)sample}
};

// C function
void sample( JNIEnv* env, jclass type, jobject data )
{
	char* dataArray = (char*)(*env)->GetDirectBufferAddress( env, data )

    // 데이터 조작
    dataArray[0] = 0;
    	.
        .
}