版本:Unity 6 (6000.0)
语言:英文
商店指南
通用 Windows 平台

iOS 和 Mac 应用商店

扩展功能

读取应用收据

一个 应用收据 存储在设备的本地存储中,并且可以按如下方式读取

var builder = ConfigurationBuilder.Instance(StandardPurchasingModule.Instance());
string receipt = builder.Configure<IAppleConfiguration>().appReceipt;

检查付款限制

应用程序内购买可能会因设备设置而受到限制,可以按如下方式进行检查

var builder = ConfigurationBuilder.Instance(StandardPurchasingModule.Instance());
bool canMakePayments = builder.Configure<IAppleConfiguration>().canMakePayments;

恢复交易

在苹果平台上,用户必须输入他们的密码才能检索之前的交易,因此您的应用程序必须向用户提供一个按钮让他们这样做。此过程中,IStoreListenerProcessPurchase 方法将为用户已有的任何项目调用。

/// <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;
        }
    }
}

当购买获得批准或被拒绝时,将调用您的商城的常规 ProcessPurchaseOnPurchaseFailed 侦听器方法。

交易收据

有时可消耗的询问购买不会显示在应用收据中,在这种情况下,您无法使用该收据对其进行验证。但是,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 允许您通过应用的产品页面来推广游戏内购买。与常规游戏内购买不同,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,请遵循此清单

  • iTunes Connect 产品标识符必须与提供给 Unity IAP 的产品标识符完全匹配
  • 必须为您的应用在 iTunes Connect 中启用游戏内购买
  • 产品必须在 iTunes Connect 中被清除以便销售
  • 对于新创建的 iTunes Connect 产品可供购买可能需要很多个小时
  • 您必须同意最新的 iTunes Connect 开发者协议并拥有有效的银行详细信息

Mac App Store

在构建桌面 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 测试用户帐户的登录信息。然后,你将可以在沙箱环境中进行试买测试。


  • 2018-05-30 发布页面
  • 2017.3 中添加了询问购买、交易收据和拦截收据 NewIn20173
商店指南
通用 Windows 平台