2010年3月11日木曜日

[Android] 「Android NDK r3」を使ってみた。

今回リリースされた「Android NDK r3」を使ってみた。

環境: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メソッドが問題なく呼ばれた。