サンプル: hello-jni

このサンプルは、NDK を使用して開発された hello-jni という小さな C / C++ アプリを紹介します。このサンプルは、android-mk ブランチ内の ndk-samples リポジトリの hello-jni ディレクトリにあります。

Android.mk

次の 2 行は、ネイティブ ソースファイルの名前と、ビルドする共有ライブラリの名前を指定しています。ビルドシステムにより lib プレフィックスと .so 拡張子が付加されるため、ビルドされるライブラリの完全な名前は libhello-jni.so になります。

LOCAL_SRC_FILES := hello-jni.c
LOCAL_MODULE    := hello-jni

Android.mk ファイルの機能と使用方法の詳細については、Android.mk をご覧ください。

Application.mk

次の行は、ビルド対象の CPU とアーキテクチャをビルドシステムに指定しています。この例では、サポートされているすべてのアーキテクチャ向けにビルドを行います。

APP_ABI := all

Application.mk ファイルとその使用方法の詳細については、Application.mk をご覧ください。

Java サイドの実装

helloJNI.java ファイルは hellojni/src/com/example/hellojni/ にあります。このプログラムは、ネイティブ サイドから文字列を取得する関数を呼び出し、その文字列を画面に表示します。

ソースコードには、NDK ユーザーにとって特に重要な 3 つの行があります。 ここでは、それらを記述されている順ではなく、使用される順に説明します。

この関数呼び出しは、アプリの起動時に .so ファイルを読み込みます。

Kotlin

System.loadLibrary("hello-jni")

Java

System.loadLibrary("hello-jni");

このメソッド宣言内の native キーワードは、関数が共有ライブラリ内にある(つまり、ネイティブ サイドに実装されている)ことを仮想マシンに伝えます。

Kotlin

external fun stringFromJNI(): String

Java

public native String stringFromJNI();

Android フレームワークは、前の手順で読み込まれ宣言された関数を呼び出し、文字列を画面に表示します。

Kotlin

tv.text = stringFromJNI()

Java

tv.setText( stringFromJNI() );

C サイドの実装

hello-jni.c ファイルは hello-jni/jni/ にあります。これには Java サイドがリクエストした文字列を返す関数が含まれています。関数の宣言は次のとおりです。

JNIEXPORT jstring JNICALL
Java_com_example_hellojni_HelloJni_stringFromJNI( JNIEnv* env,
                                                  jobject thiz )

この宣言は、Java のソースコード内で宣言されているネイティブ関数に対応しています。戻り値の型である jstring は、Java Native Interface Specification で定義されているデータ型です。実際は文字列ではなく、Java 文字列へのポインタです。

jstring の後に関数名を記述します。関数名は、Java の関数名とその関数を含むファイルへのパスに基づいており、次のルールに従って記述します。

  • 先頭に Java_ を付加する。
  • ソース ディレクトリの最上位からの相対ファイルパスを記述する。
  • スラッシュの代わりにアンダースコアを使用する。
  • ファイル拡張子(.java)は省略する。
  • 最後のアンダースコアの後に関数名を付加する。

上記のルールにより、このサンプルで使用される関数名は Java_com_example_hellojni_HelloJni_stringFromJNI になります。この名前は、hellojni/src/com/example/hellojni/HelloJni.java にある stringFromJNI() という Java 関数を指しています。

JNIEnv* は VM へのポインタで、jobject は Java サイドから渡される暗黙的な this オブジェクトへのポインタです。

次の行は、VM API (*env) を呼び出して、この API に戻り値(Java サイドの関数がリクエストした文字列)を渡します。

return (*env)->NewStringUTF(env, "Hello from JNI !
Compiled with ABI " ABI ".");