Android NDK JNI
S.O.LAB develop by OracleON(이상온)
안드로이드 NDK
- 안드로이드 SDK와 함께 이용되는 개발키트
   => 안드로이드 NDK를 사용하면 애플리케이션의 일부 또는 전부를
      c/c++로 만들수 있다.
   => NDK로 만들어진 실행파일은 바이너리코드이다.(기계어)

- NDK 포함된 것들
    => 컴파일러, 링커,ToolChain,헤더파일,라이브러리,문서, 예제소스

- SDK가 기본으로 사용되며, NDK는 보조적인 역할을 하기 위해 사용

- NDK에서 할수 있는 것들
    => OpenGL/ES , OpenSL/ES(사운드), 센서입력,터치패널
    => NativeActivity , 리눅스시스템콜
    => Assets폴더로부터 데이터입력(파일을 추가할때마다 빌드필요없다)
안드로이드 내부구조(계층)
- 리눅스 커널 => 하드웨어 추상계층(HAL) => 라이브러리,안드로이드런타임
  => 애플리케이션 프레임워크 => 애플리케이션
- 안드로이드 런타임 : (달빅VM)
- 애플리케이션 프레임워크 : 버튼,텍스트박스 같은 애플리케이션을
                  동작시키는데 필요한 라이브러리가 포함

- 애플리케이션 실행환경
   => 자바소스 => VM바이트코드 =>VM =>라이브러리 => 커널

- NDK 실행환경
    => 네이티브코드 => 라이브러리 => 커널
    자바로 만들어지 부분중 NDK코드는 달빅VM을 거치지 않고 바로
    라이브러리를 호출한다.
안드로이드 내부구조(계층)
- SDK,NDK같이 개발한 소스는 VM바이트코드+네이티브코드 포함한
    하나의 실행파일에 공존하게 된다.

- NDK경우 c/c++로 만든코드는 컴파일러와 링커를 거쳐 .so 파일로 생성
  => 공유라이브러이 이므로 단독으로 동작할수 없다.
- 자바코드 (.dex파일)로 부터 호출하여 .so 모듈을 이용
- 자바코드을 빌드할때 모듈(.so)을 이용하여 실행파일(.apk)생성

- NDK단점
    1. 디버깅이 어렵다
    2. 디바이스마다 실행파일 만들어야한다.(하드웨어 의존성)
- NDK장점
    1. 빠른속도의 데이터 처리(이미지처리, 게임등)
    2. c/c++ 라이브러리 사용
안드로이드 NDK 설치 for OS X
- NDK 설치는 압축파일 형태로 배포되어 압축을 풀기만 하면 완료.

- 맥OS X 기준으로 설명
   1. http://developer.android.com/sdk/ndk/index.html (NDK다운)
   2. 임시폴터에 압축풀기
        $ tar xvf android-ndk-r5c-darwin-x86.tar.bz2
        $ sudo mv android-ndk-r5c /Developer/SDKs/

   3. android-ndk-r5폴더에 포함된 명령어 실행하도록 패스 추가
        export $PATH=/Developer/SDKs/android-ndk-r5c:$PATH
안드로이드 NDK 설치 for Window
- Window 기준으로 설명
   1. www.cygwin.com에서 시그윈설치(GNU make필요하기 때문)
       => 리눅스에서 자주 사용되는 명령어를 윈도우에서 가능하게
       => Cygwin 설치 시에 Select Packages 단계에서 'make'를 체크 후 설치

  2. 큰 카테고리에 +를 눌러서 활성화 시키면 아래 항목들 활성화
      Devel : gcc-core, gcc-g++, make, swing
      Editor : vim

       * Devel통째로 받아서 설치 추천~!!

  3.Windows 환경변수에서 PATH설정
  C:cygwinbin;C:cygwinusrinclude 추가
안드로이드 NDK 설치 for Window
- Window 기준으로 설명

  4. http://developer.android.com/sdk/ndk 에서 ndk 를 받는다

  5. NDK 의 압축을 푼다. (cygwin/home/계정/하위폴더에 설치)
      => C:cygwinhomeAdministratorandroid-ndk-r8c

  6. cygwinhome(사용자계정)Administrator.bashrc 파일수정
       export ANDROID_NDK_ROOT= homeAdministratorandroid-ndk-r8c
안드로이드 NDK 설치 for Window


 6. 환경변수의 시스템변수에서 새로만들기
     ANDROID_SDK 변수이름, 값은 설치한디렉토리
     ANDROID_NDK 변수이름, 값은 설치한 디렉토리

 7. 환경변수의 시스템변수-> PATH 값 설정
     C:Program Files (x86)Androidandroid-sdktools;
     C:Program Files (x86)Androidandroid-sdkplatform-tools;
     C:cygwinhomeAdministratorandroid-ndk-r8c;
안드로이드 JNI
- 자바에서 c/c++의 함수를 사용할수 있게 해주는 인터페이스
- JNI 규약
    1. 메모리 관리
        => 자바는 달빅VM이 메모리 관리하지만 c/c++은 개발자가
            메모리 관리를 책임지고 할당,해제 해야한다.
    2. 타입선언
       =>자바의 자료형을 c/c++에서 사용할때 자바자료형 앞에j를 붙인다.
       (예: byte=>jbyte , int=>jint , float=>jfloat , object=>jobject)
       =>자바의 배열형은 c/c++에서 Array를 붙여서 선언
       (예: byte[] => jbyteArray)
  3. 시그니처: 메소드를 만들때 사용하는 독특한 형태
       =>원시타입은 알파벳 한글자로 표현(byte=>B , long=>J)
       =>클래스앞에는 L,끝에는 세미콜론을 붙인다.
       =>클래스명은 패키지명을 포함한 문자열로 지정
  (예: Ljava/lang/String; => 자바의 String타입일경우)
       =>배열은 선투에 '['을 붙여서 지정
  (예: int[] => [I; , String[]=> [Ljava/lang/String;
안드로이드 JNI
      => 인수,반환값은 소괄호'(',')'로 구분, 반환값 void면 'V'
      B=byte, F=float,I=int,J=long, V=void, Z=boolean , C=char
          (예: void foo(int val) => (I)V
               String bar(int val) => (I)Ljava/lang/String;
               void buzz() =>()V

 4. JNI에서 C와 C++의 차이
      => C에서는 env구조체 함수포인터를 이용해 호출
      (예:FindClass함수호출
      jclass jklass =(*env)->FindClass(env,"java/lang/Integer");       )

      => C++에서는 env인스턴스의 멤버함수를 호출
      (예:FindClass함수호출
      jclass jklass =env->FindClass("java/lang/Integer");          )
안드로이드 JNI
 5. 메소드 정의 규칙
     * 자바측
           - 호출하는 함수를 선언할때 native 추가
           - loadLibrary()를 이용해 호출할 라이브러리를 지정
     public native int addVals(int a,int b); // native 붙인다
     static{     System.loadLibrary("calcvals"); //libcalcvals.so 로드
           }
     * c/c++ 측
           - 함수명은 java로 시작, 패키지명+클래스명+메서드명 연결하여 기술
           - 인수중 처음2개의 인수는 JNIEnv,jObject타입으로 한다.
 #include <jni.h>
 jint java_com_solab_calcval_MainActivity_addVals(JNIEnv* env,jObject thiz , jint a, jint b)
 {
        return a+b;
 }
      =>co.solab.clacval 패키지에 있는 MainActivity 클래스의 addVals메서드 호출
안드로이드 JNI
 6. 리플렉션
 => c/c++에서 자바의 클래스에 접근할수 있는 기능(자바함수, 자바 변수 호출)
 예: 문자열을 넣으면 숫자값으로 변화하는 자바클래스의 parseInt 함수 호출
 jclass jklass= (*env)->FindClass(env,"java/lang/Integer");
        - FindClass함수를 이용하여 java.lang.Integer클래스를 가져온다.
 jmethodID jmethod = (*env)->GetStaticMethodID(env, jklass,"parseInt","(Ljava/lang/String);I");
        - jmethod 에 "parseInt"와 인수, 반환값을 전달하고 해당 메서드의 ID를 구한다.
 if(jmethod == NULL)return;
 jint value =(*env)->CallStaticIntMethod(env, jklass,jmethod,strInt);
        - jklass 클래스와 jmethod를 실행


 예: intValue라는 int타입의 멤버변수를 가져오는 코드
 jfieldID jfieldid = (*env)->GetFieldID(env, instance,"intValue","I");
        - 세번째인수 : 가져올 변수명, 네번째인수: 가져올 변수타입
 if(jfieldid = NULL)return;
 jint val = (*env)->GetIntField(env,instance,jfieldid);
        - GetXXXField 멤버변수를 int 타입으로 가져온다.
안드로이드 JNI
 7. C/C++에서 자바의 배열 사용법
      - 자바의 배열을 가져올려면 GetXXXArrayElements(XXX)
      - releaseArrayElements 배열메모리 영역 해제

 8. C/C++에서 자바의 예외 발생
      - ExceptionCheck 함수
      - ExceptionOccurred 함수
      - ExceptionClear 함수

 9. 문자열
     - UTF-8인코딩된 문자열
          jstring jstr =(*env)->NewStringUTF(env, "펭귄");
          jsize jlen =(*env)->GetStringLength(env,jstr);
          const char* bytes =(*env)->GetStringUTFChars(env,jstr,NULL);
          (*env)->ReleaseStringUTFChars(env,jstr,bytes);
안드로이드 JNI
 10. 대규모 메모리 처리
      - 자바에서 C/C++로 이미지 데이터 보내기
      1. 자바의 배열을 이용하기
      : 자바에서 설정한 배열을 C/C++용으로 변환해서 저장
      2. java.nio.ByteBuffer클래스 이용
      : 변환과정 필요없어 처리시간 단축
      NewDirectByteBuffer(JNIEnv * env,viud* address, jlong capacity)
      -> 메모리 주소와 크기를 설정하고 새로운 인스턴스 생성
      GetDirectBufferAddress(JNIEnv *env, jobject buf)
      -> 인스턴스를 전달하고 시작주소를 반환한다.
      GetDirectBufferCapacity(JNIEnv *env, jobject buf)
      -> 인스턴스를 전달하고 크기를 반환한다.
 11. 리틀 엔디언, 빅 엔디언
      데이터를 메모리에 저장할때 상위비트부터 저장 : 빅에디언
      데이터를 메모리에 저장할때 하위비트부터 저장 : 리틀에디언
      =>달빅VM에서는 리틀에디언 사용
안드로이드 JNI
    12. Android.mk 파일
         - 안드로이드 NDK를 이용하여 빌드할려면 Android.mk파일이 필요
         - c/c++에서 makefile을 만들어서 빌드하지만 안드로이드는 Android.mk 파일만
듬
       - 모듈을 만드는데 필요한 소스코드 및 링크할 라이브러리 지정
       - 문법은 GNU make에 따라 작성
       예: clacvlas.c에서 모듈인 libcalcvalc.so 파일을 생성
       LOCAL_PATH :=$(call my-dir)
       include $(CLEAR_VARS)
            -> 이전의 모든 설정을 정리
       LOCAL_MODULE := calcvals
            -> 생성할 모듈 지정 ,libcalcvalc.so 라는 공유라이브러리가 생성
       LOCAL_SRC_FILES := calcvals.c
            -> 생성된 모듈을 빌드하는데 필요한 소스파일을 지정
       include $(BUILD_SHARED_LIBRARY)
            -> 이 라이브러리는 공유라이브러리로 생성
안드로이드 JNI
- 자바에서 C 함수 호출하기
   * int타입만 사용해 사칙연산 메소드 만들기 실습 *

  1. 프로젝트 만들기

  - cygwin/home/user계정/ 폴더에 프로젝트를 생성한다.
  - 이클립스에서 프로젝트 생성후 소스코드와 Android.mk 파일위한 jni폴더 추가

  2. jni폴터 밑에 Android.mk 파일 생성
        LOCAL_PATH := $(call my-dir)
        include $(CLEAR_VARS)
        LOCAL_SRC_FILES := calcvals.c
        LOCAL_MODULE := calcvals
        include $(BUILD_SHARED_LIBRARY)
        => 이 파일에 의해 calcvals.c가 빌드되고 libcalcvals.so파일이 만들어진다.
안드로이드 JNI
 3. MainActivity.java 변경
 protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         StringBuffer buf = new StringBuffer();
         TextView tv = new TextView(this);
         int a=10;
         int b=2;
         int val = addVals(a,b);
         buf.append("a+b="+String.valueOf(val)+"n");
         val = subVals(a,b);
         buf.append("a-b="+String.valueOf(val)+"n");
         val = mulVals(a,b);
         buf.append("a*b="+String.valueOf(val)+"n");
         val = divVals(a,b);
         buf.append("a/b="+String.valueOf(val)+"n");

           tv.setText(buf.toString());
           setContentView(tv);
 }
           public native int addVals(int a, int b);
           public native int subVals(int a, int b);
           public native int mulVals(int a, int b);
           public native int divVals(int a, int b);

 static{
           System.loadLibrary("calcvals");
 }
안드로이드 JNI
 4. calcvals.h 파일 생성

    #include <jni.h>

    #ifndef _addvals_h
    #define _addvals_h
    #ifdef __cplusplus

    extern "C"
    {
           #endif
           jint Java_com_solab_jnicalc_MainActivity_addVals(JNIEnv* env,jobject thiz,jint a, jint

             jint Java_com_solab_jnicalc_MainActivity_subVals(JNIEnv* env,jobject thiz,jint a, jint

             jint Java_com_solab_jnicalc_MainActivity_mulVals(JNIEnv* env,jobject thiz,jint a, jint

             jint Java_com_solab_jnicalc_MainActivity_divVals(JNIEnv* env,jobject thiz,jint a, jint


             #ifdef __cplusplus
    }
    #endif
    #endif
안드로이드 JNI
 5. calcvals.c 파일 생성

   #include "calcvals.h"

   jint Java_com_solab_jnicalc_MainActivity_addVals(JNIEnv* env,jobject thiz,jint a, jint b)
   {
          return a+b;
   }
   jint Java_com_solab_jnicalc_MainActivity_subVals(JNIEnv* env,jobject thiz,jint a, jint b)
   {
          return a-b;
   }
   jint Java_com_solab_jnicalc_MainActivity_mulVals(JNIEnv* env,jobject thiz,jint a, jint b)
   {
          return a*b;
   }
   jint Java_com_solab_jnicalc_MainActivity_divVals(JNIEnv* env,jobject thiz,jint a, jint b)
   {
          return a/b;
   }
안드로이드 JNI
 6. 빌드
     - 먼저, 프로젝트 폴더로 이동하여 ndk-build명령을 실행한다.




    - 빌드에 성공하면 libs/armeabi 폴더 아래에 libcalcvals.so생성됨
    - 이클립스에서 project -> clean 후에 프로그램 실행

Android ndk jni 설치및 연동

  • 1.
    Android NDK JNI S.O.LABdevelop by OracleON(이상온)
  • 2.
    안드로이드 NDK - 안드로이드SDK와 함께 이용되는 개발키트 => 안드로이드 NDK를 사용하면 애플리케이션의 일부 또는 전부를 c/c++로 만들수 있다. => NDK로 만들어진 실행파일은 바이너리코드이다.(기계어) - NDK 포함된 것들 => 컴파일러, 링커,ToolChain,헤더파일,라이브러리,문서, 예제소스 - SDK가 기본으로 사용되며, NDK는 보조적인 역할을 하기 위해 사용 - NDK에서 할수 있는 것들 => OpenGL/ES , OpenSL/ES(사운드), 센서입력,터치패널 => NativeActivity , 리눅스시스템콜 => Assets폴더로부터 데이터입력(파일을 추가할때마다 빌드필요없다)
  • 3.
    안드로이드 내부구조(계층) - 리눅스커널 => 하드웨어 추상계층(HAL) => 라이브러리,안드로이드런타임 => 애플리케이션 프레임워크 => 애플리케이션 - 안드로이드 런타임 : (달빅VM) - 애플리케이션 프레임워크 : 버튼,텍스트박스 같은 애플리케이션을 동작시키는데 필요한 라이브러리가 포함 - 애플리케이션 실행환경 => 자바소스 => VM바이트코드 =>VM =>라이브러리 => 커널 - NDK 실행환경 => 네이티브코드 => 라이브러리 => 커널 자바로 만들어지 부분중 NDK코드는 달빅VM을 거치지 않고 바로 라이브러리를 호출한다.
  • 4.
    안드로이드 내부구조(계층) - SDK,NDK같이개발한 소스는 VM바이트코드+네이티브코드 포함한 하나의 실행파일에 공존하게 된다. - NDK경우 c/c++로 만든코드는 컴파일러와 링커를 거쳐 .so 파일로 생성 => 공유라이브러이 이므로 단독으로 동작할수 없다. - 자바코드 (.dex파일)로 부터 호출하여 .so 모듈을 이용 - 자바코드을 빌드할때 모듈(.so)을 이용하여 실행파일(.apk)생성 - NDK단점 1. 디버깅이 어렵다 2. 디바이스마다 실행파일 만들어야한다.(하드웨어 의존성) - NDK장점 1. 빠른속도의 데이터 처리(이미지처리, 게임등) 2. c/c++ 라이브러리 사용
  • 5.
    안드로이드 NDK 설치for OS X - NDK 설치는 압축파일 형태로 배포되어 압축을 풀기만 하면 완료. - 맥OS X 기준으로 설명 1. http://developer.android.com/sdk/ndk/index.html (NDK다운) 2. 임시폴터에 압축풀기 $ tar xvf android-ndk-r5c-darwin-x86.tar.bz2 $ sudo mv android-ndk-r5c /Developer/SDKs/ 3. android-ndk-r5폴더에 포함된 명령어 실행하도록 패스 추가 export $PATH=/Developer/SDKs/android-ndk-r5c:$PATH
  • 6.
    안드로이드 NDK 설치for Window - Window 기준으로 설명 1. www.cygwin.com에서 시그윈설치(GNU make필요하기 때문) => 리눅스에서 자주 사용되는 명령어를 윈도우에서 가능하게 => Cygwin 설치 시에 Select Packages 단계에서 'make'를 체크 후 설치 2. 큰 카테고리에 +를 눌러서 활성화 시키면 아래 항목들 활성화 Devel : gcc-core, gcc-g++, make, swing Editor : vim * Devel통째로 받아서 설치 추천~!! 3.Windows 환경변수에서 PATH설정 C:cygwinbin;C:cygwinusrinclude 추가
  • 7.
    안드로이드 NDK 설치for Window - Window 기준으로 설명 4. http://developer.android.com/sdk/ndk 에서 ndk 를 받는다 5. NDK 의 압축을 푼다. (cygwin/home/계정/하위폴더에 설치) => C:cygwinhomeAdministratorandroid-ndk-r8c 6. cygwinhome(사용자계정)Administrator.bashrc 파일수정 export ANDROID_NDK_ROOT= homeAdministratorandroid-ndk-r8c
  • 8.
    안드로이드 NDK 설치for Window 6. 환경변수의 시스템변수에서 새로만들기 ANDROID_SDK 변수이름, 값은 설치한디렉토리 ANDROID_NDK 변수이름, 값은 설치한 디렉토리 7. 환경변수의 시스템변수-> PATH 값 설정 C:Program Files (x86)Androidandroid-sdktools; C:Program Files (x86)Androidandroid-sdkplatform-tools; C:cygwinhomeAdministratorandroid-ndk-r8c;
  • 9.
    안드로이드 JNI - 자바에서c/c++의 함수를 사용할수 있게 해주는 인터페이스 - JNI 규약 1. 메모리 관리 => 자바는 달빅VM이 메모리 관리하지만 c/c++은 개발자가 메모리 관리를 책임지고 할당,해제 해야한다. 2. 타입선언 =>자바의 자료형을 c/c++에서 사용할때 자바자료형 앞에j를 붙인다. (예: byte=>jbyte , int=>jint , float=>jfloat , object=>jobject) =>자바의 배열형은 c/c++에서 Array를 붙여서 선언 (예: byte[] => jbyteArray) 3. 시그니처: 메소드를 만들때 사용하는 독특한 형태 =>원시타입은 알파벳 한글자로 표현(byte=>B , long=>J) =>클래스앞에는 L,끝에는 세미콜론을 붙인다. =>클래스명은 패키지명을 포함한 문자열로 지정 (예: Ljava/lang/String; => 자바의 String타입일경우) =>배열은 선투에 '['을 붙여서 지정 (예: int[] => [I; , String[]=> [Ljava/lang/String;
  • 10.
    안드로이드 JNI => 인수,반환값은 소괄호'(',')'로 구분, 반환값 void면 'V' B=byte, F=float,I=int,J=long, V=void, Z=boolean , C=char (예: void foo(int val) => (I)V String bar(int val) => (I)Ljava/lang/String; void buzz() =>()V 4. JNI에서 C와 C++의 차이 => C에서는 env구조체 함수포인터를 이용해 호출 (예:FindClass함수호출 jclass jklass =(*env)->FindClass(env,"java/lang/Integer"); ) => C++에서는 env인스턴스의 멤버함수를 호출 (예:FindClass함수호출 jclass jklass =env->FindClass("java/lang/Integer"); )
  • 11.
    안드로이드 JNI 5.메소드 정의 규칙 * 자바측 - 호출하는 함수를 선언할때 native 추가 - loadLibrary()를 이용해 호출할 라이브러리를 지정 public native int addVals(int a,int b); // native 붙인다 static{ System.loadLibrary("calcvals"); //libcalcvals.so 로드 } * c/c++ 측 - 함수명은 java로 시작, 패키지명+클래스명+메서드명 연결하여 기술 - 인수중 처음2개의 인수는 JNIEnv,jObject타입으로 한다. #include <jni.h> jint java_com_solab_calcval_MainActivity_addVals(JNIEnv* env,jObject thiz , jint a, jint b) { return a+b; } =>co.solab.clacval 패키지에 있는 MainActivity 클래스의 addVals메서드 호출
  • 12.
    안드로이드 JNI 6.리플렉션 => c/c++에서 자바의 클래스에 접근할수 있는 기능(자바함수, 자바 변수 호출) 예: 문자열을 넣으면 숫자값으로 변화하는 자바클래스의 parseInt 함수 호출 jclass jklass= (*env)->FindClass(env,"java/lang/Integer"); - FindClass함수를 이용하여 java.lang.Integer클래스를 가져온다. jmethodID jmethod = (*env)->GetStaticMethodID(env, jklass,"parseInt","(Ljava/lang/String);I"); - jmethod 에 "parseInt"와 인수, 반환값을 전달하고 해당 메서드의 ID를 구한다. if(jmethod == NULL)return; jint value =(*env)->CallStaticIntMethod(env, jklass,jmethod,strInt); - jklass 클래스와 jmethod를 실행 예: intValue라는 int타입의 멤버변수를 가져오는 코드 jfieldID jfieldid = (*env)->GetFieldID(env, instance,"intValue","I"); - 세번째인수 : 가져올 변수명, 네번째인수: 가져올 변수타입 if(jfieldid = NULL)return; jint val = (*env)->GetIntField(env,instance,jfieldid); - GetXXXField 멤버변수를 int 타입으로 가져온다.
  • 13.
    안드로이드 JNI 7.C/C++에서 자바의 배열 사용법 - 자바의 배열을 가져올려면 GetXXXArrayElements(XXX) - releaseArrayElements 배열메모리 영역 해제 8. C/C++에서 자바의 예외 발생 - ExceptionCheck 함수 - ExceptionOccurred 함수 - ExceptionClear 함수 9. 문자열 - UTF-8인코딩된 문자열 jstring jstr =(*env)->NewStringUTF(env, "펭귄"); jsize jlen =(*env)->GetStringLength(env,jstr); const char* bytes =(*env)->GetStringUTFChars(env,jstr,NULL); (*env)->ReleaseStringUTFChars(env,jstr,bytes);
  • 14.
    안드로이드 JNI 10.대규모 메모리 처리 - 자바에서 C/C++로 이미지 데이터 보내기 1. 자바의 배열을 이용하기 : 자바에서 설정한 배열을 C/C++용으로 변환해서 저장 2. java.nio.ByteBuffer클래스 이용 : 변환과정 필요없어 처리시간 단축 NewDirectByteBuffer(JNIEnv * env,viud* address, jlong capacity) -> 메모리 주소와 크기를 설정하고 새로운 인스턴스 생성 GetDirectBufferAddress(JNIEnv *env, jobject buf) -> 인스턴스를 전달하고 시작주소를 반환한다. GetDirectBufferCapacity(JNIEnv *env, jobject buf) -> 인스턴스를 전달하고 크기를 반환한다. 11. 리틀 엔디언, 빅 엔디언 데이터를 메모리에 저장할때 상위비트부터 저장 : 빅에디언 데이터를 메모리에 저장할때 하위비트부터 저장 : 리틀에디언 =>달빅VM에서는 리틀에디언 사용
  • 15.
    안드로이드 JNI 12. Android.mk 파일 - 안드로이드 NDK를 이용하여 빌드할려면 Android.mk파일이 필요 - c/c++에서 makefile을 만들어서 빌드하지만 안드로이드는 Android.mk 파일만 듬 - 모듈을 만드는데 필요한 소스코드 및 링크할 라이브러리 지정 - 문법은 GNU make에 따라 작성 예: clacvlas.c에서 모듈인 libcalcvalc.so 파일을 생성 LOCAL_PATH :=$(call my-dir) include $(CLEAR_VARS) -> 이전의 모든 설정을 정리 LOCAL_MODULE := calcvals -> 생성할 모듈 지정 ,libcalcvalc.so 라는 공유라이브러리가 생성 LOCAL_SRC_FILES := calcvals.c -> 생성된 모듈을 빌드하는데 필요한 소스파일을 지정 include $(BUILD_SHARED_LIBRARY) -> 이 라이브러리는 공유라이브러리로 생성
  • 16.
    안드로이드 JNI - 자바에서C 함수 호출하기 * int타입만 사용해 사칙연산 메소드 만들기 실습 * 1. 프로젝트 만들기 - cygwin/home/user계정/ 폴더에 프로젝트를 생성한다. - 이클립스에서 프로젝트 생성후 소스코드와 Android.mk 파일위한 jni폴더 추가 2. jni폴터 밑에 Android.mk 파일 생성 LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_SRC_FILES := calcvals.c LOCAL_MODULE := calcvals include $(BUILD_SHARED_LIBRARY) => 이 파일에 의해 calcvals.c가 빌드되고 libcalcvals.so파일이 만들어진다.
  • 17.
    안드로이드 JNI 3.MainActivity.java 변경 protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); StringBuffer buf = new StringBuffer(); TextView tv = new TextView(this); int a=10; int b=2; int val = addVals(a,b); buf.append("a+b="+String.valueOf(val)+"n"); val = subVals(a,b); buf.append("a-b="+String.valueOf(val)+"n"); val = mulVals(a,b); buf.append("a*b="+String.valueOf(val)+"n"); val = divVals(a,b); buf.append("a/b="+String.valueOf(val)+"n"); tv.setText(buf.toString()); setContentView(tv); } public native int addVals(int a, int b); public native int subVals(int a, int b); public native int mulVals(int a, int b); public native int divVals(int a, int b); static{ System.loadLibrary("calcvals"); }
  • 18.
    안드로이드 JNI 4.calcvals.h 파일 생성 #include <jni.h> #ifndef _addvals_h #define _addvals_h #ifdef __cplusplus extern "C" { #endif jint Java_com_solab_jnicalc_MainActivity_addVals(JNIEnv* env,jobject thiz,jint a, jint jint Java_com_solab_jnicalc_MainActivity_subVals(JNIEnv* env,jobject thiz,jint a, jint jint Java_com_solab_jnicalc_MainActivity_mulVals(JNIEnv* env,jobject thiz,jint a, jint jint Java_com_solab_jnicalc_MainActivity_divVals(JNIEnv* env,jobject thiz,jint a, jint #ifdef __cplusplus } #endif #endif
  • 19.
    안드로이드 JNI 5.calcvals.c 파일 생성 #include "calcvals.h" jint Java_com_solab_jnicalc_MainActivity_addVals(JNIEnv* env,jobject thiz,jint a, jint b) { return a+b; } jint Java_com_solab_jnicalc_MainActivity_subVals(JNIEnv* env,jobject thiz,jint a, jint b) { return a-b; } jint Java_com_solab_jnicalc_MainActivity_mulVals(JNIEnv* env,jobject thiz,jint a, jint b) { return a*b; } jint Java_com_solab_jnicalc_MainActivity_divVals(JNIEnv* env,jobject thiz,jint a, jint b) { return a/b; }
  • 20.
    안드로이드 JNI 6.빌드 - 먼저, 프로젝트 폴더로 이동하여 ndk-build명령을 실행한다. - 빌드에 성공하면 libs/armeabi 폴더 아래에 libcalcvals.so생성됨 - 이클립스에서 project -> clean 후에 프로그램 실행