Android
cocos2d-x
JNI
More than 1 year has passed since last update.

この投稿はモバイルファクトリー Advent Calenaderの20日目のものです。

この記事ではcocos2d-x 3系で、何かと面倒で忘れがちなJNI記法・使用例を記述していきます。

JNIとは

Java Native Interface (JNI) は、Javaプラットフォームにおいて、Javaで記述されたプログラムと、他の言語(たとえばCやC++など)で書かれた、実際のCPUの上で動作するコード(ネイティブコード)とを連携するためのインタフェース仕様である。

wikipediaより引用

メソッドシグネチャ

シグネチャとは

引数の型、引数の数、メソッド名の組み合わせを組み合わせをシグネチャ(シグニチャ)と呼びます。

型対応表

java 型のシグネチャ
void V
byte B
boolean Z
char C
short S
int I
long J
double D
float F
String Ljava/lang/String;
その他javaクラス L + パッケージ/クラス名 + ;

メソッドシグネチャ例

c++ シグネチャ例
void hoge(); "()V"
void hoge(int a); "(I)V"
int hoge(int a) "(I)I"
int hoge(int a, int b) "(II)I"
long hoge(short a, double b) "(SD)J"
boolean hoge(String a); "(Ljava/lang/String;)Z"
boolean hoge(int a[], char b, byte c[] ) "([ab[c)Z"

記法

"(引数)返り値"

  • 引数がない場合未指定
  • 引数を複数持たせる場合、連続してシグネチャを記述する
  • 配列はシグネチャの前に[を記述する

より詳細な情報はOracleのJNI仕様などを見ると良いかと思います。

JNIの記述例は下記サイトが解りやすくまとまっています。
JNIサンプル集 : 技術者のたまごブログ

cocos2d::JniHelper

cocos2d::JniHelperを利用した記述例を記載していきます。

記法

JniHelperのドキュメントが見当たらなかったのですが、基本的にはJNIの関数なので気にしないことにします。

cocos2d::JniMethodInfo methodInfo;
if (cocos2d::JniHelper::getStaticMethodInfo(methodInfo, "名前空間/クラス名", "関数名", "メソッドシグネチャ")) 
{
    // メソッド呼び出し
     methodInfo.env->CallxxxMethod...

    // 開放処理
    methodInfo.env->DeleteLocalRef(methodInfo.classID);
}

インスタンスメソッドも呼べると思うのですが、どうもうまく叩けず...
今回はjava側がstaticメソッドとしたサンプルを作成します。

cocos2d::JniHelper使用例

  • void hoge();
cocos2d::JniMethodInfo methodInfo;
if (cocos2d::JniHelper::getStaticMethodInfo(methodInfo, "JAVA_CLASS_NAME", "hoge", "()V")) 
{
    methodInfo.env->CallStaticVoidMethod(methodInfo.classID, methodInfo.methodID);
    methodInfo.env->DeleteLocalRef(methodInfo.classID);
}
  • void hoge(int a, int b);
cocos2d::JniMethodInfo methodInfo;
if (cocos2d::JniHelper::getStaticMethodInfo(methodInfo, "JAVA_CLASS_NAME", "hoge", "(II)V")) 
{
    methodInfo.env->CallStaticVoidMethod(methodInfo.classID, methodInfo.methodID, 1, 2);
    methodInfo.env->DeleteLocalRef(methodInfo.classID);
}
  • String hoge();
std::string ret;

cocos2d::JniMethodInfo methodInfo;
if (cocos2d::JniHelper::getStaticMethodInfo(methodInfo, "JAVA_CLASS_NAME", "hoge", "()Ljava/lang/String;")) 
{
    jobject objResult = methodInfo.env->CallStaticObjectMethod(methodInfo.classID, methodInfo.methodID);
    ret = cocos2d::JniHelper::jstring2string((jstring)objResult); // jstringをstd::stringに変換
    methodInfo.env->DeleteLocalRef(objResult);
    methodInfo.env->DeleteLocalRef(methodInfo.classID);
}

return ret;

実際には下記のようにプラットフォーム別に処理を分けて書くと思います。

#if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)
    // jni
#elif(CC_TARGET_PLATFORM == CC_PLATFORM_IOS)
    // obj-c++
#endif

他プラットフォーム

おわりに

JNI周りはエラーが追いづらいので、ある程度まではコピペ生活が出来ると幸せかなと思っています。
今後も使用例は更新していきます。(サンプル集というには少ないので...

明日はmorigamixさんです!