nirasan's tech blog

趣味や仕事の覚え書きです。Linux, Perl, PHP, Ruby, Javascript, Android, Cocos2d-x, Unity などに興味があります。

Unity で Android In App Billing Plugin を試す

はじめに

  • Unity の Android 用アプリ内課金プラグインとして実績のある prime31 の Android In App Billing Plugin を使って見たメモです。

公式ドキュメント

メモ

  • Google Developers にサインインしているアカウントだと購入ができないので、テストアカウントを別途作って端末に割り当ててテストする。
    • テストアカウントは Google Developers で登録する必要がある。
  • まずは GoogleIAB.init(string public_key) で初期化
    • public_key には Google Developer Console で確認できる公開鍵を文字列で指定。
    • init に成功すると GoogleIABManager.billingSupportedEvent が発火する。失敗すると billingSupportedEvent が発火する。
  • init 成功後、GoogleIAB.queryInventory(string[] skus) で商品情報のリストを入手できる
    • skus には商品ID文字列のリストを渡す
    • queryInventory に成功すると GoogleIABManager.queryInventorySucceededEvent が発火し、商品情報のリストが手に入るので、これを元にショップ画面などを作成する。
    • queryInventory に失敗すると GoogleIABManager.queryInventoryFailedEvent が発火する。
  • 課金は Google Play にアップロードしているバージョンの apk でないと動かない。

デモ

  • プラグインをインポートすると Assets/Plugins/InAppBillingAndroid/demo にデモ用のシーンが出来る
  • IABUIManager.cs はボタンを表示して、GoogleIAB.init, queryInventory, purchaseProduct などのイベントの起動を行う
  • GoogleIABEventListener.cs は各種コールバックメソッドの宣言と GoogleIABManager への登録を行う

apk の作成

  • アプリ内課金をするには適切な apk を作成して Google Play Developer Console に登録する必要がある
  • 主に必要な設定は以下の二点

マニフェストの設定

  • 別の Asset の影響か、In App Billing Plugin を入れただけだと AndroidManifest.xml が課金できる状態になっていなかった。
  • AndroidManifest は Assets/Plugins/Android/AndroidManifest にあるので、この中の 要素の子要素として、プラグイン用のマニフェストである Assets/Plugins/InAppBillingAndroid/Manifest に記載してある内容を追記する。

apk の署名と作成

Google Play Developer Console で課金アイテムの登録

  • アプリの追加をし、apk のアップロードを行い、アプリ内アイテムの登録を行う。
  • アプリ内アイテムのステータスは「有効」に。(アプリ自体がドラフト状態なら公開はされません)
  • 購入テストのため、テスト用のアカウントを別途作成し、「テスト用のアクセス権がある Gmail アカウント」に登録。

購入シーンの実装

  • デモの GoogleIABEventListener を参考に、購入シーンを実装。
  • NGUI を使い課金アイテム一覧ウィンドウを用意し、シーン開始時にアプリ内課金の初期化を行い、購入可能なアイテムの購入ボタンを並べて表示。
  • 以下はイベントの登録と初期化、購入ボタンの作成をするスクリプトです。課金アイテム一覧ウィンドウにアタッチして使う。
using UnityEngine;
using System;
using System.Collections;
using System.Collections.Generic;

public class IABAndroidScript : MonoBehaviour {

    // 購入ボタンを Prefab にしてインスペクターで割り当てる
    public GameObject PaymentButtonPrefab;

#if UNITY_ANDROID

    bool Initialized = false;
    string LicenseKey = "Google Play Developer Console からライセンスキーをコピペする";
    string[] Skus = { "登録したアプリ内課金アイテムのID" };

    void OnEnable()
    {
        // Listen to all events for illustration purposes
        GoogleIABManager.billingSupportedEvent += billingSupportedEvent;
        GoogleIABManager.billingNotSupportedEvent += billingNotSupportedEvent;
        GoogleIABManager.queryInventorySucceededEvent += queryInventorySucceededEvent;
        GoogleIABManager.queryInventoryFailedEvent += queryInventoryFailedEvent;
        GoogleIABManager.purchaseCompleteAwaitingVerificationEvent += purchaseCompleteAwaitingVerificationEvent;
        GoogleIABManager.purchaseSucceededEvent += purchaseSucceededEvent;
        GoogleIABManager.purchaseFailedEvent += purchaseFailedEvent;
        GoogleIABManager.consumePurchaseSucceededEvent += consumePurchaseSucceededEvent;
        GoogleIABManager.consumePurchaseFailedEvent += consumePurchaseFailedEvent;

        // 課金処理の初期化
        if (!Initialized) {
            GoogleIAB.init (LicenseKey);
            Initialized = true;
        }
    }


    void OnDisable()
    {
        // Remove all event handlers
        GoogleIABManager.billingSupportedEvent -= billingSupportedEvent;
        GoogleIABManager.billingNotSupportedEvent -= billingNotSupportedEvent;
        GoogleIABManager.queryInventorySucceededEvent -= queryInventorySucceededEvent;
        GoogleIABManager.queryInventoryFailedEvent -= queryInventoryFailedEvent;
        GoogleIABManager.purchaseCompleteAwaitingVerificationEvent += purchaseCompleteAwaitingVerificationEvent;
        GoogleIABManager.purchaseSucceededEvent -= purchaseSucceededEvent;
        GoogleIABManager.purchaseFailedEvent -= purchaseFailedEvent;
        GoogleIABManager.consumePurchaseSucceededEvent -= consumePurchaseSucceededEvent;
        GoogleIABManager.consumePurchaseFailedEvent -= consumePurchaseFailedEvent;
    }



    void billingSupportedEvent()
    {
        Debug.Log( "billingSupportedEvent" );

        // 初期化が成功したら課金アイテム一覧の取得
        GoogleIAB.queryInventory (Skus);
    }


    void billingNotSupportedEvent( string error )
    {
        Debug.Log( "billingNotSupportedEvent: " + error );
    }


    void queryInventorySucceededEvent( List<GooglePurchase> purchases, List<GoogleSkuInfo> skus )
    {
        Debug.Log( string.Format( "queryInventorySucceededEvent. total purchases: {0}, total skus: {1}", purchases.Count, skus.Count ) );
        Prime31.Utils.logObject( purchases );
        Prime31.Utils.logObject( skus );
        
        // 課金アイテム一覧から、購入ボタンの作成
        for (int i = 0, count = skus.Count; i < count; i++) {
            GoogleSkuInfo sku = skus [i];
            // 購入ボタンを、アイテム一覧ウィンドウの子要素として追加
            GameObject button = NGUITools.AddChild (this.gameObject, PaymentButtonPrefab);
            // 購入対象アイテムのIDを設定
            button.GetComponent<IABAndroidButtonScript> ().ProductId = sku.productId;
            // 購入ボタンのラベル変更
            button.GetComponentInChildren<UILabel> ().text = sku.title;
            // 購入ボタンの表示位置を設定 / 被らないように適当に並べる
            button.transform.localPosition = new Vector3 (0, i * -100);
        }
    }


    void queryInventoryFailedEvent( string error )
    {
        Debug.Log( "queryInventoryFailedEvent: " + error );
    }


    void purchaseCompleteAwaitingVerificationEvent( string purchaseData, string signature )
    {
        Debug.Log( "purchaseCompleteAwaitingVerificationEvent. purchaseData: " + purchaseData + ", signature: " + signature );
    }


    void purchaseSucceededEvent( GooglePurchase purchase )
    {
        Debug.Log( "purchaseSucceededEvent: " + purchase );
    }


    void purchaseFailedEvent( string error )
    {
        Debug.Log( "purchaseFailedEvent: " + error );
    }


    void consumePurchaseSucceededEvent( GooglePurchase purchase )
    {
        Debug.Log( "consumePurchaseSucceededEvent: " + purchase );
    }


    void consumePurchaseFailedEvent( string error )
    {
        Debug.Log( "consumePurchaseFailedEvent: " + error );
    }

#endif

}
using UnityEngine;
using System.Collections;

public class IABAndroidButtonScript : MonoBehaviour {

	public string ProductId;

	public void OnClick () {

		GoogleIAB.purchaseProduct (ProductId);
	}
}

動作確認

  • テストアカウントでログインしている端末を用意し、端末上でアプリを実行する