アプリストアのレシート はデバイスのローカルストレージに保管されており、以下のようにして読むことができます。
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 のテストアカウントでログインします。これでサンドボックス環境でテスト購入を行うことができます。
Did you find this page useful? Please give it a rating:
Thanks for rating this page!
What kind of problem would you like to report?
Thanks for letting us know! This page has been marked for review based on your feedback.
If you have time, you can provide more information to help us fix the problem faster.
Provide more information
You've told us this page needs code samples. If you'd like to help us further, you could provide a code sample, or tell us about what kind of code sample you'd like to see:
You've told us there are code samples on this page which don't work. If you know how to fix it, or have something better we could use instead, please let us know:
You've told us there is information missing from this page. Please tell us more about what's missing:
You've told us there is incorrect information on this page. If you know what we should change to make it correct, please tell us:
You've told us this page has unclear or confusing information. Please tell us more about what you found unclear or confusing, or let us know how we could make it clearer:
You've told us there is a spelling or grammar error on this page. Please tell us what's wrong:
You've told us this page has a problem. Please tell us more about what's wrong:
Thank you for helping to make the Unity documentation better!
Your feedback has been submitted as a ticket for our documentation team to review.
We are not able to reply to every ticket submitted.