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

ほげほげ(仮)

仮死状態

Cocos2d-xからAndroidの処理を呼び出す

Android Cocos2d-x

Cocos2d-xのC++からAndroidJavaの処理を呼び出す方法です。JNIを使用します。

Objective-Cの場合と違って結構面倒です。

ここの連携はEclipseで書いたほうが良いかもです。

関連

環境

  • Cocos2d-x 3.2

Androidの処理

Cocos2d-xのプロジェクトを作った段階でorg.cocos2dx.cpp.AppActivityというクラスが用意されているのでそこに処理を書きます。

public class AppActivity extends Cocos2dxActivity {
    public static void executeJava() {
        // なんか処理
    }
}

注意としてはここでのJavaの処理はUIスレッドで動いていません。ダイアログ出す等の処理をする場合は注意が必要です。一番下の補足に書きました。

C++からJNIでJavaの処理を呼び出す処理

実際にC++からJNIを経由してJavaの処理を呼び出すための処理を作ります。

Classes/platform/android/jniっていうディレクトリを作ってその中にファイルを作りました。

NativeControllerJni.h

#ifndef __NATIVE_CONTROLLER_JNI_H_
#define __NATIVE_CONTROLLER_JNI_H_

extern "C" {
    extern void executeJni();
}

#endif //__NATIVE_CONTROLLER_JNI_H_

NativeControllerJni.cpp

このファイルはXcodeでビルドターゲットには含めないように注意してください。

#include "NativeControllerJni.h"
#include "platform/android/jni/JniHelper.h"

extern "C" {
    void executeJni()
    {
        cocos2d::JniMethodInfo t;

        if (cocos2d::JniHelper::getStaticMethodInfo(t, "org.cocos2dx.cpp.AppActivity", "executeJava", "()V")) {
            t.env->CallStaticVoidMethod(t.classID, t.methodID);
            t.env->DeleteLocalRef(t.classID);
        }
    }
}

Cocos2d-xに用意されているJniHelperを使ってJavaを呼び出しています。

呼び出したいクラス名、メソッド名、引数タイプを指定して呼び出しています。

このファイルをjni/Android.mkに追加するのを忘れずに。

C++Javaとの橋渡しするクラス

C++からAndroidJavaを呼ぶための橋渡しをするクラスです。Objective-Cの方にも書きましたが、iOSも共通して使いたいのでiOS/Androidの処理を橋渡しするクラスを作っておきます。

名前空間platformにしてあります。

NativeBridge.h

ヘッダーファイルはClasses/platform/NativeBridge.hに入れました。

#ifndef __NATIVE_CONTROLLER_H__
#define __NATIVE_CONTROLLER_H__

namespace platform
{

class NativeBridge
{
public:
    static void executeNative();
};

}

#endif //__NATIVE_CONTROLLER_H__

NativeBridge.cpp

実装ファイルはClasses/platform/android/NativeBridge.cppに入れました。

このファイルはXcodeでビルドターゲットには含めないように注意してください。

#include "platform/NativeBridge.h"
#include "jni/NativeControllerJni.h"

namespace platform
{

void NativeBridge::executeNative()
{
    executeJni();
}

}

NativeControllerJni.hをincludeして、先ほど作ったJNIの処理を呼び出しています。

このファイルをjni/Android.mkに追加するのを忘れずに。

C++から呼び出す

ここまで出来たら、C++から呼び出すだけです。

#include "platform/NativeBridge.h"

...

platform::NativeBridge::executeNative();

ディレクトリ構成

出来上がったディレクトリ構成はこんな感じです。

AndroidからC++の呼び出しとiOSの対応も含めての構成です。

Classes
├── AppDelegate.cpp
├── AppDelegate.h
├── HelloWorldScene.cpp
├── HelloWorldScene.h
└── platform
    ├── NativeBridge.h
    ├── android
    │   ├── NativeBridge.cpp
    │   └── jni
    │       ├── NativeControllerJni.cpp
    │       ├── NativeControllerJni.h
    │       ├── org_cocos2dx_cpp_AppActivity.cpp
    │       └── org_cocos2dx_cpp_AppActivity.h
    └── ios
        ├── NativeBridge.mm
        └── objc
            ├── NativeController_objc.h
            └── NativeController_objc.mm

補足: UIスレッド

JNIからAndroidの処理を呼び出した場合はUIスレッドではないのでダイアログを出したりする処理がそのままでは出来ません。

用意されているCocos2dxActivityCocos2dxHelperを使ってこの辺はうまく解決できます。

Cocos2dxHelper.getActivity().runOnUiThread(new Runnable() {
    @Override
    public void run() {
        AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
        builder.setTitle("hoge");
        builder.setMessage("foo");
        builder.setPositiveButton("OK", null);
        builder.create().show();
    }
});

Cocos2dxHelper#getActivityでActivityのインスタンスを取得しています。そのインスタンスからrunOnUiThreadを使って、UIスレッドでの実行を行っています。

またCocos2dxActivity#getContextでもActivityを取得できます。

Cocos2dxActivityCocos2dxHelperは全然コード量ないので読むのに苦労しないはずなので使えるものは使っていきましょう。

参考: JNI資料

http://docs.oracle.com/javase/jp/7/technotes/guides/jni/spec/jniTOC.html