夏真っ盛り、というかもう終盤ですね。
毎年8月よりも9月の方が暑い気がします。
こんにちは、プログラマのgmatsuです。
ドラクエ11は全クリし、今はリネレボやってます。
以前リネージュ1をプレイしていましたので、懐かしさも相まってとても楽しいです。
9月はメトロイド、10月は女神転生。
ああ、忙しい…。
前回に引き続き、今回もNIFTY Cloud mobile backendの導入についてのお話となります。
以前紹介したiOS編はこちらになります。
iOS版の実装が終わっている事が今回のお話での前提となります。
Android版の紹介ではありますが、前回で既に実装されている物もありますのでお気をつけ下さい。
cocos2d-xバージョン
v3.15.1
NCMBバージョン
Android
v2.3.0
導入手順にあたっての前提
前回のiOS版実装が完了済み
導入手順
Android
1.NCMB用Androidライブラリの作成と設置
iOSとAndroidのネイティブ処理に必要なファイルがあっちこっちに分かれてしまう事がcocosを使っていて多々ありました。
Android用のSDKをproj.android-studio以下に設置したりするのが嫌だったので、Androidライブラリとして1つにまとめてしまう事にしました。
これであればClassesの中にiOS版とまとめて設置できるので精神衛生的にも非常によろしかったです。
そもそもAndroidのライブラリを作ったことがなかったので調べて所、AndroidStudioで作成とのことでした。
ただ、こんな作り方で良かったのかは自信がありませんので変だなと思った方はコメントを頂ければ幸いです。
自分が行った手順は次の通りです。
- ライブラリ作成用のプロジェクトを作成
- ライブラリを作成
- ライブラリを作成用プロジェクトから抜き出してcocos2d-xのプロジェクトに設置
- 各種設定ファイルにライブラリを使用する為の記述を追加
とりあえず手順通りやっていきたいと思います。
1.ライブラリ作成用のプロジェクトを作成
ここからの作業はAndroidStudioで行います。
プロジェクトを作るだけですので、特に難しい事は無いと思います。
私は「AndroidLibrary」という名前にしました。
2.ライブラリを作成
次は1.で作成したプロジェクトにライブラリを作成します。
作成のウィンドウは以下の手順で出せます。
File > New > New Module…
すると次のようなウィンドウが出ます。
作成する物の種類を選択します。
今回は「Android Library」を選択して下さい。
次はライブラリの名前等を決めて行きます。
今回は「NcmbManager」としています。
Package nameの変更は右の方にある「Edit」から行えます。
後は「Finish」ボタン押下でライブラリが作成されます。
3.ライブラリを作成用プロジェクトから抜き出してcocos2d-xのプロジェクトに設置
作成が終わったら次はcocosのプロジェクトに設置を行います。
コードは設置後に書いて行きますのでまずはちゃちゃっと置いてしまいましょう。
作成後のプロジェクトには次のようにライブラリが設置されています。
この中身を全て、cocosのプロジェクトへと移動してしまいましょう。
Classes/External/Ncmb/Android/
その後、
Classes/External/Ncmb/Android/src/main/Androidmanifest.xml
を
Classes/External/Ncmb/Android/
に移動。
Classes/External/Ncmb/Android/src/test/java/com/example/gmatsu/ncmbmanager/ExampleUnitTest.java
の.javaファイルを
NcmbManager.java
に変更。
Classes/External/Ncmb/Android/src/test/java/com
を
Classes/External/Ncmb/Android/src/
に移動します。
Classes/External/Ncmb/Android/src/
にある、com/以外のディレクトリは消してしまってください。
また、
Classes/External/Ncmb/Android/
に
NcmbManager.cpp
を作成。
Classes/External/Ncmb/Android/libs/
にはNCMBのAndroidSDKを入れておきましょう。
すると次のようなディレクトリ構造になるはずです。
ここまでで設置が完了です。
文にすると結構長い…。
4.各種設定ファイルにライブラリを使用する為の記述を追加
後は設定の記述をしてしまえばライブラリの準備は完了です。
Classes/External/Ncmb/Android/build.gradle
apply plugin: 'com.android.library' android { compileSdkVersion 22 buildToolsVersion "25.0.0" defaultConfig { minSdkVersion 10 targetSdkVersion PROP_TARGET_SDK_VERSION versionCode 1 versionName "1.0" } sourceSets.main { java.srcDir "src" jniLibs.srcDir "libs" manifest.srcFile "AndroidManifest.xml" } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' if (project.hasProperty("RELEASE_STORE_FILE")) { signingConfig signingConfigs.release } } } } dependencies { compile project(':libcocos2dx') compile 'com.google.code.gson:gson:2.3.1' compile files('libs/NCMB.jar') }
java.srcDirにjavaファイルのルートとなるディレクトリの指定、dependenciesにNCMBのSDKを追記します。
Classes/External/Ncmb/Android/AndroidManifest.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.gmatsu.ncmbmanager"> <application android:allowBackup="true"> </application> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> </manifest>
パッケージ名、通信設定等を指定。
proj.android-studio/settings.gradle
include ':libcocos2dx' project(':libcocos2dx').projectDir = new File(settingsDir, '../cocos2d/cocos/platform/android/libcocos2dx') include ':mbaas_test' project(':mbaas_test').projectDir = new File(settingsDir, 'app') include ':ncmbmanager' project(':ncmbmanager').projectDir = new File(settingsDir, '../Classes/External/Ncmb/Android')
ライブラリのパスを追加。
proj.android-studio/app/build.gradle
: dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) compile project(':libcocos2dx') compile project(':controlotherapp') }
ライブラリ名の追加。
proj.android-studio/app/jni/Android.mk
: LOCAL_SRC_FILES := hellocpp/main.cpp \ ../../../Classes/AppDelegate.cpp \ ../../../Classes/HelloWorldScene.cpp \ ../../../Classes/External/Ncmb/Android/NcmbManager.cpp : LOCAL_C_INCLUDES := $(LOCAL_PATH)/../../../Classes LOCAL_C_INCLUDES += $(LOCAL_PATH)/../../../Classes/External/Ncmb
ビルドに加えるソースファイル、ヘッダファイルを追加。
ここまでの設定が終わると以下の処理をコメントにする事でAndroidのビルドが通るようになります。
- AppDelegate.cpp、HelloWorld.cpp等でのNcmbManager.hのインクルード
- NcmbManager.cppに何も記述しない、又は全てコメント
- NcmbManager.javaの「package com.example.gmatsu.ncmbmanager;」以外が全てコメント
iOSで既に実装していた部分等ですね。
やっと設置が終わりました…。
後はソースを書いていくことになります。
2.NCMBのAPI呼び出し作成
APIの呼び出しはjavaで書きます。
先程名前を変えたファイル、
Classes/External/Ncmb/Android/src/com/example/gmatsu/ncmbmanager/NcmbManager.java
に処理を書いていきます。
Classes/External/Ncmb/Android/src/com/example/gmatsu/ncmbmanager/NcmbManager.java
package com.example.gmatsu.ncmbmanager; import android.util.Log; import android.content.Context; import org.cocos2dx.lib.Cocos2dxActivity; import com.nifty.cloud.mb.core.NCMB; import com.nifty.cloud.mb.core.NCMBException; import com.nifty.cloud.mb.core.NCMBObject; import com.nifty.cloud.mb.core.DoneCallback; public class NcmbManager { // Context private static Context context = null; /** * @brief SDK初期化 */ static public void init(String app_key, String client_key) { // Context取得 context = Cocos2dxActivity.getContext(); // NCMB初期化 NCMB.initialize(context.getApplicationContext(), app_key, client_key); } /** * @brief データ登録 * @param const char* class_name クラス名 * @param int lv レベル * @param int hp HP * @param int exp 経験値 */ static public void add(String class_name, int lv, int hp, int exp) { // NCMBObject生成 NCMBObject obj = new NCMBObject(class_name); // 登録データの指定 obj.put("lv", lv); obj.put("hp", hp); obj.put("exp", exp); // 登録 obj.saveInBackground(new DoneCallback() { @Override public void done(NCMBException error) { if (error != null) { // 失敗 Log.d("NCMB", "データ登録失敗"); } else { // 成功 Log.d("NCMB", "データ登録失敗"); } } }); } }
iOS側(NcmbManager.mm)に準備した同様の役割、名前の関数を準備しています。
初期化方法、登録データの設定・登録の流れはほとんどiOS版と変わりません。
JavaとObjective-cの違いがあるくらいです。
イントロダクション (Android) : クイックスタート | ニフティクラウド mobile backend
公式のドキュメントに詳細が載っていますので詳しくはそちらで確認してください。
3.C++からJavaの関数を呼び出す
Objective-cのようにC++のコードからそのままJavaの関数が呼び出せれば良いのですが、それは行なえません。
そこでJNIを利用し、C++からJavaの関数を呼び出せるようにします。
JNIについてはこちらのサイトで解説して下さっています。
Classes/External/Ncmb/Android/NcmbManager.cpp
#include "NcmbManager.h" #include "platform/android/jni/JniHelper.h" namespace NcmbConnect { using namespace cocos2d; const char* MBAAS_CONNECT_CLASS_NAME = "com/example/gmatsu/ncmbmanager/NcmbManager"; /** * @brief コンストラクタ */ NcmbManager::NcmbManager() { } /** * @brief デストラクタ */ NcmbManager::~NcmbManager() { } /** * @brief SDK初期化 * @param app_key アプリケーションキー * @param client_key クライアントキー */ void NcmbManager::init(const char* app_key, const char* client_key) { cocos2d::JniMethodInfo method_info; // java内関数取得 if (cocos2d::JniHelper::getStaticMethodInfo(method_info, MBAAS_CONNECT_CLASS_NAME, "init","(Ljava/lang/String;Ljava/lang/String;)V")) { // 文字列変換 jstring in_app_key = method_info.env->NewStringUTF(app_key); jstring in_client_key = method_info.env->NewStringUTF(client_key); // Java関数呼び出し method_info.env->CallStaticVoidMethod(method_info.classID, method_info.methodID, in_app_key, in_client_key); // 解放 method_info.env->DeleteLocalRef(in_app_key); method_info.env->DeleteLocalRef(in_client_key); method_info.env->DeleteLocalRef(method_info.classID); } } /** * @brief データ登録 * @param class_name クラス名 * @param lv レベル * @param hp HP * @param exp 経験値 */ void NcmbManager::add(const char* class_name, int lv, int hp, int exp) { cocos2d::JniMethodInfo method_info; // java内関数取得 if (cocos2d::JniHelper::getStaticMethodInfo(method_info, MBAAS_CONNECT_CLASS_NAME, "add", "(Ljava/lang/String;III)V")) { // 文字列変換 jstring in_class_name = method_info.env->NewStringUTF(class_name); // Java関数呼び出し method_info.env->CallStaticVoidMethod(method_info.classID, method_info.methodID, in_class_name, lv, hp, exp); // 解放 method_info.env->DeleteLocalRef(in_class_name); method_info.env->DeleteLocalRef(method_info.classID); } } };
これでJava側の関数をC++で呼び出せるようになります。
ちなみにヘッダファイルと関数の呼び出し箇所ですが、新しく追記する必要はありません。
今回はiOS版で用意したヘッダファイル、呼び出しがそのまま使えるように作成を行いました。
関数名を同じにしていますので、iOSで実行した際はNcmbManager.mmの関数、Androidで実行した時はNcmbManager.cppから呼び出したNcmbManager.javaの関数が呼び出されるようになります。
iOS、Androidの関数名を分けてしまうと、OSを判別するマクロ等を利用しなければなりませんからこちらの方が断然扱いやすいと思います。
NCMBについては以上です。
そういえば今日からCEDEC2017が始まりましたね。
初参加なので少し緊張していますが、著名な方々のお話が聞けるのはとても楽しみです。
それではまた。