PlayFab (レガシ エコノミー)、Unity IAP、Android の概要

Important

Economy v1 API はメンテナンス モードであり、新機能は受け取らず、バグ修正のみを受け取ります。 v1 API は、当面維持されます。 次のバージョンの PlayFab エコノミーの詳細については、「エコノミー v2 の概要」を参照してください。

このチュートリアルでは、PlayFab、Unity + IAP サービス、Android 課金 API を使用して、アプリ内購入 (IAP) を設定する方法を説明します。

開始の前に

特に異なるサービスがどのように統合および連動するかを把握していない場合、IAP の設定作業は退屈な場合があります。

以下の図は、Android 課金 API と PlayFab がどのように連動し、顧客に安定した IAP 体験を提供するかを示しています。

Android-PlayFab - PlayFab - 統合のタイムライン

まず、PlayMarket で製品 ID価格を設定します。 最初は、すべての製品が特定化されていません。プレイヤーが購入可能なデジタル エンティティであり、PlayFab プレイヤーにとって何の意味もありません。

これらのエンティティを有益化するには、PlayFab アイテム カタログでミラー化する必要があります。 これによって、特定化されていないエンティティがバンドル、コンテナー、個別のアイテムとなります。

それぞれに次のような独自の側面があります:

  • タイトル
  • 説明
  • Tags
  • types
  • Images
  • ビヘイビア によって特徴付けられます。

ID を共有することで、これらすべてがマーケットの製品にリンクされます。

購入可能な実際の金額のアイテムにアクセスする最適な方法は、GetCatalogItemsGetStoreItems を使用することです。 これらは自由通貨ストアで使用される API メソッドと同じであるため、プロセスには馴染みがあるはずです。

アイテムの ID は、PlayFab と外部 IAP システム間のリンクです。 したがって、IAP サービスにアイテム ID を渡します。

この時点で、購入プロセスが開始します。 プレイヤーが IAP インターフェイスと通信し、購入が成功すると、領収書を取得できます。

PlayFab はその後その領収書を検証し、購入を登録して、購入アイテムをプレイヤーに付与します。

これが、IAP 統合の仕組みの概要です。以下の例は、実際の動作の大部分を示しています。

クライアント アプリケーションを設定する

このセクションでは、非常に簡素なアプリケーションを構成し、PlayFab、UnityIAP、 Android 課金 API を使用した IAP をテストする方法を説明します。

前提条件:

  • Unity プロジェクト。
  • PlayFab SDK がインポートされ、タイトルに対して動作するように構成されていること。

まずは UnityIAP を設定します。

  1. [サービス] に移動します。
  2. [サービス] タブが選択されていることを確認してください。
  3. 自分の Unity サービスのプロフィールまたは組織を選択します。
  4. [作成] を選択します。

UnityIAP サービスを設定する

  1. 次に、[アプリ内購入 (IAP)] サービスに移動します。

UnityIAP サービスに移動する

  1. [Simplify cross-platform IAP (プラットフォーム間 IAP の簡素化)] の切り替えをオンにして、サービス を有効にします。

  2. 次に、[Continue (続ける)] を選択します。

UnityIAP サービスを有効化する

プラグインの一覧ページが表示されます。

  1. [Import (インポート)] を選択します。

UnityIAP サービス - プラグインのインポート

Uすべてのプラグインがインポートされる段階まで Unity のインストールとインポート手順を続行します。

  1. プラグインが揃っていることを確認してください。
  2. 次に AndroidIAPExample.cs という名前の新しいスクリプトを作成します。

UnityIAP 新しいスクリプトを作成する

AndroidIAPExample.cs以下に示すコードが含まれています (詳しくは、コードのコメントを参照してください)。

using PlayFab;
using PlayFab.ClientModels;
using PlayFab.Json;
using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Purchasing;

public class AndroidIAPExample : MonoBehaviour, IStoreListener {
    // Items list, configurable via inspector
    private List<CatalogItem> Catalog;

    // The Unity Purchasing system
    private static IStoreController m_StoreController;

    // Bootstrap the whole thing
    public void Start() {
        // Make PlayFab log in
        Login();
    }

    public void OnGUI() {
        // This line just scales the UI up for high-res devices
        // Comment it out if you find the UI too large.
        GUI.matrix = Matrix4x4.TRS(new Vector3(0, 0, 0), Quaternion.identity, new Vector3(3, 3, 3));

        // if we are not initialized, only draw a message
        if (!IsInitialized) {
            GUILayout.Label("Initializing IAP and logging in...");
            return;
        }

        // Draw menu to purchase items
        foreach (var item in Catalog) {
            if (GUILayout.Button("Buy " + item.DisplayName)) {
                // On button click buy a product
                BuyProductID(item.ItemId);
            }
        }
    }

    // This is invoked manually on Start to initiate login ops
    private void Login() {
        // Login with Android ID
        PlayFabClientAPI.LoginWithAndroidDeviceID(new LoginWithAndroidDeviceIDRequest() {
            CreateAccount = true,
            AndroidDeviceId = SystemInfo.deviceUniqueIdentifier
        }, result => {
            Debug.Log("Logged in");
            // Refresh available items
            RefreshIAPItems();
        }, error => Debug.LogError(error.GenerateErrorReport()));
    }

    private void RefreshIAPItems() {
        PlayFabClientAPI.GetCatalogItems(new GetCatalogItemsRequest(), result => {
            Catalog = result.Catalog;

            // Make UnityIAP initialize
            InitializePurchasing();
        }, error => Debug.LogError(error.GenerateErrorReport()));
    }

    // This is invoked manually on Start to initialize UnityIAP
    public void InitializePurchasing() {
        // If IAP is already initialized, return gently
        if (IsInitialized) return;

        // Create a builder for IAP service
        var builder = ConfigurationBuilder.Instance(StandardPurchasingModule.Instance(AppStore.GooglePlay));

        // Register each item from the catalog
        foreach (var item in Catalog) {
            builder.AddProduct(item.ItemId, ProductType.Consumable);
        }

        // Trigger IAP service initialization
        UnityPurchasing.Initialize(this, builder);
    }

    // We are initialized when StoreController and Extensions are set and we are logged in
    public bool IsInitialized {
        get {
            return m_StoreController != null && Catalog != null;
        }
    }

    // This is automatically invoked automatically when IAP service is initialized
    public void OnInitialized(IStoreController controller, IExtensionProvider extensions) {
        m_StoreController = controller;
    }

    // This is automatically invoked automatically when IAP service failed to initialized
    public void OnInitializeFailed(InitializationFailureReason error) {
        Debug.Log("OnInitializeFailed InitializationFailureReason:" + error);
    }

    // This is automatically invoked automatically when purchase failed
    public void OnPurchaseFailed(Product product, PurchaseFailureReason failureReason) {
        Debug.Log(string.Format("OnPurchaseFailed: FAIL. Product: '{0}', PurchaseFailureReason: {1}", product.definition.storeSpecificId, failureReason));
    }

    // This is invoked automatically when successful purchase is ready to be processed
    public PurchaseProcessingResult ProcessPurchase(PurchaseEventArgs e) {
        // NOTE: this code does not account for purchases that were pending and are
        // delivered on application start.
        // Production code should account for such case:
        // More: https://docs.unity3d.com/ScriptReference/Purchasing.PurchaseProcessingResult.Pending.html

        if (!IsInitialized) {
            return PurchaseProcessingResult.Complete;
        }

        // Test edge case where product is unknown
        if (e.purchasedProduct == null) {
            Debug.LogWarning("Attempted to process purchase with unknown product. Ignoring");
            return PurchaseProcessingResult.Complete;
        }

        // Test edge case where purchase has no receipt
        if (string.IsNullOrEmpty(e.purchasedProduct.receipt)) {
            Debug.LogWarning("Attempted to process purchase with no receipt: ignoring");
            return PurchaseProcessingResult.Complete;
        }

        Debug.Log("Processing transaction: " + e.purchasedProduct.transactionID);

        // Deserialize receipt
        var googleReceipt = GooglePurchase.FromJson(e.purchasedProduct.receipt);

        // Invoke receipt validation
        // This will not only validate a receipt, but will also grant player corresponding items
        // only if receipt is valid.
        PlayFabClientAPI.ValidateGooglePlayPurchase(new ValidateGooglePlayPurchaseRequest() {
            // Pass in currency code in ISO format
            CurrencyCode = e.purchasedProduct.metadata.isoCurrencyCode,
            // Convert and set Purchase price
            PurchasePrice = (uint)(e.purchasedProduct.metadata.localizedPrice * 100),
            // Pass in the receipt
            ReceiptJson = googleReceipt.PayloadData.json,
            // Pass in the signature
            Signature = googleReceipt.PayloadData.signature
        }, result => Debug.Log("Validation successful!"),
           error => Debug.Log("Validation failed: " + error.GenerateErrorReport())
        );

        return PurchaseProcessingResult.Complete;
    }

    // This is invoked manually to initiate purchase
    void BuyProductID(string productId) {
        // If IAP service has not been initialized, fail hard
        if (!IsInitialized) throw new Exception("IAP Service is not initialized!");

        // Pass in the product id to initiate purchase
        m_StoreController.InitiatePurchase(productId);
    }
}

// The following classes are used to deserialize JSON results provided by IAP Service
// Please, note that JSON fields are case-sensitive and should remain fields to support Unity Deserialization via JsonUtilities
public class JsonData {
    // JSON Fields, ! Case-sensitive

    public string orderId;
    public string packageName;
    public string productId;
    public long purchaseTime;
    public int purchaseState;
    public string purchaseToken;
}

public class PayloadData {
    public JsonData JsonData;

    // JSON Fields, ! Case-sensitive
    public string signature;
    public string json;

    public static PayloadData FromJson(string json) {
        var payload = JsonUtility.FromJson<PayloadData>(json);
        payload.JsonData = JsonUtility.FromJson<JsonData>(payload.json);
        return payload;
    }
}

public class GooglePurchase {
    public PayloadData PayloadData;

    // JSON Fields, ! Case-sensitive
    public string Store;
    public string TransactionID;
    public string Payload;

    public static GooglePurchase FromJson(string json) {
        var purchase = JsonUtility.FromJson<GooglePurchase>(json);
        purchase.PayloadData = PayloadData.FromJson(purchase.Payload);
        return purchase;
    }
}
  1. Code という名前の新しいゲームオブジェクトを作成します。
  2. そこに AndroidIAPExample コンポーネントを追加します (2 段階)。
  3. そこに AndroidIAPExample コンポーネントを追加します。
  4. 必ずシーンを保存してください。

UnityIAP ゲーム オブジェクトの例を作成する

最後に、[Build Settings (ビルド設定)] に移動します。

  1. シーンが [Scenes In Build (ビルド中のシーン)] エリアに追加されたことを確認します。
  2. [Android] プラットフォームが選択されていることを確認します。
  3. [プレイヤーの設定] エリアに移動します。
  4. [パッケージ名] を割り当てます。

注意

PlayMarket の競合を避けるために、独自のパッケージ名を付けてください。

UnityIAP ゲーム プロジェクトの例を追加する

最後に、通常どおりにアプリケーションをビルドし、APK が安全で適切であることを確認します。

まだテストをする方法はありません。 最初に、以下のセクションで説明するように、PlayMarket と PlayFab を構成する必要があります。

IAP に向けて PlayMarket アプリケーションを設定する

このセクションでは、PlayMarket アプリケーションで IAP を有効にする方法の詳細を説明します。

注意

アプリケーション自体の設定は、このチュートリアルの範囲外です。 すでにアプリケーションがあり、少なくともアルファ版のリリースとして公開できるように構成されていると想定しています。

PlayMarket アプリケーションを有効にする

便利なメモ

  • 実行するには APK をアップロードする必要があります。 前のセクションで構築した APK を使用してください。
  • APK のアップロードを求められたら、アルファ版またはベータ版のアプリケーションとしてそれをアップロードし、IAP サンドボックスを有効にします。
  • [コンテンツの規則] の構成には、アプリケーションでの IAP の有効化方法に関する質問が含まれます。
  • PlayMarket では、パブリッシャーによる IAP の使用またはテストが許容されません。そのため、テストの目的では別の Google アカウントを選択し、アルファ版/ベータ版のビルドのためのテスターとして追加してください。

アプリケーションのビルドを公開したら、以下を実行します。

  1. メニューから [In-app products (アプリ内製品)] を選択します。
    • [Merchant Account (販売者アカウント)] を求められた場合は、1 つをリンクするか作成します。
  2. [Add New Product (新しい製品の追加)] を選択します。

PlayMarket 新しい製品の追加

  1. 次に示す画面で、[Managed Product (管理されている製品)] を選択します。
  2. わかりやすい [製品 ID] を付けます。
  3. [続行] を選択します。

PlayMarket 製品 ID の追加

PlayMarket で、[Title (タイトル)] (1)[Description (説明)] (2) を入力するように求められます。 ただし、今回はあまり使用しません。

データ アイテムのデータのみを PlayFab サービスから取得し、一致する ID のみを必要とします。

PlayMarket 製品のタイトルと説明の追加

  1. さらにスクロールし、[Add a price (価格を追加)] を選択します。

PlayMarket 製品価格の追加

  1. 有効な価格を入力します (各国/地域に応じて、価格がどのように変換されるかに注意してください)。
  2. [Apply (適用)] を選択します。

PlayMarket 製品の追加と現地価格の適用

  1. 最後に、画面の一番上までスクロールし、アイテムのステータスを [Active (アクティブ)] に変更します。

PlayMarket 製品をアクティブにする

これでアプリの構成は完了ですが、いくつかの微調整が必要です。 まず、ライセンス キーを保存します (これは、PlayFab と PlayMarket とをリンクするために役立ちます)。

  1. メイン メニューの [Services & APIs (サービスと API)] に移動します。
  2. 次に、キーBase64 バージョンを見つけて保存します。

PlayMarket 製品ライセンス キーの保存

次の手順では、IAP のテストを有効にします。 アルファ版およびベータ版のビルドに対してサンドボックスは自動的に有効になりますが、アプリのテストのために承認されたアカウントを設定する必要があります。

  1. [ホーム] に移動します。
  2. 左側のメニューで、[Account details (アカウントの詳細)] を見つけて選択します。
  3. [License Testing (ライセンスのテスト)] エリアを見つけます。
  4. テスト アカウントが一覧にあることを確認します。
  5. [License Test Response (ライセンス テストの応答)]RESPOND_NORMALLY に設定されていることを確認します。

設定を適用することを忘れないでください。

PlayMarket IAP テストの有効化

PlayMarket 側の統合は、この時点で設定する必要があります。

PlayFab タイトルを設定する

最後の手順では、PlayFab タイトルを構成して製品を反映させ、Google 課金 API と統合します。

  1. [アドオン] を選択します。
  2. 次に、Google 追加コンテンツを選択します。

PlayFab Google 追加コンテンツを開く

  1. [パッケージ ID] に入力します。
  2. 前のセクションで取得した [Google App License Key (Google アプリのライセンス キー)] を入力します。
  3. [Install Google (Google のインストール)] を選択して変更を確定します。

PlayFab Google 追加コンテンツのインストール

次の手順では、PlayFab でゴールデン ソードのアイテムを反映させます。

  1. [Economy (エコノミー)] を選択します。
  2. [カタログ] サブタブが選択されていることを確認します。
  3. [New Catalog (新しいカタログ)] を選択します。
  4. カタログ バージョン名を指定します。
  5. [Save Catalog (カタログの保存)] を選択します。

PlayFab カタログの保存

カタログにアイテムがない場合、自動的に削除されます。 そのため、すべてのカタログには「One」というアイテムが事前に追加されています。

常に新しいアイテムを作成できますが、簡単にするために、「One」アイテムを変更します。

  1. アイテムを選択して、PlayMarket の ID に合わせて [アイテム ID] を編集します。
  2. 次に、[表示名] を編集し、[説明] を追加します。

注意

このデータは、PlayMarket アイテム タイトル説明 とは何の関係もないことに注意してください。完全に独立しています。

  1. アイテム[価格] を追加します。
  2. [Save Item (アイテムの保存)] を選択して変更を確定します。

PlayFab カタログ アイテムの編集と保存

注意

このチュートリアルでは、IAP は主に実際のお金での購入に言及しています。 そのため、特別な実際のお金の通貨である「RM」を使用します。 PlayFab の金額は US セントで定義されます。

  1. [アイテム ID] リストでアイテムを確認します。

PlayFab カタログ アイテム リスト

これで、PlayFab タイトルの設定が完了しました。

テスト

テスト目的で、アルファ版/ベータ版 リリースを使用してアプリをダウンロードします。

  • テスト アカウントと実際の Android デバイスを使用してください。
  • アプリを開始すると、IAP が初期化されたことがわかり、アイテムを表す 1 つのボタンが表示されます。
  • そのボタンを選択します。

アプリのテスト - ゴールデンソードの購入ボタン

IAP の購入が開始されます。 正常に購入が完了するまで、Google Play の指示に従います。

アプリのテスト - Google Play - 支払いの完了

最後に、PlayFab ゲーム マネージャーのダッシュボードでタイトルに移動し、[New Events (新しいイベント)] を見つけます。

ゲーム マネージャー ダッシュ ボードの新しいイベント

これは、購入が正常に提供、検証され、PlayFab エコシステムに接続されたことを意味します。

これで、UnityIAP と Android 課金 API を PlayFab アプリケーションに正常に統合できました。