Cocos2d-xでSoomlaを使って課金を実装する

cocos2d-xで課金に対応したアプリを作る場合、ネイティブ連携のコードを書いて実装する必要があります。
特にiOSとAndroid両対応の場合、両方環境に対応した課金処理とテストを行う必要があり、かなり大変な作業になってしまいます。

# SOOMLA
そこで今回は __SOOMLA__ という課金ライブラリを使って、簡単に課金処理を実装する方法を解説します。
http://soom.la/

SoomlaではiOS/Androidでの課金処理、課金アイテムの一括管理、課金済アイテムのリストア、非消費型アイテムの課金処理、仮想通貨（消費型アイテム）や仮想アイテムの所持数管理などを行う事が出来ます。

>なお、消費型アイテムの場合はコインの所持数などをサーバーで管理する必要がありますが、課金ライブラリだけSoomla（MITライセンス）を使用し、サーバーサイドは自分で用意することが可能です。
>また有料になりますが、高機能なSoomlaのクラウドサービスを利用することも可能です。

# soomla/cocos2dx-storeの導入

それでは、Soomlaの導入手順を解説して行きます（といっても、殆ど公式ページを意訳しただけですが）。
詳しい情報はGitHubの公式ページに解説がありますので、そちらを参照してください。

・soomla/cocos2dx-store
https://github.com/soomla/cocos2dx-store

## 1. cocos2d-xのダウンロード
まずcocos2d-xをダウンロードし、プロジェクト用のディレクトリに展開します
※現時点では3.0には未対応のようですので、2.2.1をDLします
http://cdn.cocos2d-x.org/cocos2d-x-2.2.1.zip

```
$ unzip cocos2d-x-2.2.1.zip -d /my/project/dir
```

## 2.  プロジェクト作成
通常の手順通りcocos2d-xプロジェクトを作成します

```
$ cd /my/project/dir
$ cd tools/project-creator
$ python create_project.py -project MyProjName -package com.my.proj -language cpp
```

## 3.  cocos2dx-storeの取得
extensionsディレクトリにcocos2dx-storeを git clone します

```
$ git clone --recursive https://github.com/soomla/cocos2dx-store.git extensions/cocos2dx-store
```

>cocos2d-x-storeはcocos用のインターフェースですので、実際にはiOSとAndroid用のサブモジュールが必要です。
>以下のディレクトリに各ストアモジュールがcloneされている事を確認してください。
>  __extensions/cocos2dx-store/submodules/ios-store__
>  __extensions/cocos2dx-store/submodules/android-store__
>
>※permissionの問題等で上手くcloneされない場合があります。個別にcloneするかGitHubに公開鍵を登録（https://help.github.com/articles/error-permission-denied-publickey ）してください。
>
```
$ git clone --recursive https://github.com/soomla/ios-store.git extensions/cocos2dx-store/submodules/ios-store
$ git clone --recursive https://github.com/soomla/android-store.git extensions/cocos2dx-store/submodules/android-store
```

## 4. Janssonの取得
SOOMLAは内部でJanssonを使用します。externalディレクトリ等にcloneします。

```
$ git clone --recursive https://github.com/vedi/jansson.git external/jansson
```

## 5. Soomla.hのインクルード
Soomlaを使用したい場所でSoomla.hをインクルードします。

```cpp
#include "Soomla.h"
```

## 6. 課金アイテムの登録
CCIStoreAssetsを継承したクラスを作成し、各課金アイテムの設定を行います。
ここでは、example projectのソースを参考に、アイテムの種別毎の設定を見て行きます。
__cocos2dx-store-example/Classes/MuffinRushAssets.h/cpp__
https://github.com/soomla/cocos2dx-store-example

以下はMuffinRushAssets.cpp内で仮想通貨や課金アイテムの設定を行っている部分の抜粋です。

### ・仮想通貨（アプリ内で消費されるもの）

```cpp
    /** Virtual Currencies **/
    CCVirtualCurrency *muffinCurrency = CCVirtualCurrency::create(
            CCString::create("Muffins"),                            // 仮想通貨の表示名
            CCString::create(""),                                   // 説明文
            CCString::create(MUFFIN_CURRENCY_ITEM_ID)               // 仮想通貨ID
    );
```

### ・仮想通貨パック（ユーザーが実際に購入するもの）

```cpp
    /** Virtual Currency Packs **/
    CCVirtualCurrencyPack *tenmuffPack = CCVirtualCurrencyPack::create(
            CCString::create("10 Muffins"),                         // 通過パックの表示名
            CCString::create("Test refund of an item"),             // 説明文
            CCString::create("muffins_10"),                         // アイテムID
            CCInteger::create(10),                                  // 購入で得られる仮想通貨数
            CCString::create(MUFFIN_CURRENCY_ITEM_ID),              // 関連する仮想通貨ID
            CCPurchaseWithMarket::create(
                    CCString::create(TENMUFF_PACK_PRODUCT_ID),      // ProductID(アプリ内サービスID)
                    CCDouble::create(0.99)                          // 金額
            )
    );
```

### ・仮想アイテム（ゲーム内で仮想通貨を消費して購入するもの）

```cpp
    /** Virtual Goods **/
    CCVirtualGood *muffincakeGood = CCSingleUseVG::create(
            CCString::create("Fruit Cake"),                         // アイテムの表示名
            CCString::create("Customers buy a double portion"),     // 説明文
            CCString::create("fruit_cake"),                         // アイテムID
            CCPurchaseWithVirtualItem::create(
                    CCString::create(MUFFIN_CURRENCY_ITEM_ID),      // 消費する仮想通貨ID
                    CCInteger::create(225)                          // 消費数
            )
    );
```

### ・非消費型アイテム（広告削除など、一度購入したらなくならないもの）

```cpp
    /** Google MANAGED Items **/
    CCNonConsumableItem *noAdsNoncons = CCNonConsumableItem::create(
            CCString::create("No Ads"),                             // アイテム表示名
            CCString::create("Test purchase of MANAGED item."),     // 説明文
            CCString::create("no_ads"),                             // アイテムID
            CCPurchaseWithMarket::createWithMarketItem(
                CCMarketItem::create(
                    CCString::create(NO_ADDS_NONCONS_PRODUCT_ID),   // ProductID(アプリ内サービスID)
                    CCInteger::create(CCMarketItem::NONCONSUMABLE), // 非消費型アイテムを指定
                    CCDouble::create(1.99)                          // 金額
                )
            )
    );
```

## 7. CCStoreControllerの初期化
ストアパラメーターを指定し、CCStoreControllerを初期化します
※この初期化はアプリ内で一度だけ行います。通常は　Appdelegate::applicationDidFinishLaunching()などに書いておけば良いかと思います。

```cpp
CCDictionary *storeParams = CCDictionary::create();
storeParams->setObject(CCString::create("ExampleSoomSecret"), "soomSec");
storeParams->setObject(CCString::create("ExamplePublicKey"), "androidPublicKey");
storeParams->setObject(CCString::create("ExampleCustomSecret"), "customSecret");
soomla::CCStoreController::createShared(YourStoreAssetsImplementation::create(), storeParams);
```

初期化パラメーターには以下の情報を指定してください。

| "ExampleSoomSecret" | 内部データ暗号化のための暗号化鍵（任意の文字列） |
|:-----------|------------:|
| "ExamplePublicKey" | GooglePlayの公開鍵 |
| "ExampleCustomSecret" | セカンダリ暗号化鍵 （任意の文字列）|

※ __soomSecとcustomSecretはアプリ公開後は変更出来ません（内部のデータを取得出来なくなる）__ ので注意してください。

## 8. 課金処理の実装
プログラム内の課金を行いたい箇所で以下の処理を実装します。

###課金開始（課金を行う時点で実行します）
```cpp
	soomla::CCStoreController::sharedStoreController()->storeOpening();
```

###・非消費アイテムの購入

```cpp
    soomla::CCSoomlaError *err;
    soomla::CCStoreController::sharedStoreController()->buyMarketItem("no_ads", &err);
```

### ・消費アイテムの購入

```cpp
    soomla::CCSoomlaError *err;
    soomla::CCStoreInventory::sharedStoreInventory()->buyItem("ConsumableItemId", &err);
    if (err != NULL) {
        int code = err->getCode();
        switch (code) {
        case SOOMLA_NO_ERROR:
            break;
        case SOOMLA_EXCEPTION_ITEM_NOT_FOUND:
            // itemNotFoundException was raised
            break;
        case SOOMLA_EXCEPTION_INSUFFICIENT_FUNDS:
            // insufficienFundsException was raised
            break;
        case SOOMLA_EXCEPTION_NOT_ENOUGH_GOODS:
            // notEnoughGoodsException was raised
            break;
        }
    }
```

### ・課金終了（課金が終わったら実行します）

```cpp
    soomla::CCStoreController::sharedStoreController()->storeClosing();
```

# まとめ
以上、簡単にですがSoomlaの導入方法についてまとめてみました。
実際にはこれに加えてiOSとAndroid双方でストアライブラリの設定が必要になりますので、各ストアのドキュメントを参考にしてください。


# お仕事募集中です
現在フリーランスで活動中。
iPhone/Androidアプリ開発、Web開発についてのご依頼・ご相談お受けしてます。
特にcocos2d-xでゲームのお仕事ありましたらぜひ！！

https://www.facebook.com/katsunori.yoshisue