アプリストアのレシート はデバイスのローカルストレージに保管されており、以下のようにして読むことができます。
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 Store の新しいレシートを取得する方法 SKReceiptRefreshRequest を提供しています。これは通常、ローカルストレージに現在レシートがキャッシュされていない場合に使用されます。
この方法にはパスワードが必要だということに気を付けてください。
Unity IAP では以下のようにこのメソッドを使用します。
/// <summary>
/// OnInitialized の IStoreListener 実装
/// </summary>
public void OnInitialized(IStoreController controller, IExtensionProvider extensions)
{
extensions.GetExtension<IAppleExtensions> ().RefreshAppReceipt (receipt => {
// リクエストが成功したら、このハンドラーが呼び出されます
// レシートは最新の App Store レシート
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);
});
}
下のサンプルは Sandbox の App Store で Ask-to-Buy シミュレーションを使用可能にするために IAppleExtensions
にアクセスする方法を示しています。
using UnityEngine;
using UnityEngine.Purchasing;
public class AppleSimulateAskToBuy : MonoBehaviour {
public void SetSimulateAskToBuy(bool shouldSimulateAskToBuy) {
if (Application.platform == RuntimePlatform.IPhonePlayer) {
IAppleExtensions extensions = IAPButton.IAPButtonStoreManager.Instance.ExtensionProvider.GetExtension<IAppleExtensions>();
extensions.simulateAskToBuy = shouldSimulateAskToBuy;
}
}
}
購入が承認/拒否されると、ストアの通常の ProcessPurchase
/ OnPurchaseFailed
リスナーメソッドが呼び出されます。
消耗品の Ask to Buy 購入がアプリのレシートに表示されないことがあります。その場合は、レシートを使用してそれらを検証できません。ただし、iOSは、Ask to Buy を含むすべての購入のトランザクションレシートを提供します。IAppleExtensions
を使用して、Product
(プロダクト) の最新のトランザクションレシートの文字列にアクセスします。
注意: トランザクションレシートは 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 はアプリケーションを起動してトランザクションを完了するか、アプリケーションがインストールされていない場合はそれをダウンロードするようにユーザーに促します。
IAppleConfiguration
と SetApplePromotionalPurchaseInterceptorCallback
メソッドは、Apple のプロモーション購入を遮ります。購入を Apple に送信する前に、このコールバックを使用してペアレンタルゲートを設けたり、分析イベントを送信したり、他の機能を実行することができます。コールバックは、ユーザーが購入しようとした Product
(プロダクト) を使用します。プロモーション購入を続行するには、IAppleExtensions.ContinuePromotionalPurchases()
を呼び出す必要があります。これにより、待機中の支払いが開始されます。
コールバックを設定しない場合は、プロモーション購入は即座に通過し、ProcessPurchase
が呼びだされます。
注意: 他のプラットフォームでこれらの 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 の Build Settings > Player Settings で Mac の Mac App Store Validation
にチェックを入れておく必要があります。
アプリケーションをビルドしたら、バンドル ID とバージョン文字列で info.plist ファイルを更新します。.app
ファイル上で右クリックし、show package contents
を選択し、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 のテストアカウントでログインします。これでサンドボックス環境でテスト購入を行うことができます。