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

先日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

実行してみます。

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

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

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

$ source /Users/[user_name]/.bash_profile

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

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

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

いいですね!

利用できるプラグイン

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

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

$ sdkbox list
  _______ ______  _     _ ______   _____  _     _
  |______ |     \ |____/  |_____] |     |  \___/
  ______| |_____/ |    \_ |_____] |_____| _/   \_
 Copyright (c) 2016 SDKBOX Inc. v1.0.1.16
 share
     v2.3.9.0
         cocos2d-x v2.x (available)
         cocos2d-x v3.x (available)

 playphone
     v2.3.9.0
         cocos2d-x v2.x (available)
         cocos2d-x v3.x (available)

 scientificrevenue
     v2.3.9.0
         cocos2d-x v2.x (available)
         cocos2d-x v3.x (available)

 leadbolt
     v2.3.9.0
         cocos2d-x v2.x (available)
         cocos2d-x v3.x (available)

 SDKBOX
     v1.0.1.16

 chartboost
     v2.3.9.0
         cocos2d-x v2.x (available)
         cocos2d-x v3.x (available)

 kochava
     v2.3.9.0
         cocos2d-x v2.x (available)
         cocos2d-x v3.x (available)

 googleanalytics
     v2.3.9.0
         cocos2d-x v2.x (available)
         cocos2d-x v3.x (available)

 review
     v2.3.9.0
         cocos2d-x v2.x (available)
         cocos2d-x v3.x (available)

 gpg
     v2.3.9.0
         cocos2d-x v2.x (available)
         cocos2d-x v3.x (available)

 googleplayservices
     v2.3.9.0
         cocos2d-x v2.x (available)
         cocos2d-x v3.x (available)

 anysdk
     v2.3.9.0
         cocos2d-x v2.x (available)
         cocos2d-x v3.x (available)

 fyber
     v2.3.9.0
         cocos2d-x v2.x (available)
         cocos2d-x v3.x (available)

 agecheq
     v2.3.9.0
         cocos2d-x v2.x (available)
         cocos2d-x v3.x (available)

 iap
     v2.3.9.0
         cocos2d-x v2.x (available)
         cocos2d-x v3.x (available)

 sdkboxads
     v2.3.9.0
         cocos2d-x v2.x (available)
         cocos2d-x v3.x (available)

 apteligent
     v2.3.9.0
         cocos2d-x v2.x (available)
         cocos2d-x v3.x (available)

 amazon
     v2.3.9.0
         cocos2d-x v2.x (available)
         cocos2d-x v3.x (available)

 flurryanalytics
     v2.3.9.0
         cocos2d-x v2.x (available)
         cocos2d-x v3.x (available)

 inmobi
     v2.3.9.0
         cocos2d-x v2.x (available)
         cocos2d-x v3.x (available)

 onesignal
     v2.3.9.0
         cocos2d-x v2.x (available)
         cocos2d-x v3.x (available)

 valuepotion
     v2.3.9.0
         cocos2d-x v2.x (available)
         cocos2d-x v3.x (available)

 tune
     v2.3.9.0
         cocos2d-x v2.x (available)
         cocos2d-x v3.x (available)

 youtube
     v2.3.9.0
         cocos2d-x v2.x (available)
         cocos2d-x v3.x (available)

 appnext
     v2.3.9.0
         cocos2d-x v2.x (available)
         cocos2d-x v3.x (available)

 admob
     v2.3.9.0
         cocos2d-x v2.x (available)
         cocos2d-x v3.x (available)

 sdkboxplay
     v2.3.9.0
         cocos2d-x v2.x (available)
         cocos2d-x v3.x (available)

 appodeal
     v2.3.9.0
         cocos2d-x v2.x (available)
         cocos2d-x v3.x (available)

 bee7
     v2.3.9.0
         cocos2d-x v2.x (available)
         cocos2d-x v3.x (available)

 facebook
     v2.3.9.0
         cocos2d-x v2.x (available)
         cocos2d-x v3.x (available)

 adcolony
     v2.3.9.0
         cocos2d-x v2.x (available)
         cocos2d-x v3.x (available)

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

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

注意

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

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

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

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

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

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

プグインを追加する前に、一旦ビルドやAndroid Studioのインポートなど済ませておくと良さそうです。
(ちなみに[ SwordOfMyoo ]は2018年にリリース予定のアプリです!)

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

プラグイン別

AdMob

プラグインの追加

$ sdkbox import admobを実行します。

$ sdkbox import admob
  _______ ______  _     _ ______   _____  _     _
  |______ |     \ |____/  |_____] |     |  \___/
  ______| |_____/ |    \_ |_____] |_____| _/   \_
 Copyright (c) 2016 SDKBOX Inc. v1.0.1.16
 test speed of hosts...
 - test host main: 56.44KB/s.
 - test host china: 130.22KB/s.
 choose the fastest server 'china', speed is 130.22KB/s.
 Installation Successful :)
 Please reference the online documentation to finish the integration:
http://sdkbox-doc.github.io/en/plugins/admob/v3-cpp/
osascript: 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.
 Installation Successful :)

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

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

広告IDの変更

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

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

{
    "android": {
        "AdMob": {
            "ads": {
                "gameover": {
                    "id": "ca-app-pub-0000000000000000/0000000000",
                    "type": "interstitial",
                    "is_designed_for_families": false
                },
                "home": {
                    "id": "ca-app-pub-0000000000000000/0000000000",
                    "type": "banner",
                    "alignment": "bottom",
                    "width": 0,
                    "height": 0,
                    "is_designed_for_families": false
                }
            }
        }
    },
    "ios": {
        // 割愛
    }
}

AdMob表示までのステップ

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

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

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

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

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

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

// GameScene.h
class GameScene : public cocos2d::CCLayer
{
private:
    bool m_idDisplayedBanner = false;
    :
// GameScene.cpp
#include "PluginAdMob/PluginAdMob.h"

bool GameScene::init()
{
    if (Layer::init() == false) {
        return false;
    }
    sdkbox::PluginAdMob::cache("home");
    this->scheduleUpdate();
}

void GameScene::update(float delta)
{
    if (m_idDisplayedBanner = false && sdkbox::PluginAdMob::isAvailable("home")) {
        sdkbox::PluginAdMob::show("home");
        m_idDisplayedBanner = true;
    }
}

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

  • フラグを持ち
  • 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を実行します。

$ sdkbox import adcolony
  _______ ______  _     _ ______   _____  _     _
  |______ |     \ |____/  |_____] |     |  \___/
  ______| |_____/ |    \_ |_____] |_____| _/   \_
 Copyright (c) 2016 SDKBOX Inc. v1.0.1.16
 test speed of hosts...
 - test host main: 244.78KB/s.
 - test host china: 129.50KB/s.
 choose the fastest server 'main', speed is 244.78KB/s.
 Installation Successful :)
 Please reference the online documentation to finish the integration:
http://sdkbox-doc.github.io/en/plugins/adcolony/v3-cpp/
osascript: 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.
 Installation Successful :)

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

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

広告IDの変更

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

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

{
    "android": {
        "AdColony": {
            "id": "app000000000000000000",
            "debug": false,
            "ads": {
                "v4vc": {
                    "zone": "vz000000000000000000",
                    "v4vc": true,
                    "pre_popup": false,
                    "post_popup": false
                },
                "video": {
                    "zone": "vz000000000000000000",
                    "v4vc": false
                }
            }
        }
    },
    "ios": {
        // 割愛
    }
}

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

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

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

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

初期化

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

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

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

// GameScene.h
#include "PluginAdColony/PluginAdColony.h"

class GameScene : public cocos2d::CCLayer, sdkbox::AdColonyListener
{
private:
    bool m_hasAdcolony;

public:
    virtual bool init();
    static cocos2d::Scene *createScene();
    CREATE_FUNC(GameScene);

    void onAdColonyChange(const sdkbox::AdColonyAdInfo& info, bool available);
    void onAdColonyReward(const sdkbox::AdColonyAdInfo& info, const std::string& currencyName, int amount, bool success);
    void onAdColonyStarted(const sdkbox::AdColonyAdInfo& info);
    void onAdColonyFinished(const sdkbox::AdColonyAdInfo& info);
};
// GameScene.cpp
#include "PluginAdColony/PluginAdColony.h"

bool GameScene::init()
{
    if (Layer::init() == false) {
        return false;
    }
    sdkbox::PluginAdColony::setListener(this);
}

void GameScene::onAdColonyChange(const sdkbox::AdColonyAdInfo& info, bool available)
{
    m_hasAdcolony = available;
}

void GameScene::onAdColonyReward(const sdkbox::AdColonyAdInfo& info, const std::string& currencyName, int amount, bool success)
{
    if (success) {
        // 報酬付与処理
    }
}

void GameScene::onAdColonyStarted(const sdkbox::AdColonyAdInfo &info)
{
    CocosDenshion::SimpleAudioEngine::getInstance()->pauseBackgroundMusic();
}

void GameScene::onAdColonyFinished(const sdkbox::AdColonyAdInfo &info)
{
    CocosDenshion::SimpleAudioEngine::getInstance()->resumeBackgroundMusic();
}
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++難しいです。