facebook twitter hatena line email

Unity/課金/サンプル

提供: 初心者エンジニアの簡易メモ
2020年7月13日 (月) 02:39時点におけるAdmin (トーク | 投稿記録)による版 (全部コードで処理する場合)

移動: 案内検索

都度購入

Androidの場合

  1. GooglePlayDeveloper/指定アプリ/ストアで表示/アプリ内サービス/管理対象のアイテム/管理対象のアイテム作成
  2. プロダクトidを(stone10)などで入れる(storeと連携してないと、購入ボタンを押しても商品が無いとなる)
  3. 有効にするを選択して、有効になっていることを確認

日本語を追加した場合は、日本語の説明も入れないと、保存されないので気を付ける。

iOSの場合

  1. ituneconnect管理画面/app内課金/管理/+をクリック
  2. 消耗型を選択し、id(stone10)などを入れてく
  3. 審査用の画像は( 640 x 920)で登録すればよい
  4. ituneconnectから契約を選択して、有料Appの利用規約に同意
  5. 口座情報を入れる(ゆうちょなら"Japan Post Bank"で"9900-[口座番号]"
  6. 納税にアメリカ納税情報を入れる
  7. 納税情報を入れたところOnInitializeFailed(NoProductsAvailable)の失敗イベントが呼ばれなくなり、正常にOnInitializedが呼ばれるようになった^^
"Type of Income"は"Income from the sale of applications"
Capacity in which acting欄に "Self"

参考:https://re35.org/release-ios-app/

参考:http://lab.studioheat.com/?p=335

定額課金

Androidの場合

  1. GooglePlayDeveloper/指定アプリ/ストアで表示/アプリ内サービス/定期購入
  2. プロダクトidを(com.example.hogeapp.monthly)などで入れる(storeと連携してないと、購入ボタンを押しても商品が無いとなる)
  3. 有効にするを選択して、有効になっていることを確認

日本語を追加した場合は、日本語の説明も入れないと、保存されないので気を付ける。

iOSの場合

  1. ituneconnect管理画面/app内課金/管理/+をクリック
  2. 自動更新サブスクリプションを追加(自動更新サブスクリプションがない場合は、ユーザ権限のとこの有料Appの契約とアメリカ納税情報が入ってるか確認する)

Unityから課金用ボタン設定

課金の記述方法として以下2パターンがある

  • 全部コードで処理する方法
  • コードレス処理がある。

全部コードで処理する場合

  1. 以下課金呼び出しコードを記述(例:stone10はproductID)
UnityIAPManager manager;
manager = new UnityIAPManager();
manager.OnPurchaseClicked("stone10");

UnityIAPManager.cs

#if UNITY_PURCHASING

#if UNITY_ANDROID || UNITY_IPHONE || UNITY_STANDALONE_OSX || UNITY_TVOS
// You must obfuscate your secrets using Window > Unity IAP > Receipt Validation Obfuscator
// before receipt validation will compile in this sample.
#define RECEIPT_VALIDATION
#endif

using UnityEngine;
using UnityEngine.Purchasing;

#if RECEIPT_VALIDATION
using UnityEngine.Purchasing.Security;
#endif

public class UnityIAPManager : IStoreListener
{
    private IStoreController controller;
    private IExtensionProvider extensions;

    public UnityIAPManager()
    {
        var builder = ConfigurationBuilder.Instance(StandardPurchasingModule.Instance());
        builder.AddProduct("stone10", ProductType.Consumable);
        UnityPurchasing.Initialize(this, builder);
    }

    /// <summary>
    /// Unity IAP が購入処理を行える場合に呼び出されます
    /// </summary>
    public void OnInitialized(IStoreController controller, IExtensionProvider extensions)
    {
        this.controller = controller;
        this.extensions = extensions;
        Debug.Log("UnityIAPManager OnInitialized");
        foreach (var product in controller.products.all)
        {
            Debug.Log("Title=" + product.metadata.localizedTitle);
            Debug.Log("Description=" + product.metadata.localizedDescription);
            Debug.Log("PriceString=" + product.metadata.localizedPriceString);
        }
    }

    /// <summary>
    ///  Unity IAP 回復不可能な初期エラーに遭遇したときに呼び出されます。
    ///
    /// これは、インターネットが使用できない場合は呼び出されず、
    /// インターネットが使用可能になるまで初期化を試みます。
    /// </summary>
    public void OnInitializeFailed(InitializationFailureReason error)
    {
        Debug.Log("OnInitializeFailed");
    }

    /// <summary>
    /// 購入が終了したときに呼び出されます。
    ///
    ///  OnInitialized() 後、いつでも呼び出される場合があります。
    /// </summary>
    public PurchaseProcessingResult ProcessPurchase(PurchaseEventArgs e)
    {
        Debug.Log("PurchaseProcessingResult " + e.purchasedProduct.metadata.localizedTitle);
        bool validPurchase = true; // R.V. のないプラットフォームに有効です

        // Unity IAP の検証ロジックはこれらのプラットフォームにのみ含まれます。
#if UNITY_ANDROID || UNITY_IOS || UNITY_STANDALONE_OSX
        // エディターの難読化ウィンドウで準備した機密を持つ
        // バリデーターを準備します。

#if RECEIPT_VALIDATION
        Debug.Log("RECEIPT_VALIDATION");
        string appIdentifier;
#if UNITY_5_6_OR_NEWER
        appIdentifier = Application.identifier;
        Debug.Log("5.6 appIdentifier=" + appIdentifier);
#else
        appIdentifier = Application.bundleIdentifier;
        Debug.Log("other appIdentifier=" + appIdentifier);
#endif
        var validator = new CrossPlatformValidator(GooglePlayTangle.Data(), AppleTangle.Data(), appIdentifier);

        try
        {
            // Google Play で、result は 1 つの product ID を取得します
            // Apple stores で、receipts には複数のプロダクトが含まれます
            var result = validator.Validate(e.purchasedProduct.receipt);
            // 情報提供の目的で、ここにレシートをリストします
            Debug.Log("Receipt is valid. Contents:");
            foreach (IPurchaseReceipt productReceipt in result)
            {
                Debug.Log("Receipt productID=" + productReceipt.productID);
                Debug.Log("Receipt purchaseDate=" + productReceipt.purchaseDate);
                Debug.Log("Receipt transactionID=" + productReceipt.transactionID);

                GooglePlayReceipt google = productReceipt as GooglePlayReceipt;
                if (null != google)
                {
                    // ここに Google のオーダー ID
                    //  sandbox でテストする場合は null にするように注意
                    // なぜなら、Google の sandbox はオーダー IDを発行しないため
                    Debug.Log("google.transactionID=" + google.transactionID);
                    Debug.Log("google.purchaseState=" + google.purchaseState);
                    Debug.Log("google.purchaseToken=" + google.purchaseToken);
                }

                AppleInAppPurchaseReceipt apple = productReceipt as AppleInAppPurchaseReceipt;
                if (null != apple)
                {
                    Debug.Log("apple.originalTransactionIdentifier=" + apple.originalTransactionIdentifier);
                    Debug.Log("apple.subscriptionExpirationDate=" + apple.subscriptionExpirationDate);
                    Debug.Log("apple.cancellationDate=" + apple.cancellationDate);
                    Debug.Log("apple.quantity=" + apple.quantity);
                }
            }
        }
        catch (IAPSecurityException)
        {
            Debug.Log("Invalid receipt, not unlocking content");
            validPurchase = false;
        }
#endif
#endif

        if (validPurchase)
        {
            // 適当なコンテンツをここにアンロックします
        }

        return PurchaseProcessingResult.Complete;
    }

    /// <summary>
    /// 購入が失敗したときに呼び出されます。
    /// </summary>
    public void OnPurchaseFailed(Product i, PurchaseFailureReason p)
    {
        Debug.Log("OnPurchaseFailed product=" + i.ToString());
        if (p == PurchaseFailureReason.PurchasingUnavailable)
        {
            // デバイス設定で IAP が無効である場合があります。
        }
    }
    public void OnPurchaseClicked(string productId)
    {
        Debug.Log("OnPurchaseClicked productId=" + productId);
        if (controller != null)
        {
            controller.InitiatePurchase(productId);
        }
    }
}
#endif // UNITY_PURCHASING

処理ログ

// 購入初期化
07-12 22:25:15.646 19383 19444 I Unity   : UnityIAPManager OnInitialized
07-12 22:25:15.664 19383 19444 I Unity   : Title=This is stone10 (Flick Typing input practice app)
07-12 22:25:15.681 19383 19444 I Unity   : Description=This is stone10!!
07-12 22:25:15.698 19383 19444 I Unity   : PriceString=¥100
// 購入確認
07-12 22:25:17.046 19383 19444 I Unity   : OnPurchaseClicked productId=stone10
// 購入後
07-12 22:25:27.994 19383 19444 I Unity   : PurchaseProcessingResult This is stone10 (Flick Typing input practice app)
07-13 01:15:54.698 31878 31955 I Unity   : RECEIPT_VALIDATION
07-13 01:15:54.715 31878 31955 I Unity   : 5.6 appIdentifier=com.example.hogeapp
07-13 01:28:23.648  1078  1232 I Unity   : Receipt is valid. Contents:
07-13 01:28:23.659  1078  1232 I Unity   : Receipt productID=stone10
07-13 01:28:23.672  1078  1232 I Unity   : Receipt purchaseDate=07/12/2020 16:28:23
07-13 01:28:23.683  1078  1232 I Unity   : Receipt transactionID=GPA.3366-6958-2462-12345
07-13 02:36:40.517  5111  5247 I Unity   : google.transactionID=GPA.3366-6958-2462-12345
07-13 02:36:40.526  5111  5247 I Unity   : google.purchaseState=Purchased
07-13 02:36:40.534  5111  5247 I Unity   : google.purchaseToken=lahnjifjnlchkhmbjjlghhbn.AO-J1OyyXV_avfKglYJsff9pPoW_5sOC3YshbqKuj8fE52bAzgnVMjwtVCj45b97yDcg4CV5arAfDndgwo-CcgHTqJ_vMFNsjULWZOuS-6K3C1qXbeVLGh9qQ2cGdJUvgVJsy123456_

全部コードで処理する場合(その2)

こちらを使ってもいける。

https://gist.github.com/YoshihideSogawa/f7c118127ce50e593a5b4a12e8426d6e

  1. 上記をPurchaser.csで保存する
  2. Unityのヒエラルキーに新規Objectを作成し、適当な名前で、Purchaser.csをアタッチする

コードレスの場合

(未完成です)

  1. unityメニュー/windows/UnityIAP/CreateIAPButtonでボタンを作成する
  2. unityメニュー/windows/IAP Catalogをクリックし以下のような詳細データを入れる
id:monthlyなど
type:Subscription(自動課金)
  1. 作ったbuttonのプロパティのproductIdに先ほどいれたid(monthlyなど)いれる
  2. Assets/Plugins/UnityPurchasing/script/CodelessIAPStoreListener.csにイベントが発生するので確認する

参考

コードレスの場合の参考

http://it-happens.info/unity-purchase/

全部コードの場合の参考

https://docs.unity3d.com/ja/current/Manual/UnityIAPSettingUp.html

https://gist.github.com/YoshihideSogawa/f7c118127ce50e593a5b4a12e8426d6e

https://qiita.com/tetr4lab/items/50d6817065c0ce2c9f04

https://docs.google.com/presentation/d/1An-HVm72fukut6LJ6n6XL1ArtlPqek0Eb_CpyXHUfOY/edit#slide=id.g49a6ed640d_4_22