2010年3月10日水曜日

[Android] Android NDK r3를 사용해보다.

이번에 새로 릴리즈된 Android NDK r3를 사용해보았다.

OS는 Mac OS X 10.6.2

android-ndk-r3-darwin-x86.zip파일을 「http://developer.android.com/」사이트에서 다운로드하고 적당한 곳에 압축을 풀어놨다.
나는 「/Users/babukuma/dev/android-ndk-r3」이 경로에 풀어놨다.(이하 $NDK)

1. Android프로젝트 생성.
테스트용으로 프로젝트를 생성.

생성되면 프로젝트는 아마도 이런 구조.

여기서 「jni」폴더를 생성.


2. 「Application.mk」파일을 작성.
프로젝트 밑에 「Application.mk」파일을 작성한다.

여기서는 모듈명을 「jnitest」로 하였다.
작성법은 「$NDK/docs/APPLICATION-MK.TXT」파일을 참조.

# Application.mk
APP_PROJECT_PATH := $(call my-dir)
APP_MODULES := jnitest


3. Native메소드를 작성
「Main.java」파일에 작성하였다.

package com.babukuma.android.test.jni;

import android.app.Activity;
import android.os.Bundle;

public class Main extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}

public native String helloJNI();

public native int add(int a, int b);
}


4. 헤더파일 생성.
프로젝트 디렉토리에서 「javah」를 커맨드로 헤더파일「jni/jnitest.h」을 생성.

생성된 「jnitest.h」파일

/* DO NOT EDIT THIS FILE - it is machine generated */
#include<jni.h>
/* Header for class com_babukuma_android_test_jni_Main */

#ifndef _Included_com_babukuma_android_test_jni_Main
#define _Included_com_babukuma_android_test_jni_Main
#ifdef __cplusplus
extern"C" {
#endif
/*
* Class: com_babukuma_android_test_jni_Main
* Method: helloJNI
* Signature: ()Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_com_babukuma_android_test_jni_Main_helloJNI
(JNIEnv *, jobject);

/*
* Class: com_babukuma_android_test_jni_Main
* Method: add
* Signature: (II)I
*/
JNIEXPORT jint JNICALL Java_com_babukuma_android_test_jni_Main_add
(JNIEnv *, jobject, jint, jint);

#ifdef __cplusplus
}
#endif
#endif


5. C소스 작성
「jni」디렉토리에 「jnitest.c」파일을 작성한다.

작성한 「jnitest.c」파일

#include<jni.h>
#include"jnitest.h"

JNIEXPORT jstring JNICALL Java_com_babukuma_android_test_jni_Main_helloJNI(
JNIEnv *env, jobject thisObj) {
jstring result = (*env)->NewStringUTF(env, "Hello JNI !");
return result;
}

JNIEXPORT jint JNICALL Java_com_babukuma_android_test_jni_Main_add(JNIEnv *env,
jobject thisObj, jint a, jint b) {
jint result = a + b;
return result;
}


6. 「Android.mk」파일을 작성.
「jni」디렉토리에 「Android.mk」파일을 작성한다.
작성법은 「$NDK/docs/ANDROID-MK.TXT」을 참조.

작성한「Android.mk」파일

# Android.mkLOCAL_PATH := $(call my-dir)

include$(CLEAR_VARS)

LOCAL_MODULE := jnitest
LOCAL_SRC_FILES := jnitest.c

include$(BUILD_SHARED_LIBRARY)


7. C소스 빌드
빌드를 하기위해서는 프로젝트의 PATH가 「$NDK/apps/<프로젝트명>」여야할 필요가 있으므로 링크를 작성하였다.

$NDK디렉토리에서 「make APP=jnitest」로 빌드.
여기서 「jnitest」는 「$NDK/apps/」밑의 프로젝트폴더명이 된다.

Eclipse를 새로고침하면 「libs/armeabi/libjnitest.so」파일이 생성되어있는 것을 알 수 있다.


8. Java소스를 수정하여 실행해봄.
수정후의 「Main.java」파일

package com.babukuma.android.test.jni;

import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;

public class Main extends Activity {
static {
System.loadLibrary("jnitest");
}

/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);

// call helloJNI()
TextView result1 = (TextView) findViewById(R.id.text_result_1);
result1.setText(helloJNI());

// call add(1, 2)
TextView result2 = (TextView) findViewById(R.id.text_result_2);
result2.setText("1 + 2 = " + add(1, 2));
}

public native String helloJNI();

public native int add(int a, int b);
}


수정후 실행해보면 Native메소드가 문제없이 호출된 것을 알 수 있다.