読者です 読者をやめる 読者になる 読者になる

WonderPlanet DEVELOPER BLOG

ワンダープラネットの開発者ブログです。モバイルゲーム開発情報を発信。

Cocos2d-xにおけるJNI(その2)

今回のエンジニアブログを担当する村田です。

前回の「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メソッドインスタンスメソッド
    戻り値なしCallStaticVoidMethodCallVoidMethod
    戻り値あり
    オブジェクト型
    CallStaticObjectMethodCallObjectMethod
    戻り値あり
    プリミティブ型
    CallStaticタイプMethod
    例:CallStaticIntMethod
    CallタイプMethod
    例:CallDoubleMethod
  • 文字列を取得した場合は、jstringからstringに変換する必要があります。
    JniHelperクラスには、この変換を簡単に行ってくれるjstring2string関数があります。

あとは、この関数をC/C++から呼び出すことで、Android端末に設定されている言語情報を取得する事ができます。

シグニチャは下記のとおりになっており、最初は取っ付きにくい部分です。

Javaの型シグニチャ
booleanZ
byteB
charC
shortS
intI
longJ
floatF
doubleD
クラスLパッケージを含めたフルパス;
例)String型 Ljava/lang/String;
配列[シグニチャ
例)double[] → [D



2回に渡りJNIを説明してきました。

JNIを利用することでAndroidネイティブの機能を呼び出す事ができるため、アプリ内課金なども実現可能となります。

実現できる事の幅が広がりますので、覚えておいて損は無いかと思います。