一个 应用收据 存储在设备的本地存储中,并且可以按如下方式读取
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 测试用户帐户的登录信息。然后,你将可以在沙箱环境中进行试买测试。