Unityでは非常に簡単にアプリ内課金を実装することが出来ます。Asset等が有料で公開されていたりするのですが、今回はIAPというものを利用します。
無料で利用出来る上に、ひとつのコードで両OSに対応出来ます。
itunes Connectでアプリ内課金の作成
アプリ内課金を実装するためには、itunes connectでアプリを追加します。
機能 > App内課金でプラスマークを押してアプリ内課金を作成しましょう。
先ずは課金タイプを選択します。タイプ種類は、説明の通りです。
課金タイプを設定したら適宜情報を追加していきます。
製品IDは、アプリで呼び出す際に利用するので、わかりやすい名前にしましょう。
審査のためのスクリーンショットは、課金後の挙動がわかる画面をなんでも良いので設定しておきましょう。
設定ができたらSaveして、itunesConnect側での設定は完了です。
GooglePlay Developer Console(Android)でアプリ内課金の作成
Google Play Developer Consoleにアクセスして、+新しいアプリを追加からアプリ内課金を実装したいアプリを追加します。
Androidでは、課金アイテムを作成するためには、apkファイルを追加していなければいけません。なので先に課金のコードを書いてapkを作成するか、とりあえずの段階でapkを作成するかはどちらかやりやすい方を選択してください。
apkを追加出来たら、アプリ内アイテムに移動して、+新しいアイテムを追加をクリックします。
そしてら、アイテムのタイプと、アイテムのIDを選択します。
消費型も非消費型も、管理対象アイテムに当たります。定期購入型は、一定期間が過ぎたら自動で課金されるタイプです。
あとは、課金の情報や、価格を好きに設定しましょう。
Unity内でIAPのImport
参考https://unity3d.com/jp/learn/tutorials/topics/analytics/integrating-unity-iap-your-game
Unityを開いて、MenuのWindow < Servicesをクリックします。
何も設定していなければ、In-App PurchasingがOFFになっていると思います。
In-App Purchasingをクリックしたら、課金を有効にしたいのでEnableを押下します。
次に、アプリが13歳未満を対象にしているかそうでないかを聞かれるので選択します。子供用のアプリなら上を、そうでないなら下にチェックを入れます。
完了したら、Importします。
Unity内でIAPの実装
C#でプログラムを書いていきます。基本的公式のドキュメントを参考にしています。より詳しいプログラムの解説は公式のドキュメントを御覧ください。(全英語ですが...)
Purchaser.cs
using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Purchasing;
namespace CompleteProject
{
public class Purchaser : MonoBehaviour, IStoreListener
{
private static IStoreController m_StoreController;
private static IExtensionProvider m_StoreExtensionProvider;
// 消費型アイテムのID
public static string kProductIDConsumable = "life_max";
// 非消費型アイテムのID
public static string kProductIDNonConsumable = "unlimitedLife";
// ios AppのBundleId
private static string kProductNameAppleSubscription = "com.test.Game";
// Android AppのBundleId
private static string kProductNameGooglePlaySubscription = "com.test.Game";
void Start()
{
if (m_StoreController == null)
{
InitializePurchasing();
}
}
public void InitializePurchasing()
{
if (IsInitialized())
{
return;
}
var builder = ConfigurationBuilder.Instance(StandardPurchasingModule.Instance());
#if UNITY_ANDROID
builder.Configure().SetPublicKey("公開鍵");
kProductIDNonConsumable = "unlimited_life";
#endif
builder.AddProduct(kProductIDConsumable, ProductType.Consumable);
builder.AddProduct(kProductIDNonConsumable, ProductType.NonConsumable);
UnityPurchasing.Initialize(this, builder);
}
private bool IsInitialized()
{
return m_StoreController != null && m_StoreExtensionProvider != null;
}
public void BuyConsumable()
{
BuyProductID(kProductIDConsumable);
}
public void BuyNonConsumable()
{
BuyProductID(kProductIDNonConsumable);
}
void BuyProductID(string productId)
{
if (IsInitialized())
{
Product product = m_StoreController.products.WithID(productId);
if (product != null && product.availableToPurchase)
{
Debug.Log(string.Format("Purchasing product asychronously: '{0}'", product.definition.id));
m_StoreController.InitiatePurchase(product);
}
else
{
Debug.Log("BuyProductID: FAIL. Not purchasing product, either is not found or is not available for purchase");
}
}
// Otherwise ...
else
{
Debug.Log("BuyProductID FAIL. Not initialized.");
}
}
public void RestorePurchases()
{
if (!IsInitialized ()) {
return;
}
if (Application.platform == RuntimePlatform.IPhonePlayer ||
Application.platform == RuntimePlatform.OSXPlayer)
{
var apple = m_StoreExtensionProvider.GetExtension();
apple.RestoreTransactions((result) => {
Debug.Log("RestorePurchases continuing: " + result + ". If no further messages, no purchases available to restore.");
});
}
// Otherwise ...
else
{
Debug.Log("RestorePurchases FAIL. Not supported on this platform. Current = " + Application.platform);
}
}
//
// --- IStoreListener
//
public void OnInitialized(IStoreController controller, IExtensionProvider extensions)
{
Debug.Log("OnInitialized: PASS");
m_StoreController = controller;
m_StoreExtensionProvider = extensions;
}
// 接続処理失敗の時(ネットーワーク不良等)
public void OnInitializeFailed(InitializationFailureReason error)
{
Debug.Log("OnInitializeFailed InitializationFailureReason:" + error);
}
// 決済成功時
public PurchaseProcessingResult ProcessPurchase(PurchaseEventArgs args)
{
if (String.Equals (args.purchasedProduct.definition.id, kProductIDNonConsumable, StringComparison.Ordinal)) {
Debug.Log (string.Format ("ProcessPurchase: PASS. Product: '{0}'", args.purchasedProduct.definition.id));
} else {
Debug.Log("PurchaseProcessingResult Else");
}
return PurchaseProcessingResult.Complete;
}
// 決済失敗時
public void OnPurchaseFailed(Product product, PurchaseFailureReason failureReason)
{
Debug.Log(string.Format("OnPurchaseFailed: FAIL. Product: '{0}', PurchaseFailureReason: {1}", product.definition.storeSpecificId, failureReason));}
}
}
スクリプトが作り終えたら、決済が発生するボタンにアタッチします。そして、OnClickに消費型ならBuyConsumable、非消費型ならBuyNonConsumableを適用させてください。
以上で実装は終了です。
アプリ内課金テスト方法
iosの場合
itunes connectでテストユーザーの登録をします。topからユーザーと役割に移動してください。
SandBoxテスターを追加します。追加したら、確認メールが届いているので必ず確認してください。
実機の設定からログインされているAppIDをSandBoxで登録したテストユーザーに変更します。
ログイン出来れば、テストが出来る状態なのでアプリを実行して見てください。
Androidの場合
Androidでテストするのは少し面倒で、β版で公開してからではないとテスト出来ません。今回は、クローズド ベータ版テストを行います。クローズドベータ版テストを設定をクリックしてください。
テスターのリストを作成します。
β版が公開されると、apkをアプうロードした場所にオプトインURLというものが発行されるので、そこからアプリをインストールしてテストを実行してください。
さいごに
アプリ内課金を調べると有料のAssetsの使い方ばかり出てきて、手を出しがちですががんばれば何でも無料で出来るということを忘れないで下さい。そして、これならそんなに頑張んなくてもできるので一度挑戦してみてください!出来なかったらコメントや問い合わせフォームからでも質問してください。