카테고리 없음
NDK를 이용한 Android 예제
53프로
2012. 2. 28. 15:21
서너달 만에 다시 안드로이드를 할려기 기억이 가물 가물하다.
예전에 하던거 쉽게 까먹는다 그래서 예전에 보고 하던 실습 예제 스크립해 둔다. 까먹어도 쉽게 찾기 위해서...
http://viiiin.tistory.com/12
1. 개발환경
2. Cygwin 설치 및 환경설정
Cygwin을 사용하는 이유는 기본적으로 Android 개발 환경이 Linux 기반으로 되어 있기 때문이고, ndk-build 명령으로 빌드하기 위함입니다. 개인적으로 MinGW를 사용하시는 분은 MinGW에서 하셔도 좋습니다.
Cygwin 설치 시에 Select Packages 단계에서 'make'를 체크 후 설치해 줍니다.
저는 이미 설치되어 있기 때문에 'Keep'이라고 나오는 것입니다. 'Skip'부분을 클릭하면 'Install'로 바꿀 수 있습니다. 같은 방법으로 Search 기능을 이용하여 'vim'을 검색 후, Editors 카테고리의 vim을 'Install'로 바꾼 후 설치해 줍니다. 혹시 나중에 추가로 필요한 패키지가 생길 경우 다운받은 Cygwin 폴더의 setup.exe를 실행시켜 패키지를 추가할 수 있습니다.
다음으로 Cygwin을 실행하여 ndk-build 명령을 어디서든 실행할 수 있게 하기 위해 .bash_profile 파일의 PATH 환경변수에 경로를 추가시켜 줍니다.
/cygdrive 는 윈도우의 '내컴퓨터'와 같은 경로입니다. 저의 경우에는 다운받은 NDK 폴더가 아래의 경로에 있기 때문에 그림과 같이 PATH설정을 해 준 것입니다. 본인의 경로에 맞게 수정해주면 됩니다.
그럼 이제 cygwin은 모두 준비가 끝난 상태입니다.
3. Eclipse Android Project 생성
이제 Eclipse를 이용하여 안드로이드 프로젝트를 만들어 보도록 하겠습니다.
먼저, [File]->[New]->[Project]를 선택하면 다음과 같은 창이 나옵니다.
Android Project를 선택한 후, Next를 클릭합니다.
아래 그림과 같이 빈 곳을 채워준 다음 Finish를 클릭합니다. 이 때, 저는 "Use default location"을 체크해제한 후, cygwin의 홈디렉토리에 프로젝트 폴더를 만든 후 이곳의 경로를 지정해 주었습니다.
다음 그림과 같이 프로그래밍할 준비를 마쳤습니다.
4. 예제 프로그래밍
그럼 이제 본격적으로 안드로이드 App 예제를 실행하기 위한 프로그래밍을 해 보도록 하겠습니다.
① Activity Layout 구성
위치 : [HelloAndroid]-[res]-[layout]-[main.xml]
텍스트뷰와 버튼을 각각 하나씩 추가합니다.
② Activity 구현
위치 : [HelloAndroid]-[src]-[ssu.os.android]-[NdkTestActivity.java]
버튼 클릭으로 jni를 호출하는 소스를 onCreate에 구현하였습니다.
혹시 에러가 나거든 [Ctrl+Shift+O]를 이용해 자동으로 import를 수행해 줍니다.
③ Class 만들기
위치 : [HelloAndroid]-[src]-[ssu.os.android]-[NativeCall.java]
위의 위치에 NativeCall.java 파일을 새로 생성합니다.
native 함수가 들어있는 NativeCall 클래스를 생성합니다. native 키워드는 javah가 헤더파일을 생성할 때 참조하게 되는 키워드 입니다. 구현부는 없습니다. static 부분은 class의 객체가 생성될 때 (new) 되어질 때 호출됩니다. "my_lib"는 ndk-build로 생성된 라이브러리 이름입니다. 파일명은 libmy_lib.so 입니다.
④ javah 실행
~/bin 디렉토리에서 javah를 실행합니다. javah는 내부적으로 ./ssu/os/android/NativeCall.class 파일을 참고하여 헤더파일을 생성하게 됩니다. 헤더 파일명은 패키지명과 클래스명을 참고해서 생성됩니다. -o 옵션을 사용하면 파일명을 임의로 지정할 수 있습니다. 프로젝트 폴더에 /jni 폴더를 생성하고, 만들어진 헤더파일을 옮겨줍니다.
- 생성 된 헤더파일(ssu_os_android_NativeCall.h) 내용
native 키워드로 되어있던 함수들이 jni 형태 함수 프로토타입을 확인할 수 있습니다.
복잡해 보이지만 C문법입니다.
⑤ 함수 구현
위치 : [HelloAndroid]-[jni]-[my_lib.c]
/jni 폴더에 my_lib.c 파일을 만들어서 다음과 같이 함수를 구현합니다. 두 개의 함수가 있는데 단순히 string을 리턴해 주는 함수와 두 정수를 입력받아 더한 후 리턴하는 함수입니다.
⑥ Android.mk 파일 작성
위치 : [HelloAndroid]-[jni]-[Android.mk]
다운받은 Android NDK 폴더의 /sample/hello-jni/jni 의 Android.mk 파일을 현재 프로젝트의 /jni 폴더에 복사한 후, 다음과 같이 수정하여 사용합니다. 수정 된 내용은 19, 20 라인의 LOCAL_MODULE 과 LOCAL_SRC_FILES 입니다.
⑦ NDK Build
프로젝트 루트 혹은 /jni 디렉토리에서 "ndk-build" 명령을 실행합니다.
빌드가 끝나면 프로젝트 폴더 밑에 /libs 폴더가 생성되고, 라이브러리인 .so 파일이 생성 된 것을 확인할 수 있습니다.
⑧ 에뮬레이터 실행
위의 과정이 정상적으로 진행되었으면 Eclipse에서 에뮬레이터를 실행시켜 줍니다. 안드로이드 부팅 과정이 끝나면 우리가 작성한 App을 볼 수 있을 것입니다.
Call JNI" 버튼을 누르게 되면 jni가 호출되어 스트링을 가져와 화면(TextView)에 뿌려주게 됩니다.
<참고 사이트>
[1] http://shchoi82.springnote.com/pages/6150375
예전에 하던거 쉽게 까먹는다 그래서 예전에 보고 하던 실습 예제 스크립해 둔다. 까먹어도 쉽게 찾기 위해서...
http://viiiin.tistory.com/12
1. 개발환경
Host OS
- Windows 7 Ultimate x86
Cygwin
- version 2.712
- http://www.cygwin.com
Eclipse
- Eclipse IDE for Java Developers : Galileo Packages(ver 3.5)
- http://www.eclipse.org/downloads
JDK
- Java SE Development Kit 6u21
- http://www.oracle.com/technetwork/java/javase/downloads/index.html
Android SDK & NDK
- Android SDK Package : android-sdk_r06-windows.zip
- Android NDK Package : android-ndk_r4b-windows.zip
- Android SDK and AVD Manager(Packages and Archives) : http://dl-ssl.google.com/android/eclipse
- http://developer.android.com/sdk/index.html
- Windows 7 Ultimate x86
Cygwin
- version 2.712
- http://www.cygwin.com
Eclipse
- Eclipse IDE for Java Developers : Galileo Packages(ver 3.5)
- http://www.eclipse.org/downloads
JDK
- Java SE Development Kit 6u21
- http://www.oracle.com/technetwork/java/javase/downloads/index.html
Android SDK & NDK
- Android SDK Package : android-sdk_r06-windows.zip
- Android NDK Package : android-ndk_r4b-windows.zip
- Android SDK and AVD Manager(Packages and Archives) : http://dl-ssl.google.com/android/eclipse
- http://developer.android.com/sdk/index.html
2. Cygwin 설치 및 환경설정
Cygwin을 사용하는 이유는 기본적으로 Android 개발 환경이 Linux 기반으로 되어 있기 때문이고, ndk-build 명령으로 빌드하기 위함입니다. 개인적으로 MinGW를 사용하시는 분은 MinGW에서 하셔도 좋습니다.
Cygwin 설치 시에 Select Packages 단계에서 'make'를 체크 후 설치해 줍니다.
저는 이미 설치되어 있기 때문에 'Keep'이라고 나오는 것입니다. 'Skip'부분을 클릭하면 'Install'로 바꿀 수 있습니다. 같은 방법으로 Search 기능을 이용하여 'vim'을 검색 후, Editors 카테고리의 vim을 'Install'로 바꾼 후 설치해 줍니다. 혹시 나중에 추가로 필요한 패키지가 생길 경우 다운받은 Cygwin 폴더의 setup.exe를 실행시켜 패키지를 추가할 수 있습니다.
다음으로 Cygwin을 실행하여 ndk-build 명령을 어디서든 실행할 수 있게 하기 위해 .bash_profile 파일의 PATH 환경변수에 경로를 추가시켜 줍니다.
/cygdrive 는 윈도우의 '내컴퓨터'와 같은 경로입니다. 저의 경우에는 다운받은 NDK 폴더가 아래의 경로에 있기 때문에 그림과 같이 PATH설정을 해 준 것입니다. 본인의 경로에 맞게 수정해주면 됩니다.
D:\UTIL\etc\Android_NDK_r4b\android-ndk-r4b
그럼 이제 cygwin은 모두 준비가 끝난 상태입니다.
3. Eclipse Android Project 생성
이제 Eclipse를 이용하여 안드로이드 프로젝트를 만들어 보도록 하겠습니다.
먼저, [File]->[New]->[Project]를 선택하면 다음과 같은 창이 나옵니다.
Android Project를 선택한 후, Next를 클릭합니다.
아래 그림과 같이 빈 곳을 채워준 다음 Finish를 클릭합니다. 이 때, 저는 "Use default location"을 체크해제한 후, cygwin의 홈디렉토리에 프로젝트 폴더를 만든 후 이곳의 경로를 지정해 주었습니다.
다음 그림과 같이 프로그래밍할 준비를 마쳤습니다.
4. 예제 프로그래밍
그럼 이제 본격적으로 안드로이드 App 예제를 실행하기 위한 프로그래밍을 해 보도록 하겠습니다.
① Activity Layout 구성
위치 : [HelloAndroid]-[res]-[layout]-[main.xml]
텍스트뷰와 버튼을 각각 하나씩 추가합니다.
01.
<?xml version=
"1.0"
encoding=
"utf-8"
?>
02.
<LinearLayout xmlns:android=
"http://schemas.android.com/apk/res/android"
03.
android:orientation=
"vertical"
04.
android:layout_width=
"fill_parent"
05.
android:layout_height=
"fill_parent"
06.
>
07.
<Button
08.
android:id=
"@+id/callbtn"
09.
android:layout_width=
"wrap_content"
10.
android:layout_height=
"wrap_content"
11.
android:text=
"Call JNI"
12.
/>
13.
<TextView
14.
android:id=
"@+id/rettxt"
15.
android:layout_width=
"fill_parent"
16.
android:layout_height=
"wrap_content"
17.
android:textSize=
"15pt"
18.
/>
19.
</LinearLayout>
② Activity 구현
위치 : [HelloAndroid]-[src]-[ssu.os.android]-[NdkTestActivity.java]
버튼 클릭으로 jni를 호출하는 소스를 onCreate에 구현하였습니다.
혹시 에러가 나거든 [Ctrl+Shift+O]를 이용해 자동으로 import를 수행해 줍니다.
01.
package ssu.os.android;
02.
03.
import android.app.Activity;
04.
import android.os.Bundle;
05.
import android.util.Log;
06.
import android.view.View;
07.
import android.view.View.OnClickListener;
08.
import android.widget.Button;
09.
import android.widget.TextView;
10.
11.
public
class
NdkTestActivity extends Activity {
12.
/** Called when the activity is first created. */
13.
private
Button bv;
14.
private
TextView tv;
15.
16.
@Override
17.
public
void
onCreate(Bundle savedInstanceState) {
18.
super.onCreate(savedInstanceState);
19.
setContentView(R.layout.main);
20.
21.
bv = (Button)findViewById(R.id.callbtn);
22.
tv = (TextView)findViewById(R.id.rettxt);
23.
24.
bv.setOnClickListener(
new
OnClickListener() {
25.
public
void
onClick(View v) {
26.
NativeCall nativeCall =
new
NativeCall();
27.
int
ret = nativeCall.add(10, 20);
28.
String retStr = nativeCall.stringFromJNI();
29.
Log.i(
"TAG"
, retStr + ret);
30.
tv.setText(retStr);
31.
}
32.
});
33.
}
34.
}
③ Class 만들기
위치 : [HelloAndroid]-[src]-[ssu.os.android]-[NativeCall.java]
위의 위치에 NativeCall.java 파일을 새로 생성합니다.
native 함수가 들어있는 NativeCall 클래스를 생성합니다. native 키워드는 javah가 헤더파일을 생성할 때 참조하게 되는 키워드 입니다. 구현부는 없습니다. static 부분은 class의 객체가 생성될 때 (new) 되어질 때 호출됩니다. "my_lib"는 ndk-build로 생성된 라이브러리 이름입니다. 파일명은 libmy_lib.so 입니다.
01.
package ssu.os.android;
02.
03.
public
class
NativeCall {
04.
static
{
05.
System.loadLibrary(
"my_lib"
);
06.
}
07.
public
native String stringFromJNI();
08.
public
native
int
add(
int
a,
int
b);
09.
}
④ javah 실행
~/bin 디렉토리에서 javah를 실행합니다. javah는 내부적으로 ./ssu/os/android/NativeCall.class 파일을 참고하여 헤더파일을 생성하게 됩니다. 헤더 파일명은 패키지명과 클래스명을 참고해서 생성됩니다. -o 옵션을 사용하면 파일명을 임의로 지정할 수 있습니다. 프로젝트 폴더에 /jni 폴더를 생성하고, 만들어진 헤더파일을 옮겨줍니다.
- 생성 된 헤더파일(ssu_os_android_NativeCall.h) 내용
native 키워드로 되어있던 함수들이 jni 형태 함수 프로토타입을 확인할 수 있습니다.
복잡해 보이지만 C문법입니다.
01.
/* DO NOT EDIT THIS FILE - it is machine generated */
02.
#include <jni.h>
03.
/* Header for class ssu_os_android_NativeCall */
04.
05.
#ifndef _Included_ssu_os_android_NativeCall
06.
#define _Included_ssu_os_android_NativeCall
07.
#ifdef __cplusplus
08.
extern
"C"
{
09.
#endif
10.
/*
11.
* Class: ssu_os_android_NativeCall
12.
* Method: stringFromJNI
13.
* Signature: ()Ljava/lang/String;
14.
*/
15.
JNIEXPORT jstring JNICALL Java_ssu_os_android_NativeCall_stringFromJNI
16.
(JNIEnv *, jobject);
17.
18.
/*
19.
* Class: ssu_os_android_NativeCall
20.
* Method: add
21.
* Signature: (II)I
22.
*/
23.
JNIEXPORT jint JNICALL Java_ssu_os_android_NativeCall_add
24.
(JNIEnv *, jobject, jint, jint);
25.
26.
#ifdef __cplusplus
27.
}
28.
#endif
29.
#endif
⑤ 함수 구현
위치 : [HelloAndroid]-[jni]-[my_lib.c]
/jni 폴더에 my_lib.c 파일을 만들어서 다음과 같이 함수를 구현합니다. 두 개의 함수가 있는데 단순히 string을 리턴해 주는 함수와 두 정수를 입력받아 더한 후 리턴하는 함수입니다.
01.
#include "ssu_os_android_NativeCall.h"
02.
03.
JNIEXPORT jstring JNICALL Java_ssu_os_android_NativeCall_stringFromJNI(JNIEnv *env, jobject obj)
04.
{
05.
return
(*env)->NewStringUTF(env,
"Hello JNI!"
);
06.
}
07.
08.
JNIEXPORT jint JNICALL Java_ssu_os_android_NativeCall_add(JNIEnv *env, jobject obj, jint a, jint b)
09.
{
10.
return
a + b;
11.
}
⑥ Android.mk 파일 작성
위치 : [HelloAndroid]-[jni]-[Android.mk]
다운받은 Android NDK 폴더의 /sample/hello-jni/jni 의 Android.mk 파일을 현재 프로젝트의 /jni 폴더에 복사한 후, 다음과 같이 수정하여 사용합니다. 수정 된 내용은 19, 20 라인의 LOCAL_MODULE 과 LOCAL_SRC_FILES 입니다.
01.
# Copyright (C) 2009 The Android Open Source Project
02.
#
03.
# Licensed under the Apache License, Version 2.0 (the "License");
04.
# you may not use this file except in compliance with the License.
05.
# You may obtain a copy of the License at
06.
#
08.
#
09.
# Unless required by applicable law or agreed to in writing, software
10.
# distributed under the License is distributed on an "AS IS" BASIS,
11.
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12.
# See the License for the specific language governing permissions and
13.
# limitations under the License.
14.
#
15.
LOCAL_PATH := $(call my-dir)
16.
17.
include $(CLEAR_VARS)
18.
19.
LOCAL_MODULE := my_lib
20.
LOCAL_SRC_FILES := my_lib.c
21.
22.
include $(BUILD_SHARED_LIBRARY)
⑦ NDK Build
프로젝트 루트 혹은 /jni 디렉토리에서 "ndk-build" 명령을 실행합니다.
빌드가 끝나면 프로젝트 폴더 밑에 /libs 폴더가 생성되고, 라이브러리인 .so 파일이 생성 된 것을 확인할 수 있습니다.
⑧ 에뮬레이터 실행
위의 과정이 정상적으로 진행되었으면 Eclipse에서 에뮬레이터를 실행시켜 줍니다. 안드로이드 부팅 과정이 끝나면 우리가 작성한 App을 볼 수 있을 것입니다.
Call JNI" 버튼을 누르게 되면 jni가 호출되어 스트링을 가져와 화면(TextView)에 뿌려주게 됩니다.
<참고 사이트>
[1] http://shchoi82.springnote.com/pages/6150375