一个 应用收据 存储在设备的本地存储中,并且可以按如下方式读取
var builder = ConfigurationBuilder.Instance(StandardPurchasingModule.Instance());
string receipt = builder.Configure<IAppleConfiguration>().appReceipt;
应用程序内购买可能会因设备设置而受到限制,可以按如下方式进行检查
var builder = ConfigurationBuilder.Instance(StandardPurchasingModule.Instance());
bool canMakePayments = builder.Configure<IAppleConfiguration>().canMakePayments;
在苹果平台上,用户必须输入他们的密码才能检索之前的交易,因此您的应用程序必须向用户提供一个按钮让他们这样做。此过程中,IStoreListener 的 ProcessPurchase 方法将为用户已有的任何项目调用。
/// <summary>
/// Your IStoreListener implementation of OnInitialized.
/// </summary>
public void OnInitialized(IStoreController controller, IExtensionProvider extensions)
{
extensions.GetExtension<IAppleExtensions> ().RestoreTransactions (result => {
if (result) {
// This does not mean anything was restored,
// merely that the restoration process succeeded.
} else {
// Restoration failed.
}
});
}
苹果提供了一种从其服务器获取新的应用收据的机制,通常在本地存储中没有缓存收据时使用;SKReceiptRefreshRequest。
请注意,这会提示用户输入他们的密码。
Unity IAP 以如下方式提供此方法
/// <summary>
/// Your IStoreListener implementation of OnInitialized.
/// </summary>
public void OnInitialized(IStoreController controller, IExtensionProvider extensions)
{
extensions.GetExtension<IAppleExtensions> ().RefreshAppReceipt (receipt => {
// This handler is invoked if the request is successful.
// Receipt will be the latest app receipt.
Console.WriteLine(receipt);
},
() => {
// This handler will be invoked if the request fails,
// such as if the network is unavailable or the user
// enters the wrong password.
});
}
iOS 8 引入了一个称为 询购买 的新家长控制功能。
询问购买购买会推迟到征得父母同意。发生这种情况时,Unity IAPUnity 应用内购买的缩写
参见 术语表 按如下方式向您的应用发送通知
/// This is called when Unity IAP has finished initialising.
public void OnInitialized(IStoreController controller, IExtensionProvider extensions)
{
extensions.GetExtension<IAppleExtensions>().RegisterPurchaseDeferredListener(product => {
Console.WriteLine(product.definition.id);
});
}
以下示例类演示了如何访问 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 侦听器方法。
有时可消耗的询问购买不会显示在应用收据中,在这种情况下,您无法使用该收据对其进行验证。但是,iOS 提供了一个包含所有购买(包括询问购买)的交易收据。使用 IAppleExtensions 访问给定 Product 的最新交易收据字符串。
注意:交易收据对于 Mac 构架不可用。在 Mac 构架上请求交易收据将导致一个空字符串。
#if UNITY_PURCHASING
using System;
using UnityEngine;
using UnityEngine.Purchasing;
public class AskToBuy : MonoBehaviour, IStoreListener
{
// Unity IAP objects
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>
/// This will be called when Unity IAP has finished initialising.
/// </summary>
public void OnInitialized (IStoreController controller, IExtensionProvider extensions)
{
m_Controller = controller;
m_AppleExtensions = extensions.GetExtension<IAppleExtensions> ();
// On Apple platforms we need to handle deferred purchases caused by Apple's Ask to Buy feature.
// On non-Apple platforms this will have no effect; OnDeferred will never be called.
m_AppleExtensions.RegisterPurchaseDeferredListener (OnDeferred);
}
/// <summary>
/// This will be called when a purchase completes.
/// </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);
// Send transaction receipt to server for validation
}
return PurchaseProcessingResult.Complete;
}
/// <summary>
/// Called when Unity IAP encounters an unrecoverable initialization error.
///
/// Note that this will not be called if Internet is unavailable; Unity IAP
/// will attempt initialization until it becomes available.
/// </summary>
public void OnInitializeFailed (InitializationFailureReason error)
{
}
/// <summary>
/// Called when a purchase fails.
/// </summary>
public void OnPurchaseFailed (Product i, PurchaseFailureReason p)
{
}
/// <summary>
/// iOS Specific.
/// This is called as part of Apple's 'Ask to buy' functionality,
/// when a purchase is requested by a minor and referred to a parent
/// for approval.
///
/// When the purchase is approved or rejected, the normal purchase events
/// will fire.
/// </summary>
/// <param name="item">Item.</param>
private void OnDeferred (Product item)
{
Debug.Log ("Purchase deferred: " + item.definition.id);
}
}
#endif // UNITY_PURCHASING
与 App 收据不同,您无法在本地验证交易收据。您必须将收据字符串发送到远程服务器进行验证。如果您已使用远程服务器验证 App 收据,请将交易收据发送到相同的 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 SetApplePromotionalPurchaseInterceptor 回调方法截取 Apple 促销购买。使用此回调呈现家长控制、发送分析Unity Analytics 的缩写
请参阅 术语表 事件,或在向 Apple 发送购买之前执行其他功能。回调使用用户尝试购买的产品。您必须调用 IAppleExtensions.ContinuePromotionalPurchases() 以继续进行促销购买。这将发起所有已排队的付款。
如果您未设置回调,促销购买将立即进行,并使用结果调用 ProcessPurchase。
注意:在其他平台上调用这些 API 不起任何作用。
private IAppleExtensions m_AppleExtensions;
public void Awake() {
var module = StandardPurchasingModule.Instance();
var builder = ConfigurationBuilder.Instance(module);
// On iOS and tvOS we can intercept promotional purchases that come directly from
// the App Store.
// On other platforms this will have no effect; OnPromotionalPurchase will never be
// called.
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) {
// Set all these products to be visible in the user's App Store
m_AppleExtensions.SetStorePromotionVisibility(item, AppleStorePromotionVisibility.Show);
}
}
}
private void OnPromotionalPurchase(Product item) {
Debug.Log("Attempted promotional purchase: " + item.definition.id);
// Promotional purchase has been detected.
// Handle this event by, e.g. presenting a parental gate.
// Here, for demonstration purposes only, we will wait five seconds before continuing
// the purchase.
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 and tvOS only
}
要在 Apple 商店中测试,您必须使用 iTunes connect 测试帐户,该帐户可以在 iTunes connect 中创建。
退出 iOS 设备或笔记本电脑上的 App Store,启动您的应用,当您尝试购买或恢复交易时,系统将提示您进行登录。
如果您收到初始化失败,理由是 NoProductsAvailable,请遵循此清单
在构建桌面 Mac 构架时,您必须在 Unity 的构架设置中选择 Mac App Store 认证。
构建您的应用后,您必须使用您的包标识符和版本字符串更新其 info.plist 文件。右键单击 .app 文件并单击 显示包内容,找到 info.plist 文件并更新 CFBundleIdentifier 字符串为您的应用的包标识符。
之后,必须对此应用程序进行签名、打包和安装。你需要在 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
若要对此捆绑包签名,可能首先需要移除 Content.meta 文件(如果存在):your.app/Contents/Plugins/unitypurchasing.bundle/Contents.meta
为了正确安装包,你需要在运行新创建的包之前删除未解包的 .app 文件。
之后,必须从应用程序文件夹启动你的 App。首次执行此操作时,你会收到输入 iTunes 帐户详情的提示,对此,你应输入你的 iTunes Connect 测试用户帐户的登录信息。然后,你将可以在沙箱环境中进行试买测试。