今回のエンジニアブログを担当する村田です。
前回の「Cocos2d-xにおけるJNI(その1)」の続きです。
今回は、『C/C++ から Java(Android) を呼び出す時』です。
Android端末に設定されている言語情報をC/C++側へ返すプログラムを作成します。
使用したCocos2d-xのバージョン:cocos2d-x-2.1.5
1. Javaプログラムの定義
C/C++側から呼び出すJavaプログラムを定義します。
今回使用するJavaプログラムは
- パッケージ名「com.example.testjni」
- クラス名 「TestJniActivity」
と付けます。
TestJniActivity.java
package com.example.testjni; : (略) : public class TestJniActivity extends Cocos2dxActivity { private static final String TAG = TestJniActivity.class.getSimpleName(); @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); : 必要な処理を記述 : } // Cocos2d-xでビルドするとlibgame.soが生成されます // libgame.soを読み込みます static { System.loadLibrary("game"); } /** * 言語情報を取得 * @return 言語情報 */ public static String getLanguage() { // 言語情報を返す return Locale.getDefault().getLanguage(); } }
2. nativeプログラムの実装
今回は、JNI用のファイルを作成して実装します。
DeviceJni.h
#ifndef __DEVICE_JNI_H__ #define __DEVICE_JNI_H__ #include <jni.h> extern "C" { // 言語情報を取得 extern const char* getLanguageJni(); } #endif // __DEVICE_JNI_H__
DeviceJni.cpp
#include "DeviceJni.h" #include "cocos2d.h" #include "platform/android/jni/JniHelper.h" extern "C" { // 言語情報を取得 const char* getLanguageJni() { JniMethodInfo methodInfo; if (! JniHelper::getStaticMethodInfo(methodInfo, "com/example/testjni/TestJniActivity", "getLanguage", "()Ljava/lang/String;")) { LOGD("Failed to find static method of getLanguageJni"); return ""; } // Javaのプログラムを呼び出す jobject objResult = methodInfo.env->CallStaticObjectMethod(methodInfo.classID, methodInfo.methodID); // jstringをstd::stringに変換 std::string ret = JniHelper::jstring2string((jstring)objResult); // 解放処理 methodInfo.env->DeleteLocalRef(objResult); methodInfo.env->DeleteLocalRef(methodInfo.classID); return ret.c_str(); } }
ポイント
- Cocos2d-xには、JNIを簡単に扱うためにJniHelperクラスが存在します。
-
staticメソッドを呼び出す場合は、JniHelper::getStaticMethodInfo関数を使用します。
インスタンスメソッドを呼び出す場合は、JniHelper::getMethodInfo関数を使用します。- 第1引数:JniMethodInfo構造体を渡します。
- 第2引数:パッケージ名を含んだ形でクラスを指定します。
- 第3引数:メソッド名を指定します。
- 第4引数:メソッドのシグニチャを指定します。
※ シグニチャについては後述
処理が正常に終了すると、JniMethodInfo構造体に必要なデータが格納されます。
- Javaで実装されたメソッドを実行する時は、状況に応じた関数を呼び出します。
staticメソッド インスタンスメソッド 戻り値なし CallStaticVoidMethod CallVoidMethod 戻り値あり
オブジェクト型CallStaticObjectMethod CallObjectMethod 戻り値あり
プリミティブ型CallStaticタイプMethod
例:CallStaticIntMethodCallタイプMethod
例:CallDoubleMethod - 文字列を取得した場合は、jstringからstringに変換する必要があります。
JniHelperクラスには、この変換を簡単に行ってくれるjstring2string関数があります。
あとは、この関数をC/C++から呼び出すことで、Android端末に設定されている言語情報を取得する事ができます。
シグニチャは下記のとおりになっており、最初は取っ付きにくい部分です。
Javaの型 | シグニチャ |
---|---|
boolean | Z |
byte | B |
char | C |
short | S |
int | I |
long | J |
float | F |
double | D |
クラス | Lパッケージを含めたフルパス; 例)String型 Ljava/lang/String; |
配列 | [シグニチャ 例)double[] → [D |
2回に渡りJNIを説明してきました。
JNIを利用することでAndroidネイティブの機能を呼び出す事ができるため、アプリ内課金なども実現可能となります。
実現できる事の幅が広がりますので、覚えておいて損は無いかと思います。