
Cocos2d-x AndroidでAndroidからCocos2d-xにコールバックする方法
2017.02.09

はじめまして。SDKエンジニアの市村です。
Cocos2d-x Android向けのSDKでは、Cocos2d-xプラグインからJava関数を呼び出し、実際の広告表示等はAndroid側で行う仕組みになっています。
Cocos2d-x(C++)とAndroid(Java)はJniHelperとextern Cを利用する事で双方向通信が可能となります。
今回は、Android(Java)からCocos2d-xにコールバックする際に若干工夫が必要だったので、それについて書きたいと思います。
何に手間取ったか
通常、Androidからコールバックする為には呼び出し元のクラスを知っている必要がありますが、C++、Javaと言語の違いもあり、どうやってCocos2d-x(C++)側のクラスをAndroid(Java)に渡せば良いのか?? 色々試行錯誤しました。
解決方法
結論、AndroidからCocos2d-xにコールバックするためにはJNIを利用します。 まず、Cocos2d-xからAndroidを呼び出すところから説明したいと思います。
Cocos2d-xからAndroidを呼び出す
Cocos2d-xからAndroidを呼び出す為には、JniHelperを利用します。
Androidに以下のようなsetCocosListener関数を用意して、Cocos2d-xからJniHelperを使って呼び出してみます。
2番目の引数 "Javaのパッケージ名" は呼び出すクラス名をパッケージ名を含めてxx.xxxx.xxのような形で文字列で渡します。
3番目の引数の"()V"という文字列はメソッドシグネチャで"(引数)戻り値"の形になっています。上記は「戻り値、引数がvoid型の関数を呼び出す」という意味になります。
Androidの方で用意したsetCocosListenerという関数は、戻り値と引数がvoid型なので、このような書き方になります。
このsetCocosListenerという関数の型が"()V"である事がポイントで、通常コールバックする際には、通知先のクラスインスタンスを保持している必要がありますが、AndroidからCocos2d-xへのコールバックの場合は、通知先のクラスをAndroidに渡すのではなく、後ほど記載するJNIという仕組みを使ってコールバックをします。
AndroidからCocos2d-xを呼び出す
AndroidからCocos2d-xを呼び出す際にはJNIの仕組みを使います。
JNIの命名規則に従ってJava_[パッケージ名][呼び出し元クラス名][メソッド名]
という形でCocos2d-x側にJava_xxx_xxx_CocosBridge_cocosOnMessage
関数を記載します。
extern Cを記載することによって、コンパイラにC言語として解釈されます。 C言語の関数はJNIを使ってAndroid(Java)から呼び出す事ができます。
JNIの仕組みにより、Androidで作成したCocosBridgeクラスのCocosBridge.cocosOnMessage(message)
関数が呼び出されると、その先でCocos2d-x側のJava_xxx_xxx_CocosBridge_cocosOnMessage
が呼び出されます。
Android側では、コールバックを行いたいタイミングで以下のような呼び出しを行い、Cocos2d-x側にメッセージが通知されます。
通知する情報はString型でやりとりしていて、 JSONやクエリを扱えるようにしてあります。
Cocos2d-x側でデリゲートを作成する
上記でCocos2d-xとAndroidの双方向通信は可能になりましたが、SDKを導入する際に使いやすいように、デリゲートを作成します。
デリゲートクラスと関数を宣言します。
SDKを利用する際にはCocos2d-xのクラスに、上記のデリゲートクラス(HogePluginDelegate)を継承して、デリゲートクラスの関数(onHogePluginMethod)を追加します。
デリゲートのインスタンスmDelegateには、HogePluginDelegateを継承したHelloWorldクラスインスタンスを設定しておきます。
先程作成したJNIの関数で、デリゲート関数を呼び出します。
以上により、Androidからのコールバックで、Cocos2d-xクラスにメッセージが通知されるようになりました。
まとめ
今回の実装のポイントは、Android側がC++側のデリゲートクラスのインスタンスを持っていなくても、JNIを使えばC++関数が呼び出せるところかな〜、と思います。
私は「コールバック = 呼び出し元を知っていなければならない」という先入観があったので苦戦しましたが、やり方さえ知っていれば意外と簡単にコールバックは実装できますね。