Android 2011. 1. 18. 10:51
반응형
반응형
posted by ssuk1010
:
Android 2010. 12. 30. 16:18
반응형

출처 :http://shchoi82.springnote.com/pages/6150375

우선 NDK는 Native Developmet Kit의 약자입니다.

자바의 JNI기술을 사용하여 안드로이드 app(java)와 안드로이드 library(c/c++)계층을 연결해주는 역할을 합니다.

 

윈도우에서 사용 cygwin에서 사용하는 방법예제입니다.

 

1. NDK를 다운로드

   아래의 http://developer.android.com에서 ndk-android-r4b 를 다운받는다.

   ※ r4b의 r은 revision 4번째 버젼이라는 의미입니다.

       2010년 7월 30일 최신버젼이 r4b 이군요

그림1.png

 

 

2. cygwin설치

   아래의 www.cygwin.com에서 다운로드

그림3.png

 

그림4.png

 

   cygwin은 설치 인터넷 접속해서 다운로드후 설치됩니다.

   GNU awk또는 Nawk 와 GNU Make 3.81이상이 같이 설치되어야 합니다.

   awk는 이미 default에 들어가 있구요 make만 체크하시고 설치합니다.

   install 하시면 됨, 저는 이미 설치되어 있기때문에 Keep이라고 나오는군요

 

 

3. cygwin 환경설정

그림6.png

 

~/.vimrc파일 수정

 

그림5.png

ndk-build명령은 어디서든 실행하기 위해 PATH환경변수에 추가시켜줍니다.

위의파일은 ~/.bash_profile입니다.

※ /(루트)의 cygwin 디렉토리는 윈도우의 "내컴퓨터"와 같은경로입니다.

    android-ndk-r4b의 경로를 적절하게 넣어주시면 됩니다.

 

예제 소스 빌드

그림7.png

sample파일 디렉토리에서 

프로젝트 루트 또는 프로젝트\jni 폴더에서 ndk-build 하시면 빌드가 됩니다.


간단한 예제 실습

1. 액티비티 레이아웃구성 

   텍스트뷰 하나와 버튼하나 추가

그림8.png

 

2. 액티비티 구현

버튼클릭으로 jni를 호출하는 소스를 onCreate에 간단하게 구현 해봤습니다.

그림9.png

 

3. 간단한 클래스 만들기

   간단하게 native 함수가 들어가있는 NativeCall 클래스를 생성

   native 키워드는 javah가 헤더파일을 생성할때 참조하게 되는 키워드입니다. 구현부가 없습니다.

   ※ static 부분은 class의 객체가 생성될때 (new) 되어질때 호출됩니다. "my_lib"은 ndk-build로 생성된 라이브러리 이름입니다. 파일명은  libmy_lib.so 입니다.

그림10.png

 

 

4.  javah실행 헤더파일을 만듭니다.

    아래에 보시면 bin폴더에서 실행하고 있는것을 볼수 있습니다.

    javah는 내부적으로 ./ssu/os/android/NativeCall.class 파일을 참고하여 헤더파일을 생성하게됩니다.

    하위디렉토리를 페키지에 맞춰진 경로에 class파일 존재해야합니다.

 

    헤더파일명은 페키지명과 클래스명을 참고해서 아래와같이 생성됩니다.

    -o 옵션을 사용하면 파일명을 지정할수 있습니다.

    프로젝트 경로 밑에 jni 폴더를 생성하고 파일을 옮겨줍니다.

   

   

그림11.png

 

 생성된 헤더파일의 내용

 native 키워드로 되어있던 함수들이 jni형태 함수 프로토타입을 확인할수 있습니다.

 복잡해보이지만 C문법입니다.

※ ifdef __cpluscplus 에서보듯이 c++도 지원됩니다.

그림12.png

 

5. 함수구현

  my_lib.c 파일을 만들어 함수를 구현합니다.

  두게의 함수가 있는대 하나는 단순하게 string을 리턴해줍니다.

  다른 하나는 두정수를 입력받아 더한후 리턴.

그림13.png

 

6. Android.mk파일 작성

   기존의 hello jni 샘플의 파일을 가져와서 작성합니다.

   수정된내용은 LOCAL_MODULE , LOCAL_SRC_FILES 이 바뀌었습니다.

   LOCAL_MODULE에는 라이브러리 명을 써주시면 되고

   LOCAL_SRC_FILES는 작성하신 C소스 파일명을 넣어주시면 됩니다.

그림14.png

 

7. ndk-build

   프로젝트루트나 jni 경로에서 ndk-build명령을 실행합니다.

그림15.png

 

libs 폴더가 생성되고 라이브러리 .so파일이 생성된것을 확인할수 있습니다.

그림16.png

 

8. 에뮬레이터 실행

    위의 과정이 정상적으로 진행되었으면 아래와 같이 실행됩니다.

    버튼을 누르면 jni가 호출되어 스트링을 가져와 textview에 뿌려줍니다.

 

 그림20.png


반응형
posted by ssuk1010
:
Android 2010. 12. 30. 13:45
반응형

Android에서 JNI 프로그램 작성

From DISLab

Jump to: navigation, search

Contents

[hide]

JNI 프로그램 작성을 위한 개발 환경 셋팅

  • JNI를 사용하기 위해서는 윈도우즈와 리눅스에서 개발환경을 셋팅할 수 있다.
  • 리눅스와 윈도우즈 둘의 차이점은 cygwin 설치 밖에 없음.
  • Android SDK, Android NDK, Cygwin 프로그램이 시스템에 설치되었고 ADT가 Eclipse에 설치되었다면 Android 프로젝트에서 JNI(Java Native Interface)를 이용하여 C, C++언어에서 작성된 공유 라이브러리(*.so)를 로드하고 포함된 함수를 호출할 수 있는 프로그램을 작성할 수 있다.


리눅스에서의 개발환경 셋팅


윈도우즈에서의 개발환경 셋팅

Cygwin 설치

  • Cygwin 이란 ? 윈도우 시스템에서 Linux와 비슷한 환경을 만들어주는 프로그램
  • Cygwin 설치방법
    1. setup.exe 파일 실행 - install from internet 선택
    2. Root 경로 지정 & install For All Users
    3. Download 받을 패키지가 저장될 경로 지정(Select Local package Directory)
    4. Internet 연결 - Direct connection 선택
    5. Download Site 선택 - ftp://ftp.kaist.ac.kr
    6. Progress - 패키지 목록을 가져옴 --> 처음 설치할 경우 설치할 패키지를 선택할 수 있다는 알림창 뜸
    7. 설치할 수 있는 패키지 목록이 대화창에 출력됨, 필요한 것 선택 Devel/gcc-g++, Devel/gcc-core, Devel/make, Editor/vim
      • 나중에 다시 필요한 패키지 설치할 수 있음. 선택한 패키지의 크기에 따라 시간이 좀 걸린다.
      • 설치화면
      • ㅣ설치화면
    8. 시작메뉴에 Cygwin Bash Shell 메뉴 생성된 것 확인 . 설치 완료
      • Cygwin Bash Shell 화면
      • Cygwin Bash Shell 화면
      • 더 설치하고 싶은 패키지가 있으면 다시 setup.exe 파일을 실행시켜 동일한 방법으로 다운받으면 된다.


Android NDK 설치

  • NDK Download 받기
    • URL : http://developer.android.com/sdk/ndk/index.html
    • Android developers 사이트에 가면 SDK 페이지 좌측에 메뉴에 Native Development Tools 메뉴에서 NDK 선택
    • Download the Android NDK 에서 자신의 개발환경에 맞는 OS 선택 - 이 페이지의 설명은 Windows 기반임.
    • Download the Android NDK Webpage
    • ㅣDownload the Android NDK Webpage


  • NDK 설치하기
    • 다운받은 android-ndk-r4.zip 파일을 Cygwin이 설치된 폴더 안의 Home에 복사
    • copy path - C:/cgywin/home/계정명/ 밑에 복사해줌
    • Android NDK Path 설정
    • ㅣAndroid NDK Path 설정


  • 다운로드 받아서 Path만 지정해주면 NDK를 사용하기 위한 절차는 끝


Hello JNI Example

  • NDK 설치가 끝나면 테스트해보기 위한 Sample Code가 있다. Sample Code 중 HelloJni를 구동하는 절차를 설명한다.
  • 윈도우즈 환경 셋팅에서 설치한 cgywin을 사용하여 NDK 빌드를 할 수 있다.

NDK 빌드

  • Cygwin Bash Shell 을 실행해서 android-ndk-r4 폴더로 이동
    • 빌드할 프로젝트 폴더인 samples로 이동 >> android-ndk-r4/samples/hello-jni
    • ndk-build 를 실행하여 빌드 시작 >> /home/Ryoung/android-nkd-r4/ndk-build -B
    • ㅣNDK Build
  • .so 파일 생성
    • /android_ndk/samples/hello-jni/libs/armeabi 경로에 가면 libhello-jni.so 파일 생성된 것 확인할 수 있다.
    • ㅣ.so파일 생성

Hello Jni 실행

  • 예제 파일이였던 Hello Jni가 들어있는 Sample 파일 가져와서 프로젝트 생성
    • 경로 : android-ndk/samples/hello-jni
    • ㅣndk 빌드해서 생성한 .so 파일 확인


  • Android 에뮬레이터 부팅이 ㅣ끝나면 HelloJni 구동화면 볼 수 있음
  • ㅣ안드로이드 에뮬레이터 구동화면
  • Android NDK에서 제공하는 Sample code는 원시코드의 헤더파일이 이미 만들어져있기 때문 NDK 빌드만 하면 에뮬레이터로 결과를 확인할 수 있다.



HelloJni Sample Code

  • NDK에 포함되어 있는 샘플 코드는 원시코드의 헤더파일이 이미 만들어져있으나, 샘플코드를 기반으로 헤더파일을 만들고 JNI 프로그램을 작성하는 절차를 설명하도록 한다.


안드로이드 프로젝트 생성

  • 제일 먼저 이클립스에서 일반적인 안드로이드 프로젝트를 생성한다.
    • New Project

자바 클래스 작성

  • JNI 규칙에 따라서 공유라이브러리를 로드하고 라이브러리에 포함된 함수를 호출하는 native 메소드를 선언한다.
  • HelloJni.java
package com.example.hellojni;
import android.app.Activity;
import android.widget.TextView;
import android.os.Bundle;
 
public class HelloJni extends Activity {
        /**Called when the activity is first created.*/
        @Override
        public void onCreate(Bundle savedInstanceState) {
                super.onCreate(savedInstanceState);
                TextView tv= new TextView(this);
                tv.setText(stringFromJNI()); // A native 함수호출
                   setContentView(tv);
        }           
 
        // A native function
        public native String stringFromJNI();
 
        // 정의하지 않은 함수 호출시 java.lang.UnsatisfiedLink Errorexception 발생!
        public native String unimplementedStringFromJNI();
 
        // com.example.HelloJni/lib/libhello-jni.so
        static {
                System.loadLibrary("hello-jni");
        }
}
  • Native Method Declaration : public native String stringFromJNI();
    • Native 선언은 자바 가상 머신 내에서 원시 함수를 호출할 수 있는 브릿지를 제공해 준다.
  • 라이브러리 적재 : System.loadLibrary()
    • 원시 코드 구현을 포함하고 있는 라이브러리는 System.loadLibrary()를 호출함으로써 적재된다. 정적 초기화 구문(static initializer ensures) 내에서 이 호출을 함으로써, 클래스당 단 한번만 적재되도록 한다. 클래스에 대해 공유되는 멤버들은 static을 이용하여 선언한다. 클래스 멤버를 선언하는 위치에 static{....} 과 같이 초기화 블럭을 정의하여 사용할 수 있다.
  • main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    >
<TextView
	android:id="@+id/textView"  
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content" 
    android:text="@string/hello"
    />
</LinearLayout>


헤더파일 작성과 프로그램 컴파일

  • 프로그램 컴파일은 command line을 이용하므로 앞에서 설치한 cgywin을 사용한다.
    • 프로젝트가 컴파일 된 bin 디렉토리로 이동한 뒤 javah packagename.classname 를 수행하면 아래 그림과 같이 헤더파일이 생성된다.
    • javah
    • 패키지명이 포함되어 헤더파일이름이 생성되므로 너무 길면 줄여서 사용해도 무방하다.
      • hufs.dislab.hellojni.HelloJni.h --> HelloJni.h


  • 생성된 HelloJni.h
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class hufs_dislab_hellojni_HelloJni */
 
#ifndef _Included_hufs_dislab_hellojni_HelloJni
#define _Included_hufs_dislab_hellojni_HelloJni
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     hufs_dislab_hellojni_HelloJni
 * Method:    stringFromJNI
 * Signature: ()Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_hufs_dislab_hellojni_HelloJni_stringFromJNI
  (JNIEnv *, jobject);
 
/*
 * Class:     hufs_dislab_hellojni_HelloJni
 * Method:    unimplementedStringFromJNI
 * Signature: ()Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_hufs_dislab_hellojni_HelloJni_unimplementedStringFromJNI
  (JNIEnv *, jobject);
 
#ifdef __cplusplus
}
#endif
#endif

라이브러리 생성을 위한 jni 디렉토리 생성

  • 만들어진 헤더파일(HelloJni.h)을 jni 디렉토리로 이동시킨다.
  • jni 디렉토리는 프로젝트 내에 생성하고 이 디렉토리는 위에서 생성한 헤더파일, C파일, Android.mk 파일을 저장한다.
  • Jni 디렉토리 생성


Android.mk 파일 생성

  • LOCAL_MODULE 에 설정한 값으로 나중에 생성될 공유 라이브러리 이름이 된다. HelloJniTest --> libHelloJniTest.so (일반적으로 라이브러리 이름은 소문자로 해야함...;; )
  • 컴파일할 소스파일이 여러 개일 경우에는 LOCAL_SRC_FILES에 나열해 준다.
  • Android.mk
LOCAL_PATH := $(call my-dir)
 
include $(CLEAR_VARS)
 
LOCAL_MODULE    := HelloJniTest
LOCAL_SRC_FILES := HelloJni.c
 
include $(BUILD_SHARED_LIBRARY)

Native code 작성(C파일 생성)

  • 생성한 헤더파일에 선언된 C 함수를 구현한다.선언된 C함수를 모두 구현하지 않아도 무방하다.
  • Hello-Jni.c
#include <string.h>
#include <jni.h>
 
jstring Java_hufs_dislab_hellojni_HelloJni_stringFromJNI( JNIEnv* env, jobject thiz )
{
        return (*env) -> NewStringUTF(env, "Hello From JNI !");
}


C소스 컴파일 / 공유라이브러리 생성

  • 앞에서 구현한 C 코드를 컴파일하여 라이브러리를 생성한다.
  • C코드 컴파일 & 라이브러리 생성
  • 위의 그림과 같이 Cygwin을 실행하고 해달 프로젝트로 이동한다. 그리고 ndk-build 명령을 이용하여 컴파일을 한다.
  • 컴파일이 끝나면 프로젝트 안에 libs/armeabi 디렉토리가 생성되고 HelloJniTest.so 가 생긴 것을 확인할 수 있다.
  • .so파일 생성 확인
  • 라이브러리 생성 과정까지 마치고 에뮬레이터를 돌려 결과를 확인한다. JNI 프로그램 작성 끝!


참고

Android NDK

  • NAtive code를 안드로이드 애플리케이션에 적용할 수 있게 함
  • NDK는 다음을 제공
    • C와 C++로 라이브러리 작성하는 툴
    • 라이브러리를 Android에 적재할 수 있는 .apsk로 변환하는 방법 제공
    • Native System headers & libraries
    • Documentation, samples & tutorials
  • NDK 활용의 예 : 신호처리, 물리 시뮬레이션, 커스텀 바이트코드/ 명령어 인터프리터 등과 같이 메모리를 너무 많이 할당하지 않으면서도 CPU를 많이 사용하는 작업에 적함
    • 장점 : 빠른실행
    • 단점 : 이식성 없음, JNI 오버헤드 수반, 시스템 라이브러리에 접근불가, 디버깅 어려움
    • 한계
    1. C에서 실행되는 메소드를 단순히 재코딩 하는것 으로는 성능향상에 큰 도움이 되지 않는다.
    2. NDK가 native-only 어플리케이션 개발은 힘들다.(Please note that the NDK does not enable you to develop native-only application)
    3. 안드로이드의 첫 번째 런타임은 Dalvik 가상머신에 있다.
  • 포함 되어 있는 C 헤더들
    • libc ( C 라이브러리 ) 헤더
    • libm ( math 라이브러리 ) 헤더
    • Jni Interface 헤더
  • 호환성을 보장하는 방법( application using a native library produced with the NDK)
    • 해당 매니페스트 파일에 android:minSdkVersion="3" 속성과 함께 <users-library> 엘리먼트를 반드시 선언한다.

출처: http://dislab.hufs.ac.kr/wiki/Android%EC%97%90%EC%84%9C_JNI_%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%A8_%EC%9E%91%EC%84%B1
반응형
posted by ssuk1010
: