アプリストアのレシート はデバイスのローカルストレージに保管されており、以下のようにして読むことができます。
var builder = ConfigurationBuilder.Instance(StandardPurchasingModule.Instance());
string receipt = builder.Configure<IAppleConfiguration>().appReceipt;
アプリ内課金はデバイスの設定で制限されている場合があります。以下のようにして、確認できます。
var builder = ConfigurationBuilder.Instance(StandardPurchasingModule.Instance());
bool canMakePayments = builder.Configure<IAppleConfiguration>().canMakePayments;
Apple のプラットフォーム上では、前回のトランザクションを取得するには、リストアするかどうかのボタンを表示して、ユーザーからパスワードを入力してもらわなくてはなりません。トランザクションの復元中、IStoreListener
の ProcessPurchase
は、ユーザーがすでに所有しているアイテムすべてに実行されます。
/// <summary>
/// OnInitialized の IStoreListener 実装
/// </summary>
public void OnInitialized(IStoreController controller, IExtensionProvider extensions)
{
extensions.GetExtension<IAppleExtensions> ().RestoreTransactions (result => {
if (result) {
// なにかがリストアされたというわけではありません
// 単に復元の処理が終了したということです
} else {
// 復元失敗
}
});
}
Apple はサーバーから新しい App Receipt を取得する方法を提供しています。通常、ローカルストレージに現在キャッシュされているレシートがない場合に使用されます: SKReceiptRefreshRequest。
この方法にはパスワードが必要だということに気を付けてください。
Unity IAP では以下のようにこのメソッドを使用します。
/// <summary>
/// OnInitialized の IStoreListener 実装
/// </summary>
public void OnInitialized(IStoreController controller, IExtensionProvider extensions)
{
extensions.GetExtension<IAppleExtensions> ().RefreshAppReceipt (receipt => {
// リクエストが成功したら、このハンドラーが呼び出されます
// レシートは最新のアプリレシート
Console.WriteLine(receipt);
},
() => {
// リクエストが失敗したら、このハンドラーが呼び出されます。
// 例えば、ネットワークが使用不可であったり、
// ユーザーが誤ったパスワードを入力した場合など。
});
}
iOS 8 からペアレンタルコントロールに Ask to Buy (承認と購入のリクエスト) と呼ばれる新しい機能が追加されました。
Ask to Buy を使った購入では、保護者の承認を待機します。このとき、Unity IAP は以下のようにアプリケーションに通知を送信します。
/// Unity IAP の初期化が終了すると、以下が呼び出されます。
public void OnInitialized(IStoreController controller, IExtensionProvider extensions)
{
extensions.GetExtension<IAppleExtensions>().RegisterPurchaseDeferredListener(product => {
Console.WriteLine(product.definition.id);
});
}
When the purchase is approved or rejected, your store’s normal ProcessPurchase
or OnPurchaseFailed
listener methods are invoked.
Sometimes consumable Ask to Buy purchases don’t show up in the App Receipt, in which case you cannot validate them using that receipt. However, iOS provides a Transaction Receipt that contains all purchases, including Ask to Buy. Access the most recent Transaction Receipt string for a given Product
using IAppleExtensions
.
注意: トランザクションレシートは Mac ビルドには使用できません。Mac ビルドでトランザクションレシートを要求すると、空の文字列が返されます。
# if UNITY_PURCHASING
using System;
using UnityEngine;
using UnityEngine.Purchasing;
public class AskToBuy : MonoBehaviour, IStoreListener
{
// Unity IAP オブジェクト
private IStoreController m_Controller;
private IAppleExtensions m_AppleExtensions;
public AskToBuy ()
{
var builder = ConfigurationBuilder.Instance (StandardPurchasingModule.Instance ());
builder.AddProduct ("100_gold_coins", ProductType.Consumable, new IDs {
{ "100_gold_coins_google", GooglePlay.Name },
{ "100_gold_coins_mac", MacAppStore.Name }
});
UnityPurchasing.Initialize (this, builder);
}
/// <summary>
/// Unity IAP の初期化が終了すると以下が呼び出されます
/// </summary>
public void OnInitialized (IStoreController controller, IExtensionProvider extensions)
{
m_Controller = controller;
m_AppleExtensions = extensions.GetExtension<IAppleExtensions> ();
// Apple プラットフォームでは、Apple の Ask to Buy 機能を使った待機後の購入を処理するに対応する必要があります
// Apple 以外のプラットフォームでは、 何も効力がありません。OnDeferred が呼び出されることはありません。
m_AppleExtensions.RegisterPurchaseDeferredListener (OnDeferred);
}
/// <summary>
/// 購入が終了すると以下が呼び出されます
/// </summary>
public PurchaseProcessingResult ProcessPurchase (PurchaseEventArgs e)
{
if (Application.platform == RuntimePlatform.IPhonePlayer ||
Application.platform == RuntimePlatform.tvOS) {
string transactionReceipt = m_AppleExtensions.GetTransactionReceiptForProduct (e.purchasedProduct);
Console.WriteLine (transactionReceipt);
// 検証のために、トランザクションレシートをサーバーに送信します
}
return PurchaseProcessingResult.Complete;
}
/// <summary>
/// Unity IAP に解決できない初期化エラーが発生すると呼び出されます
///
/// インターネットが使用できない場合は、これは呼び出されません。
///Unity IAP は使用可能になるまで、初期化を試みます。
/// </summary>
public void OnInitializeFailed (InitializationFailureReason error)
{
}
/// <summary>
/// 購入が失敗すると呼び出されます
/// </summary>
public void OnPurchaseFailed (Product i, PurchaseFailureReason p)
{
}
/// <summary>
/// iOS 特有
///購入が子供によってリクエストされ、保護者の承認が必要な場合に
/// Apple の Ask to Buy 機能の一部として
/// 呼び出されます
///
///購入が承認か拒否をされると、
/// 通常のイベントが発生します
/// </summary>
/// <param name="item">item</param>
private void OnDeferred (Product item)
{
Debug.Log ("Purchase deferred: " + item.definition.id);
}
}
# endif // UNITY_PURCHASING
アプリストアのレシートとは異なり、トランザクションレシートをローカルで検証することはできません。代わりに、検証のためにレシートの文字列をリモートサーバーに送信する必要があります。 すでにリモートサーバーを使用してアプリストアのレシートを検証している場合は、トランザクションレシートを同じ Apple エンドポイントに送信して JSON 応答を受信します。
JSON 応答の例
{
"receipt": {
"original_purchase_date_pst": "2017-11-15 15:25:20 America/Los_Angeles",
"purchase_date_ms": "1510788320209",
"unique_identifier": "0ea7808637555b2c633eb07aa1cb0894c821a6f9",
"original_transaction_id": "1000000352597239",
"bvrs": "0",
"transaction_id": "1000000352597239",
"quantity": "1",
"unique_vendor_identifier": "01B57C2E-9E91-42FF-9B0D-4983175D6694",
"item_id": "1141751870",
"original_purchase_date": "2017-11-15 23:25:20 Etc/GMT",
"product_id": "100.gold.coins",
"purchase_date": "2017-11-15 23:25:20 Etc/GMT",
"is_trial_period": "false",
"purchase_date_pst": "2017-11-15 15:25:20 America/Los_Angeles",
"bid": "com.unity3d.unityiap.demo",
"original_purchase_date_ms": "1510788320209"
},
"status": 0
}
Apple は、開発者がアプリケーションのプロダクトページを通して ゲーム内購入 を促進することを許可しています。従来のアプリ内購入とは異なり、Apple のプロモーション購入は iOS および tvOS の App Store から直接開始されます。その後、App Store はアプリケーションを起動してトランザクションを完了するか、アプリケーションがインストールされていない場合はそれをダウンロードするようにユーザーに促します。
The IAppleConfiguration
SetApplePromotionalPurchaseInterceptor
callback method intercepts Apple promotional purchases. Use this callback to present parental gates, send analytics events, or perform other functions before sending the purchase to Apple. The callback uses the Product
that the user attempted to purchase. You must call IAppleExtensions.ContinuePromotionalPurchases()
to continue with the promotional purchase. This will initiate any queued-up payments.
If you do not set the callback, promotional purchases go through immediately and call ProcessPurchase
with the result.
注意: 他のプラットフォームでこれらの API を呼び出しても効果はありません。
private IAppleExtensions m_AppleExtensions;
public void Awake() {
var module = StandardPurchasingModule.Instance();
var builder = ConfigurationBuilder.Instance(module);
// iOS と tvOS で、App Store から直接行われるプロモーション購入を
// 遮ることができます。
// Apple 以外のプラットフォームでは、 何も効力がありません。
// OnPromotionalPurchase は呼び出されることはありません。
builder.Configure<IAppleConfiguration>().
SetApplePromotionalPurchaseInterceptorCallback(OnPromotionalPurchase);
Debug.Log("Setting Apple promotional purchase interceptor callback");
}
public void OnInitialized(IStoreController controller, IExtensionProvider extensions) {
m_AppleExtensions = extensions.GetExtension<IAppleExtensions>();
foreach (var item in controller.products.all) {
if (item.availableToPurchase) {
// ユーザーの App Store でこれらすべてのプロダクトを表示します
m_AppleExtensions.SetStorePromotionVisibility(item, AppleStorePromotionVisibility.Show);
}
}
}
private void OnPromotionalPurchase(Product item) {
Debug.Log("Attempted promotional purchase: " + item.definition.id);
// プロモーション購入が検知されます。
// このイベントは、例えばペアレンタルゲートなどを
// 設けることによって処理します。
// ここでは、デモの目的で、購入を継続する前に 5秒間待機することにします。
StartCoroutine(ContinuePromotionalPurchases());
}
private IEnumerator ContinuePromotionalPurchases() {
Debug.Log("Continuing promotional purchases in 5 seconds");
yield return new WaitForSeconds(5);
Debug.Log("Continuing promotional purchases now");
m_AppleExtensions.ContinuePromotionalPurchases (); // iOS と tvOS のみ
}
Apple ストアでテストをするには ITunes Connect でテストアカウントを作成し、そのテストアカウントで iTunes に接続しなければいけません。
iOS デバイスやラップトップで App Store からサインアウトしてアプリを起動すると、課金やリストアを行うときにログインするよう求められます。
NoProductsAvailable
が原因で初期化に失敗したときは以下の内容を確認してください。
Unity のビルド設定で Mac のスタンドアロン用に Mac App Store validation
にチェックを入れておく必要があります。
アプリをビルドしたら、info.plist のバンドル ID とバージョン設定を更新する必要があります。.app
ファイル上で右クリックして パッケージの内容を表示
を選択し、info.plist
ファイルの CFBundleIdentifier
の値をアプリのバンドル ID へと変更します。
そして署名をした後に、パッケージとアプリをインストールします。そのための操作は Mac OSX 上のターミナルで行います。
codesign -f --deep -s "3rd Party Mac Developer Application: " your.app/Contents/Plugins/unitypurchasing.bundle
codesign -f --deep -s "3rd Party Mac Developer Application: " your.app
productbuild --component your.app /Applications --sign "3rd Party Mac Developer Installer: " your.pkg
バンドルに署名するには、Contents.meta ファイルが存在する場合、まずこれを削除する必要があります。
your.app/Contents/Plugins/unitypurchasing.bundle/Contents.meta
正しくパッケージをインストールするには、新しく作成したパッケージを実行する前にパッケージ化していない .app ファイルを削除しておく必要があります。
そして、アプリケーションフォルダーからアプリを起動します。初回は iTunes アカウントの詳細を入力するよう求められるので、iTunes Connect のテストアカウントでログインします。これでサンドボックス環境でテスト購入を行うことができます。