JNIを使用するには、「native」というキーワードを持つメソッドをクラス内に宣言します。今回は、以下の2つを宣言しました。
private native String hello();
private native void effect(int fireLevel, int width, int height, int[] image, int[] pallet, int[] seedparam, int[] color);
1つ目はお約束のHello Worldです。2つ目は、実際の炎のエフェクトの処理を行わせるJNIメソッドです。
nativeメソッドの実際の処理が実装されているネイティブライブラリをSystem.loadLibrary(String)でロードする必要があります。
static { System.loadLibrary("FireEffect"); }
今回は、static節で読み込むことにしました。ライブラリの名前は「FireEffect」とします。
今回の高速化は、Java側にピクセルデータを持たせ、JNI側でピクセル操作を行う、という仕組みになっています。実は、JNI側でピクセルデータを持たせるようにすれば、もっと高速化できる見込みなのですが、以下の理由で実現できませんでした。
static { System.loadLibrary("FireEffect"); }
結果として、JNI_OnLoad()が何度も呼び出されてしまうため、実は「JNI_OnLoad()やJNI_OnUnload()でメモリやリソースを管理する」という方法はAndroidでは破たんします。
Dalvik VMのクラスローダが特殊な仕組みになっているのが原因だと思いますが、原因は分かっていません。
どちらも、JavaやJNIの仕様に準拠してない動作です。特に、「クラスが何度もロードされる」というのは、JNIを使わない通常のAndroidアプリでも影響を受ける動作なので、頭の片隅に置いておくとよいでしょう。
ここまで完了したら、コンパイルされたクラスファイルに対してJDK付属のjavahコマンドを使用します。
javah com.example.android.livewallpaper2.FireEffect
カレントディレクトリにcom_example_android_livewallpaper2_FireEffect.hというヘッダファイルが作成されるので、これをベースにC/C++の実装を行います。
次はNDK側の作業です。
2010年3月17日現在のNDKの指針版はr3ですが、2月28日の原稿執筆時時点での最新版は、1.6r1(r2)でした。各プラットフォーム向けのバイナリが提供されていて、今回のサンプルでは、1.6r1のWindows版を使用しました。
ダウンロードしたzipファイルを任意のフォルダに展開します。今回は、C:\ android-ndk-1.6_r1(以降、「NDKホームディレクトリ」)に展開したものとして話を進めます。
Windows版のAndroid NDKを使用するには、別途Cygwinが必要です。Cygwinはデフォルトのインストールオプションに加え、makeが必要です。
Cygwinを起動し、NDKホームディレクトリに移動し、以下のコマンドを入力します。
bash ./build/host-setup.sh
これで、NDKを使用する準備が整いました。
Android NDKのビルド対象は、NDKホームディレクトリ以下の「apps」ディレクトリです。ここにADTで作成したプロジェクト(または、そのシンボリックリンク)があると非常に便利です。
Windows Vista以降であれば、mklinkコマンド(またはエクスプローラの機能)を、Windows XPであれば「Windows Server 2003 Resource Kit Tools」などに含まれるlinkdを使用してシンボリックリンク(または、ジャンクション)を作成するとよいでしょう。
NDKを使用するには、「Application.mk」「Android.mk」という名前の設定ファイルを用意する必要があります。
NDKホームディレクトリ + apps + <プロジェクトディレクトリ> + Application.mk + jni + Android.mk
1つはプロジェクトディレクトリ直下、もう1つはプロジェクトディレクトリ配下に作成した「jni」ディレクトリ内です。
Application.mkはアプリケーションの定義を行います。
定義 | 説明 |
---|---|
APP_MODULES | モジュール名を指定(必須) |
APP_PROJECT_PATH | プロジェクトパスを指定(必須) |
APP_OPTIM | debugかreleaseを指定(releaseがデフォルト) |
APP_CFLAGS | Cソースコンパイルフラグを指定 |
APP_CXXFLAGS | C++ソースコンパイルフラグを指定 |
APP_CPPFLAGS | CとC++で共通のコンパイルフラグを指定 |
APP_BUILD_SCRIPT | Android.mkのパスを指定($( APP_PROJECT_PATH)/jni/Android.mkがデフォルト) |
表4 Application.mkの定義 |
今回は、以下のように定義しています。
APP_PROJECT_PATH := $(call my-dir) APP_MODULES := FireEffect
APP_MODULESは、Javaの「System.loadLibrary(String)」と合わせる必要があります。APP_PROJECT_PATHの$(call my-dir)は、NDKが提供するマクロで、この場合は、そのファイルの存在する場所に置き換えられます。次ページでは、「Android.mk」にファイルやライブラリの情報を定義し、コンパイルやパッケージングを行ってみましょう。最後に、JNIとNDKの注意点もお話しします。
NDKでは、$(call my-dir)のように使用できるマクロが、my-dir以外にも用意されています。
jni/foo/Android.mk jni/foo/lib1/Android.mk jni/foo/lib2/Android.mk
jni/foo/Android.mkに以下の行が含まれていると、「jni/foo/lib1/Android.mk」「jni/foo/lib2/Android.mk」も自動的にビルドに含まれます。
include $(call all-subdir-makefiles)
この定義は、サブディレクトリのサブディレクトリまでは探さないことに注意してください。
Copyright © ITmedia, Inc. All Rights Reserved.