二つ目のAndroid NDKアプリケーション

目的

最初のAndroid NDKアプリケーションではネイティブアプリケーションを作ってそれのデバッグを実施しましたが、今度は通常のAndroid NDKアプリケーションを作成します。

プロジェクトの構築

基本的にはAndroid SDKのアプリケーションを作成した後に、追加でネイティブライブラリを作成して二つを合わせてビルドする様な手順となります。まずはAndroid SDKのプロジェクトをeclipseで作成します。最初のAndroidアプリケーションで説明したこととほとんど変わりませんが、注意事項としてApplication.mkでそのディレクトリを指定する必要があるということです。Application.mkでディレクトリを指定するのは手間ですので、この例ではApplication.mkを置いた配下のディレクトリにprojectディレクトリを作成してそこにプロジェクトを配置します。

ネイティブライブラリ作成のためのプロジェクトについては最初のAndroid NDKアプリケーションで説明した通りですので、ここでは特に説明しません。

設定の仕方

基本的にAndroidでのネイティブ実行コードへのアクセスは通常のJNIと変わりません。つまり、以下のような手順で行われます。

  1. 起動したいネイティブ関数をJAVA側で宣言。
  2. JAVA側で宣言したソースをCヘッダ生成ツールに入力。
  3. 出力されたCヘッダを元に実装を作成。
  4. ネイティブライブラリをビルド
  5. 作成されたネイティブライブラリをロードする処理をJAVA側に追加
  6. ネイティブ関数をJAVA側から起動

次にそれぞれの手順を見ていきます。

起動したいネイティブ関数をJAVA側で宣言

以下の様にstatic nativeで関数(testMethod)を宣言します。

public class SecondNDKApplication extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        System.loadLibrary("SecondNDKApplication");
        final String result = testMethod();
        Log.e("SecondNDKApplication", result);
    }
    
    private static native String testMethod();
}
JAVA側で宣言したソースをCヘッダ生成ツールに入力。

JDKにjavahというJNI向けのツールがあります。使い方としてはjavah -classpath クラスパス -d 出力ディレクトリ 対象クラス(完全修飾で)でヘッダが出力されます。以下が今回出力されたヘッダです。

/* DO NOT EDIT THIS FILE - it is machine generated */
#include 
/* Header for class com_suddenAngerSystem_SecondNDKApplication */

#ifndef _Included_com_suddenAngerSystem_SecondNDKApplication
#define _Included_com_suddenAngerSystem_SecondNDKApplication
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     com_suddenAngerSystem_SecondNDKApplication
 * Method:    testMethod
 * Signature: ()Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_com_suddenAngerSystem_SecondNDKApplication_testMethod
  (JNIEnv *, jclass);

#ifdef __cplusplus
}
#endif
#endif
            
出力されたCヘッダを元に実装を作成
ネイティブライブラリをビルド

この二つは最初のAndroid NDKアプリケーションで説明した通りですので、特に説明しません。

作成されたネイティブライブラリをロードする処理をJAVA側に追加
ネイティブ関数をJAVA側から起動

既にソースは記載してしまいましたが、以下の様にloadLibraryでライブラリをロードして、その後ネイティブ関数を起動する。注意点としてはloadLibraryはネイティブ関数起動する前に一度だけ起動する必要があると言うことと、特定の位置にあるライブラリしかロードできないということになります。Android NDKの場合は一つのapkにまとめるため、後者を気にする必要はありませんが、前者についてはstaticイニシャライザで実施するなど考慮が必要です。

public class SecondNDKApplication extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        System.loadLibrary("SecondNDKApplication");
        final String result = testMethod();
        Log.e("SecondNDKApplication", result);
    }
    
    private static native String testMethod();
}

実行・デバッグ

実行・デバッグについてはAndroid SDKで作成した通常のアプリケーションと特に変わりません。ただし、ネイティブ側についての確認は別途実施する必要があります。ネイティブ側、JAVA側を同時にデバッガで確認できるようにとも考えましたが、今のところまともな解決策が思い当たりません。