この投稿はモバイルファクトリー 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さんです!