본문 바로가기
Development/Android

[안드로이드][JNI] JNI 개발 순서 절차!

by 푸민 2015. 10. 27.
반응형


안녕하세요 푸민입니다.

안드로이드 NDK 환경설정을 한 저번 포스팅에 이어 이번에는 JNI 개발 순서를 한번 알아보겠습니다.



1. so 파일 명칭과 메소드 명칭을 정하고 클래스를 작성한다.

당연한 얘기지만 해당 명칭을 정하고 자바로 먼저 적용할 것을 만들어 두면 보기가 편해요! 

그러면 한번 안드로이드 자바와 JNI 속도를 간단하게 테스트해볼 클래스를 생성해보겠습니다.


public class SpeedTest {

static{

System.loadLibrary("speedtest");

}


long start_time;

long end_time;

int ret;


public void test(){

start_time = System.currentTimeMillis();

ret = java_calc();

end_time = System.currentTimeMillis();

Log.d("test", "java : " + (end_time-start_time) + ", ret : " + ret);


start_time = System.currentTimeMillis();

ret = nativecalc();

end_time = System.currentTimeMillis();

Log.d("test", "native : " + (end_time-start_time) + ", ret : " + ret);

}


public int java_calc(){

int count = 3;

int i = 0 ;

for (i = 0 ; i < 100000000 ; i++){

count = count * 2 / 3 + 5 - 1;

}

return count;

}


public native int nativecalc();

}


자 코드를 보시면 먼저 클래스 이름을 SpeedTest 로 하였습니다. 그리고 test(), java_calc() 그리고 nativecals() 이렇게 3개의 메소드를 만들었습니다. 

하나씩 보면

- test() : 실제로 테스트하는 코드가 있습니다. 계산 시작과 끝의 시간을 체크하여 얼마나 소요 되는지 확인합니다.

- java_calc() : 안드로이드에서 java 를 이용하여 계산합니다.

- nativecalc() : native 즉 C언어를 이용하여 계산합니다.

보시면 조금 다른것을 보실수 있는데요. 네! 바로 static 함수native 라는 예약어입니다. 해당 예약어를 사용하면, 메소드를 네이티브 함수에서 찾습니다. static 함수는 해당 클래스가 생성될때 호출되며 System.loadLibrary() 를 통해서 native lib 파일을 로딩합니다.



2. 설정한 명칭에 맞게 C파일을 생성한다.

C언어로 코드 작성시 유의해야할 사항이 몇가지 있습니다. 

- 메소드 이름 작성 규칙이 있습니다. 이름은 패키지명이 들어가야됩니다. 패키지명이 com.example.pluscals 일 경우


java_com_example_pluscalc_SpeedTest_nativecalc


- 데이터 타입을 잘 설정해줍니다.


 자바 타입

JNI 타입 

C 타입 

boolean 

jboolean 

unsigned char 

byte 

jbyte 

signed char 

char 

jchar 

unsigned short 

double 

jdouble 

double 

float 

jfloat 

float 

int 

jint 

int 

long 

jlong 

long long 

short 

jshort 

short 

 

 

 


speedtest.c 소스코드


#include <jni.h>

#include <string.h>

jint Java_com_example_pluscalc_peedTest_nativecalc ( JNIEnv* env, jobject obj){

int count = 3;

int i = 0 ;

for(i = 0 ; i < 100000000; i++){

count = count * 2 / 3 + 5 - 1;

}

return count;

}


먼저 jni.h 헤더파일을 인클루드합니다. 그리고 jint 타입을 반환하는 nativecalc() 메소드를 정의합니다. 파라미터의 첫번째와 두번째는 항상 넣어줘야되요! 그리고 코드는 자바와 같은 코드입니다.



3. C파일이 있는 경로에 Android.mk 파일을 생성한다.

.mk 파일make 파일로서 C파일을 SO파일로 변경할때 각종 설정사항들을 지정할수 있습니다. 아래는 speedtest.c 파일을 libspeedtest.so 로 만들기 위한 설정입니다.


LOCAL_PATH := $(call my-dir)


include $(CLEAR_VARS)

LOCAL_MODULE := libspeedtest
LOCAL_SRC_FILES := speedtest.c

include $(BUILD_SHARED_LIBRARY)


먼저 경로를 지정해주고 변수들을 정리해줍니다. 그리고 만들 SO파일과 C파일 소스위치를 설정해줍니다. 마지막으로 어떤 형식으로 빌드할지 설정하면 끝!


4. 위의 경로로 들어가서 ndk-build 를 실행한다.

문제가 없다면 정상적으로 libs/ameabi/libspeedtest.so 파일이 생성되었을 것입니다.


5. libspeedtest.so 파일을 프로젝트에 복사한다.

복사가 되면 이제 클래스에서 native 함수를 호출할 수 있습니다. 물론 함수 사용전에 System.loadLibrary() 메소드를 통해서 해당 lib 파일을 호출해야되요!


6. 안드로이드를 빌드하여 실행한다.


전체적인 JNI 개발 순서는 이렇게 하시면 됩니다. 그리고 테스트 결과 안드로이드는 약 3.3초 JNI는 약 1.6초가 걸리네요. 하지만 기기별, 기종별, 버전별, 기능별로 다 다른 퍼포먼스를 보이기때문에 무조건 JNI가 빠른것은 아닙니다. 타입변환에도 시간이 소요되기도 하구요. 상황에 잘 맞게 사용하면 좋을것같네요!

반응형

댓글