業界はUnity一色のように見えますが、もうちょっとcocos2d-xでがんばろうと思っています。

先日SDKBOXを使って、リリース済み Android アプリに新しい広告を実装しました。

SDKBOXについて (というよりcocos2d-x全般について) はあまり新しい情報がないように見受けられるため、私が辿った実装手順についてまとめてみました。

ゴール

Cocos2d-x の新規プロジェクトにAdMobAdColonyの広告を実装する。

AdMob はフッターにスマートバナーを表示します。
AdColony はインタースティシャルリワード広告(動画)をします。

それぞれのアカウント作成を済ませて広告コードを取得済みという前提です。

なお動作を確認したのはAndroidアプリのみで、iOS版は未確認です。

環境

  • macOS Sierra
  • Cocos2d-x 3.10
  • SDKBOX v1.0.1.16

cocos2d-xのバージョンは古いのですが、cocosの最新バージョンであってもSDKBOXの導入についてはそれほど変わらないかと思います。

SDKBOXとは

課金やFaceBookなど、よく使うSKDを簡単に扱うことができるようにしてくださる便利ツールです。

SDKBOX
http://docs.sdkbox.com/

Cocos2d-xだけではなく、実はUnityにも使えるのです!

SDKBOXのインストール

はじめに「各プラグインのインストーラー」をインストールします。 ややこしいですね。。。

セットアップ方法は次のURLに掲載されております。

http://docs.sdkbox.com/en/installer/#get-the-installer

実行してみます。

1$ python -c "import urllib; s = urllib.urlopen('https://raw.githubusercontent.com/sdkbox-doc/en/master/install/install.py').read(); exec s"
2Download SDKBox installer ...
3[###################################] 100%
4INFO Please execute command: "source /Users/[user_name]/.bash_profile" to make added system variables take effect
5SUCCESS! SDBOX installer have been installed.
6Next, type "sdkbox -h" to see the usage help.

無事インストールできました。

sourceコマンドを叩いてね 」とおっしゃるので、次にこれを実行しましょう。

1$ source /Users/[user_name]/.bash_profile

[user_name]の部分はログイン中のユーザ名が入ります。

さて、動作確認です。sdkboxを呼び出してみましょう。

 1$ sdkbox
 2  _______ ______  _     _ ______   _____  _     _
 3  |______ |     \ |____/  |_____] |     |  \___/
 4  ______| |_____/ |    \_ |_____] |_____| _/   \_
 5 Copyright (c) 2016 SDKBOX Inc. v1.0.1.16
 6usage: sdkbox [-h] [-v] [-p [PROJECT]] [-b [PLUGIN]] [-D SYMBOL] [-q]
 7              [-d [DAYS]] [--dryrun] [--forcedownload] [--noupdate]
 8              [--alwaysupdate] [--patcherrors] [--nopatching]
 9              [--nopatchingcpp] [--jsonapi] [--forcecopy] [--mkey MKEY]
10              [--mvalue MVALUE] [--local] [--remote] [--info INFO]
11              [--runin RUNIN]
12              {import,info,update,forget,restore,list,clean,symbols,version,set,tracking}
13sdkbox: error: too few arguments

いいですね!

利用できるプラグイン

これまでの手順は「 SDKBOX各プラグインをインストールするためのインストーラー 」の導入手順でした。

次のコマンドを打つと、利用可能なプラグインをチェックすることができます。

  1$ sdkbox list
  2  _______ ______  _     _ ______   _____  _     _
  3  |______ |     \ |____/  |_____] |     |  \___/
  4  ______| |_____/ |    \_ |_____] |_____| _/   \_
  5 Copyright (c) 2016 SDKBOX Inc. v1.0.1.16
  6 share
  7     v2.3.9.0
  8         cocos2d-x v2.x (available)
  9         cocos2d-x v3.x (available)
 10
 11 playphone
 12     v2.3.9.0
 13         cocos2d-x v2.x (available)
 14         cocos2d-x v3.x (available)
 15
 16 scientificrevenue
 17     v2.3.9.0
 18         cocos2d-x v2.x (available)
 19         cocos2d-x v3.x (available)
 20
 21 leadbolt
 22     v2.3.9.0
 23         cocos2d-x v2.x (available)
 24         cocos2d-x v3.x (available)
 25
 26 SDKBOX
 27     v1.0.1.16
 28
 29 chartboost
 30     v2.3.9.0
 31         cocos2d-x v2.x (available)
 32         cocos2d-x v3.x (available)
 33
 34 kochava
 35     v2.3.9.0
 36         cocos2d-x v2.x (available)
 37         cocos2d-x v3.x (available)
 38
 39 googleanalytics
 40     v2.3.9.0
 41         cocos2d-x v2.x (available)
 42         cocos2d-x v3.x (available)
 43
 44 review
 45     v2.3.9.0
 46         cocos2d-x v2.x (available)
 47         cocos2d-x v3.x (available)
 48
 49 gpg
 50     v2.3.9.0
 51         cocos2d-x v2.x (available)
 52         cocos2d-x v3.x (available)
 53
 54 googleplayservices
 55     v2.3.9.0
 56         cocos2d-x v2.x (available)
 57         cocos2d-x v3.x (available)
 58
 59 anysdk
 60     v2.3.9.0
 61         cocos2d-x v2.x (available)
 62         cocos2d-x v3.x (available)
 63
 64 fyber
 65     v2.3.9.0
 66         cocos2d-x v2.x (available)
 67         cocos2d-x v3.x (available)
 68
 69 agecheq
 70     v2.3.9.0
 71         cocos2d-x v2.x (available)
 72         cocos2d-x v3.x (available)
 73
 74 iap
 75     v2.3.9.0
 76         cocos2d-x v2.x (available)
 77         cocos2d-x v3.x (available)
 78
 79 sdkboxads
 80     v2.3.9.0
 81         cocos2d-x v2.x (available)
 82         cocos2d-x v3.x (available)
 83
 84 apteligent
 85     v2.3.9.0
 86         cocos2d-x v2.x (available)
 87         cocos2d-x v3.x (available)
 88
 89 amazon
 90     v2.3.9.0
 91         cocos2d-x v2.x (available)
 92         cocos2d-x v3.x (available)
 93
 94 flurryanalytics
 95     v2.3.9.0
 96         cocos2d-x v2.x (available)
 97         cocos2d-x v3.x (available)
 98
 99 inmobi
100     v2.3.9.0
101         cocos2d-x v2.x (available)
102         cocos2d-x v3.x (available)
103
104 onesignal
105     v2.3.9.0
106         cocos2d-x v2.x (available)
107         cocos2d-x v3.x (available)
108
109 valuepotion
110     v2.3.9.0
111         cocos2d-x v2.x (available)
112         cocos2d-x v3.x (available)
113
114 tune
115     v2.3.9.0
116         cocos2d-x v2.x (available)
117         cocos2d-x v3.x (available)
118
119 youtube
120     v2.3.9.0
121         cocos2d-x v2.x (available)
122         cocos2d-x v3.x (available)
123
124 appnext
125     v2.3.9.0
126         cocos2d-x v2.x (available)
127         cocos2d-x v3.x (available)
128
129 admob
130     v2.3.9.0
131         cocos2d-x v2.x (available)
132         cocos2d-x v3.x (available)
133
134 sdkboxplay
135     v2.3.9.0
136         cocos2d-x v2.x (available)
137         cocos2d-x v3.x (available)
138
139 appodeal
140     v2.3.9.0
141         cocos2d-x v2.x (available)
142         cocos2d-x v3.x (available)
143
144 bee7
145     v2.3.9.0
146         cocos2d-x v2.x (available)
147         cocos2d-x v3.x (available)
148
149 facebook
150     v2.3.9.0
151         cocos2d-x v2.x (available)
152         cocos2d-x v3.x (available)
153
154 adcolony
155     v2.3.9.0
156         cocos2d-x v2.x (available)
157         cocos2d-x v3.x (available)

availableは「利用可能」であるという状態を指しており、この時点ではまだプラグイン本体がDLされておりません。

プラグイン組み込みを実行すると、表示がinstalledに変化するようです。

注意

今回追加するプラグインはどちらもgoogleplayservicesプラグインが一緒にインストールされます。

既に GooglePlayServiceを導入済みのプロジェクトでは競合にご注意 ください。

また、大量のファイルが追加されますから.gitignoreで次のものなどは除外しておくと吉です。

1[projectRoot]/cocos2d/cocos/platform/android/java/libs/gps/build/*

私はまっさらな状態からプラグインを追加したく、新規プロジェクトを追加しました。

1$ cocos new SwordOfMyoo -p net.atuweb.mobile.SwordOfMyoo -l cpp

プグインを追加する前に、一旦ビルドやAndroid Studioのインポートなど済ませておくと良さそうです。

それでは、ぞれぞれプラグインを追加していきましょう。

プラグイン別

AdMob

プラグインの追加

$ sdkbox import admobを実行します。

 1$ sdkbox import admob
 2  _______ ______  _     _ ______   _____  _     _
 3  |______ |     \ |____/  |_____] |     |  \___/
 4  ______| |_____/ |    \_ |_____] |_____| _/   \_
 5 Copyright (c) 2016 SDKBOX Inc. v1.0.1.16
 6 test speed of hosts...
 7 - test host main: 56.44KB/s.
 8 - test host china: 130.22KB/s.
 9 choose the fastest server 'china', speed is 130.22KB/s.
10 Installation Successful :)
11 Please reference the online documentation to finish the integration:
12http://sdkbox-doc.github.io/en/plugins/admob/v3-cpp/
13osascript: OpenScripting.framework - scripting addition "/Library/ScriptingAdditions/Adobe Unit Types.osax" cannot be used with the current OS because it has no OSAXHandlers entry in its Info.plist.
14 Installation Successful :)

AdMobプラグインの説明ドキュメントは以下です。

http://docs.sdkbox.com/en/plugins/admob/v3-cpp/

広告IDの変更

設定ファイルは自動生成されるResources/sdkbox_config.jsonです。
このjsonファイルを編集し、IDをご自身のものに差し替えてください。

以下は私が動作を確認した設定です。

 1{
 2    "android": {
 3        "AdMob": {
 4            "ads": {
 5                "gameover": {
 6                    "id": "ca-app-pub-0000000000000000/0000000000",
 7                    "type": "interstitial",
 8                    "is_designed_for_families": false
 9                },
10                "home": {
11                    "id": "ca-app-pub-0000000000000000/0000000000",
12                    "type": "banner",
13                    "alignment": "bottom",
14                    "width": 0,
15                    "height": 0,
16                    "is_designed_for_families": false
17                }
18            }
19        }
20    },
21    "ios": {
22        // 割愛
23    }
24}

AdMob表示までのステップ

次の手順を追って広告を呼びだします。

  • 初期化
  • キャッシュ
  • 表示
初期化

プラグイン導入時にAppDelegate.cppが修正され初期化メソッドが埋め込まれています。

1sdkbox::PluginAdMob::init();
2
キャッシュ/表示

キャッシュを実行してから実際に広告が表示されるまで多少時間がかかります。

そのため、update()など定期的に呼び出されるメソッドの中で「広告データの読み込みが完了」するまで待つ必要があります。

1// GameScene.h
2class GameScene : public cocos2d::CCLayer
3{
4private:
5    bool m_idDisplayedBanner = false;
6    :
7
 1// GameScene.cpp
 2#include "PluginAdMob/PluginAdMob.h"
 3
 4bool GameScene::init()
 5{
 6    if (Layer::init() == false) {
 7        return false;
 8    }
 9    sdkbox::PluginAdMob::cache("home");
10    this->scheduleUpdate();
11}
12
13void GameScene::update(float delta)
14{
15    if (m_idDisplayedBanner = false && sdkbox::PluginAdMob::isAvailable("home")) {
16        sdkbox::PluginAdMob::show("home");
17        m_idDisplayedBanner = true;
18    }
19}
20

上記のプログラムでは次のようなことを行なっています。

  • フラグを持ち
  • update()メソッドで広告データの到着をチェック
  • 広告データが準備できたらshow()
  • フラグを立てる

この実装が一番正直かなと思います。

cache()、show()には[sdkbox_config.json]で定義した広告名を与えます。
そのため、複数の広告タイプがある場合はそれぞれをcache()、show()する必要がある点ご注意ください。

なお、AdMobについては以下を参考にいたしました。
ありがとうございました。

津田の開発な日記
cocos2d-x v3 への sdkbox admob 組み込み
http://vivi.dyndns.org/blog/archives/1347

ハマりポイント

実装については「cache()を呼び出してからisAvailable()がtrueになるまでタイムラグがある」ことがわかれば問題がないと思います。

実装よりも、私はJSONの設定でつまづく点が多かったです。

はじめ全くバナーが表示されませんでしたが、ドキュメントなどを読み込んで、定義ファイルにis_designed_for_families : falseを足してみるとバナーが表示されました。

また、JSONで[ debug : false ]にしてもバナーが表示されず、debugそのものをカットすると良いという情報もありました。

AdColony

プラグインの追加

$ sdkbox import adcolonyを実行します。

 1$ sdkbox import adcolony
 2  _______ ______  _     _ ______   _____  _     _
 3  |______ |     \ |____/  |_____] |     |  \___/
 4  ______| |_____/ |    \_ |_____] |_____| _/   \_
 5 Copyright (c) 2016 SDKBOX Inc. v1.0.1.16
 6 test speed of hosts...
 7 - test host main: 244.78KB/s.
 8 - test host china: 129.50KB/s.
 9 choose the fastest server 'main', speed is 244.78KB/s.
10 Installation Successful :)
11 Please reference the online documentation to finish the integration:
12http://sdkbox-doc.github.io/en/plugins/adcolony/v3-cpp/
13osascript: OpenScripting.framework - scripting addition "/Library/ScriptingAdditions/Adobe Unit Types.osax" cannot be used with the current OS because it has no OSAXHandlers entry in its Info.plist.
14 Installation Successful :)

AdColonyプラグインの説明ドキュメントは以下です。

http://docs.sdkbox.com/en/plugins/adcolony/v3-cpp/

広告IDの変更

設定ファイルは同じくResources/sdkbox_config.jsonです。
このjsonファイルを編集し、IDをご自身のものに差し替えてください。

以下は私が動作を確認した設定です。

 1{
 2    "android": {
 3        "AdColony": {
 4            "id": "app000000000000000000",
 5            "debug": false,
 6            "ads": {
 7                "v4vc": {
 8                    "zone": "vz000000000000000000",
 9                    "v4vc": true,
10                    "pre_popup": false,
11                    "post_popup": false
12                },
13                "video": {
14                    "zone": "vz000000000000000000",
15                    "v4vc": false
16                }
17            }
18        }
19    },
20    "ios": {
21        // 割愛
22    }
23}

広告動画表示までのステップ

広告表示までのフローは次です。

  • 初期化
  • 広告データ準備
  • 広告表示
  • 報酬の付与

AdMobほぼ同じですが、AdColonyはリスナーを設定します。

初期化

プラグイン導入時にAppDelegate.cppが修正され初期化メソッドが埋め込まれています。 これはAdMob同様ですね。

1sdkbox::PluginAdColony::init();
2
リスナーの実装

C++は多重継承できます。
今回はゲームのメインシーンにAdColonyListenerを継承させる方法で実装します。

 1// GameScene.h
 2#include "PluginAdColony/PluginAdColony.h"
 3
 4class GameScene : public cocos2d::CCLayer, sdkbox::AdColonyListener
 5{
 6private:
 7    bool m_hasAdcolony;
 8
 9public:
10    virtual bool init();
11    static cocos2d::Scene* createScene();
12    CREATE_FUNC(GameScene);
13
14    void onAdColonyChange(const sdkbox::AdColonyAdInfo& info, bool available);
15    void onAdColonyReward(const sdkbox::AdColonyAdInfo& info, const std::string& currencyName, int amount, bool success);
16    void onAdColonyStarted(const sdkbox::AdColonyAdInfo& info);
17    void onAdColonyFinished(const sdkbox::AdColonyAdInfo& info);
18};
19
 1// GameScene.cpp
 2#include "PluginAdColony/PluginAdColony.h"
 3
 4bool GameScene::init()
 5{
 6    if (Layer::init() == false) {
 7        return false;
 8    }
 9    sdkbox::PluginAdColony::setListener(this);
10}
11
12void GameScene::onAdColonyChange(const sdkbox::AdColonyAdInfo& info, bool available)
13{
14    m_hasAdcolony = available;
15}
16
17void GameScene::onAdColonyReward(const sdkbox::AdColonyAdInfo& info, const std::string& currencyName, int amount, bool success)
18{
19    if (success) {
20        // 報酬付与処理
21    }
22}
23
24void GameScene::onAdColonyStarted(const sdkbox::AdColonyAdInfo &info)
25{
26    CocosDenshion::SimpleAudioEngine::getInstance()->pauseBackgroundMusic();
27}
28
29void GameScene::onAdColonyFinished(const sdkbox::AdColonyAdInfo &info)
30{
31    CocosDenshion::SimpleAudioEngine::getInstance()->resumeBackgroundMusic();
32}
33
onAdColonyChange()

広告データのスタンバイを確認するためのメソッドで、「ステータスが変化した時」だけコールバックが入るもののようです。

サンプルソースではメンバにもたせたフラグを立てる処理のみといたしました。 詳しくは後述します。

onAdColonyReward()

動画の視聴が完了した時に呼び出されるメソッドです。

success=trueの場合に報酬を付与する処理を実装してあげましょう。

「報酬内容」はアプリによると思いますため、上記のコードではコメントのみ入れてあります。

onAdColonyStarted() / onAdColonyFinished()

広告の開始、終了時に呼び出されます。

ドキュメントに「動画広告を再生するときはアプリのBGMをミュートしましょう」という記述がありました。
たしかに動画再生中にBGMが混ざってしまうのはかっこよくありませんね。

私はSimpleAudioEngineを使っているため、ドキュメントそのままの処理を入れました。

ハマりポイント

広告データの有無

前述の通り、onAdColonyChange()は「 ステータスが変化した時にだけ呼び出される 」もので、update()のように定期的に呼ばれるものではありません。

私が思い切り勘違いしていたのは「アプリ起動後に一度でもavailable=trueを受け取ったら、状態が変わらない限りonAdColonyChange()はもう呼び出されない」ことです。

私はアプリを次のように実装していました

  • 1.アプリ起動
  • 2.シーンAを生成しリスナーをセット
  • 3.onAdColonyChange()がコールバックされavailable=trueを受け取る
  • 4.シーンを破棄して新しいシーンを生成
  • 5.シーンAを再度生成

上記のフローでは3でフラグを受け取り済みのため、 5でフラグを再度受け取ることはありません。
このように、シーケンスの組み立て方によってはどれだけ待っても「広告準備状態にならない」ということになってしまいます。

先のソースではavailableをメンバに代入する実装としたのはそのためで、対処として私はコールバックと広告表示を別々に処理する形にいたしました。

リスナーがなくてアプリ落ち

リスナーをセットした後に replaceScene() でシーンを切り替えててしまうとリスナーが行方不明になってアプリ落ちにつながってしまいました。

対応としては次が考えられます。

  • リスナーをシーンから切り離した実装に変更する
  • シーンを破棄しないでシーンの移動はpushScene()、popScene()を利用する。

私は後者で対応しました。

かっこ悪いダイアログ

以下のタイミングでかっこ悪いダイアログが表示されることがあります。

  • 動画広告の再生前
  • 動画広告の再生完了後

おそらくpre_popuppost_popupがtrueだとそうなるようなのですが、因果関係がよくわかってないです。

デバッグフラグ

JSON の設定は無視されるものがあるようです。
JSON を[ debug :false ]にしても動画広告が「公開用」に切り替わるわけではありません。

こちらはAdColonyご担当者様に連絡して切り替えていただく必要があります。

おわりに

今まで時間がかかっていた広告の実装が、SDKBOX を利用することで簡単に終えられるようになりました。

つまづきポイントをしっかり把握すれば、SDKBOX はなかなか便利なツールだと思いますよ!


C++難しいです。

プログラミング言語C++ 第4版

ビャーネ・ストラウストラップ,Bjarne Stroustrup
出版社:SBクリエイティブ  発売日:2015-02-28

Amazonで詳細を見る

Effective C++ 第3版 (ADDISON-WESLEY PROFESSIONAL COMPUTI)

スコット メイヤーズ
出版社:丸善出版  発売日:2014-03-18

Amazonで詳細を見る