Unity支付模块

利用now.gg支付模块,可以在您的Unity游戏里实现应用内购买。

使用now.gg支付模块实现应用内购买需要:

  1. 下载并导入now.gg支付的Unity模块(now.gg Payments Unity Module)。
  2. 添加所需的依赖项。
  3. 在您的工程中实现now.gg支付。

下载并导入模块

now.gg支付Unity模块以Unity的包文件形式 nowgg-payments-login.unitypackage 被引入。

将模块添加到您的Unity工程中:

  1. 下载 包含最新版的now.gg支付模块的Unity软件包。
  2. 下载模块后,将其导入您的 Unity 工程。要做到这一点,您可以按照:
    • 点击 Assets > Import Package > Custom Package,如下所示:
    • 选择之前下载好的 nowgg-payments-login.unitypackage
    • 选择所有列出的文件,然后点击导入(Import)

导入所有模块文件后,工程中将创建一个名为’NowGGSdk‘的文件夹。您可以在Assets文件夹的根目录下找到该文件夹。

注意:请不要修改NowGGSdk文件夹,因为其中包含与now.gg支付相关的所有资源。

添加所需的依赖项

此操作将使用Unity外部依赖关系管理器(External Dependency Manager)下载所有依赖,并将其添加到 Assets/Plugins/Android 目录中。

添加所需依赖项:

  • 点击 Assets > External Dependency Manager > Android Resolver > Resolve

实现now.gg支付

导入now.gg支付模块并添加依赖项后,您可以按照此章节操作在您的应用程序/游戏中集成now.gg支付。

为Unity IAP的实现添加平台检查

要运行now.gg IAP服务,需要使用now.gg平台。Unity IAP(或任何其他 IAP 服务)仅在非now.gg平台上运行时才能进行初始化。

检查当前运行的平台,在你的项目中添加以下代码,以便您的应用程序在now.gg平台上运行时Unity IAP不会被激活:

public void Start()
 {
 	 if (NowGG.Sdk.NowGGPaymentsSdkManager.IsNowGGIapAvailable())
            return;

	 // 您的 Unity IAP 代码...
 }

在Unity中实现now.gg IAP

以下章节说明了now.gg IAP函数的实现,您可以从Unity的应用/游戏中调用这些函数。

首先创建一个包含now.gg IAP实现的类,并将其附加到一个可用于初始化应用内购买的游戏对象。

1. 添加产品并初始化模块

此步骤将允许您在应用/游戏中添加应用内购买产品,并初始化模块。比如,我们在以下代码中添加了两个IAP 可消耗型产品(IAP consumable products),它们分别是带有 productId 的 ‘coin1’ 和 ‘coin2’。我们还添加了一个带有 productId 的月包(‘monthlyPack’)的订阅(subscription)。

同样地,如果您在nowStudio中还添加了其他产品和订阅(具有对应的 productId ),您也可以将它们添加进来。

now.gg支付模块需要一个唯一的用户ID来识别用户并启动交易。或者用户可以选择保存支付信息,这样他们就不需要在接下来的交易中再次输入支付信息。

在初始化支付时,必须将唯一用户ID (IN_GAME_ID)传递给now.gg支付模块,如以下示例代码所示:

public void Start()
  {
	 // 如果运行在 Now.gg 平台,仅初始化 Now.gg IAP
	 if (!NowGG.Sdk.NowGGPaymentsSdkManager.IsNowGGIapAvailable())
		 return;

     // 可消耗产品请参考
	 NowGGProductBuilder.Instance.AddProduct("coin1", ProductType.Consumable);
	 NowGGProductBuilder.Instance.AddProduct("coin2", ProductType.Consumable);

     // 订阅请参考
     NowGGProductBuilder.Instance.AddProduct("monthlyPack", ProductType.Subscription);

     NowGGPaymentsSdkManager.Instance.OnInitSuccess += OnInitSuccess;
	 NowGGPaymentsSdkManager.Instance.OnInitFailed += OnInitFailed;
	 NowGGPaymentsSdkManager.Instance.OnPurchaseCompleted += OnPurchaseProduct;
     NowGGPaymentsSdkManager.Instance.OnPurchaseFailed += OnPurchaseFailed;

	 NowGGPaymentsSdkManager.Instance.InitializeIap(PAYMENT_ID, IN_GAME_ID);
 }

说明:

  • 首先会执行初始检查,以确保您正在now.gg平台上初始化now.gg支付服务。
  • 应用内产品和订阅被添加到 NowGGProductBuilder 类中。
  • NowGGPaymentsSdkManager 类的 InitializeIap 函数被调用,以使用 PAYMENT_ID 初始始化支付模块。
  • SDK的响应会通过上述的回调函数进行记录。
  • 参考资料 – NowGGPaymentsSdkManager

重要信息:

  • IN_GAME_ID 是您用户的唯一标识符。
    • 请确保您的 IN_GAME_ID 对每个用户都是唯一的。
      • IN_GAME_ID的唯一性至关重要,因为在进行购买时,如果用户选择存储支付相关的信息,这些信息将被关联到特定的 IN_GAME_ID
      • 支付集成测试:如果您想使用特定的IN_GAME_ID进行支付测试,请将其添加为nowStudio内部测试员
  • PAYMENT_ID 是您应用的唯一标识符。
    • 您在 nowStudio 中添加的每个应用都会生成一个唯一的 PAYMENT_ID
    • 相应的 PAYMENT_ID 可以在nowStudio的“应用详情”(App Details)章节找到 – 更多信息
  • 退款处理 – 与now.gg支付相关的退款流程在 此处说明

2. 获取产品详情

在成功初始化之后,您可以使用 productId 获取产品详情。

要获取产品详情,请参考以下实现:

private void OnInitSuccess()
 {
    Debug.Log($"IAP init success");
    Product coin1 = NowGGPaymentsSdkManager.Instance.GetProductWithID("coin1");

    // 现在你可以使用 productId 获取产品详情
    // 可消耗型
    string price = coin1.price;
    string currencyCode = coin1.priceCurrencyCode;

    // 订阅
    Product monthlyPack = NowGGPaymentsSdkManager.Instance.GetProductWithID("monthlyPack");
    string monthlyPackSubscriptionPeriod = monthlyPack.subscriptionPeriod;
 }

 private void OnInitFailed(string reason)
 {
   Debug.Log($"IAP init failed {reason}");
 }

参考资料:


3. 发起支付

获取了产品详情之后,您可以发起产品购买。为此,您需要调用如下所示的 PurchaseProduct() 函数:

public void PurchaseProduct(string productId, string developerPayload=null)
 {
     NowGGPaymentsSdkManager.Instance.PurchaseProduct(productId, developerPayload);
 }

参考资料:

重要信息

  • developerPayload 是一个可选参数。
  • ProductId 是您在nowStudio中为您的应用(App Id)定义的 内购产品 和 订阅 的唯一标识符。
  • 产品价格是从您在 nowStudio 中创建的 价格模板 中获取的。

4. 分配购买的权利

在一次成功购买后,您可以将购买的权利分配给用户。

以下方法展示了如何将购买的权利分配给用户:

1. 可消耗产品

我们提供了两种方式实现购买的消费:

2. 订阅

我们提供了两种方式用于确认购买的订阅:


使用 PurchaseProcessingResult

private PurchaseProcessingResult OnPurchaseProduct(PurchasedProduct purchasedProduct)
 {
     string orderId = purchasedProduct.orderId;
     string purchaseToken = purchasedProduct.purchaseToken;
     string developerPayload = purchasedProduct.developerPayload;

     // 用户购买了一个可消耗产品。
     if (String.Equals(purchasedProduct.productId, "coin1", StringComparison.Ordinal))
     {
         Debug.Log(string.Format("OnPurchaseProduct: PASS. Product: '{0}'", purchasedProduct.productId));
         // 可消耗产品被成功购买, 为玩家添加100的游戏内货币。
         // coin += 100;
     }
     else if (String.Equals(purchasedProduct.productId, "coin2", StringComparison.Ordinal))
     {
         Debug.Log(string.Format("OnPurchaseProduct: PASS. Product: '{0}'", purchasedProduct.productId));
         // 可消耗产品被成功购买, 为玩家添加200的游戏内货币。
         // coin += 200;
     }
     else if (String.Equals(purchasedProduct.productId, "monthlyPack", StringComparison.Ordinal))
     {
         Debug.Log(string.Format("OnPurchaseProduct: PASS. Product: '{0}'", purchasedProduct.productId));
         Debug.Log("Subscription: " + purchasedProduct.subscriptionStatus + " " + purchasedProduct.subscriptionPeriod + " " + purchasedProduct.expiryTimeMillis + " " + purchasedProduct.subscriptionPurchaseDateMillis);
         
if (purchasedProduct.subscriptionStatus == "ACTIVE" && purchaseProduct.isAcknowledged == false)
         {
            // 订阅被成功购买。将订阅的权利交付给玩家。
            // 根据购买订阅的状态,计费周期,到期时间更新UI。
            // 返回 PurchaseProcessingResult.Complete 以确认购买已被确认(订阅)
         }
     }
     else
     {
         Debug.Log(string.Format("OnPurchaseProduct: FAIL. Unrecognized product: '{0}'", purchasedProduct.productId));
     }

     // 返回一个标志,表明该产品是否已收到,或者应用程序是否需要在下次启动时提醒此购买。
     // 返回 PurchaseProcessingResult.Pending,如果你希望在下一次启动应用程序/游戏时提醒此次购买。
     // 返回 PurchaseProcessingResult.Complete,代表可消耗型产品(consumable products)的购买已被消费(consumed),或者订阅(subscriptions)已被确认(acknowledged ),并且已将购买的权利交付给用户。
     // 确保您已将购买的权利交付给用户。

     return PurchaseProcessingResult.Complete;
 }

注意:

  • 如果您希望在您的后端服务器上处理购买,或者需要根据您的实现使用另一种方法来完成购买,您应该在 OnPurchaseProduct  中返回 PurchaseProcessingResult.Pending
    • 如果有任何待处理的购买,它们将在您的应用/游戏下次启动时提醒用户。
  • 要确认待处理的购买并授予权利,- 请参考本章节。

参考资料:

重要信息

  • 在一次成功的购买之后会生成一个唯一的 purchaseToken
  • 每个订单也会生成 orderId
    • 每次购买的凭证,包括订单ID和其他相关信息也会通过电子邮件发送给用户。

使用 consumePurchase – 用于可消耗产品

对于有后端服务器的应用,应使用 consumePurchase API 进行服务端的购买消费。

在验证购买之后,您应该将其标记为已消费。

购买的实现包括:

将购买的产品分配给用户。

通知now.gg该产品已被消费。

实现购买消费的示例代码

以下示例代码展示了使用 consumePurchase API 的相关请求。

import requests

  url = "https://cloud-api.bluestacks.cn/v2/order/consumePurchase"

  payload = 'purchaseToken=nowgg-_purchase_token'
  headers = {
    'Authorization': 'payment_api_key_here',
    'Content-Type': 'application/x-www-form-urlencoded'
  }

  response = requests.request("POST", url, headers=headers, data=payload)

  print(response.text)

参考资料

重要信息

  • 在调用consumePurchase API之前,请确保将购买的产品分配给用户。
  • API Key – 支付API Key(Payments API Key)可以在nowStudio的证书章节找到。 更多信息
  • 在一次成功的购买后,会返回 purchaseToken 。你可以在下面的文档中找到更多信息:
  • 如果权利在购买的三日之内未被授予,那么该购买交易将被取消,并对用户发起退款。

使用 acknowledgePurchase – 用于订阅

acknowledgePurchase API应被用于服务器端的订阅型产品的确认。

在验证购买之后,您应该将其标记为已确认。

确认购买订阅的示例代码

下列示例代码展示了使用 acknowledgePurchase API的相关请求。

import requests

  url = "https://cloud-api.bluestacks.cn/v2/seller/order/acknowledgepurchase"

  payload = 'purchaseToken=nowgg-_purchase_token'
  headers = {
    'Authorization': 'payment_api_key_here',
    'Content-Type': 'application/x-www-form-urlencoded'
  }

  response = requests.request("POST", url, headers=headers, data=payload)

  print(response.text)

参考资料

重要信息

  • API Key – 支付API Key(Payments API Key)可以在nowStudio的证书章节找到。更多信息
  • 在一次成功的购买后,会返回 purchaseToken 。你可以在下面的文档中找到更多信息:
  • 如果权利在购买的三日之内未被授予,那么该购买交易将被取消,并对用户发起退款。

5. 确认待处理的购买

如果您想在您的后端服务器上处理购买,或者您需要根据您的实现机制使用另一种方法来完成购买,您的应用应从 OnPurchaseProduct 返回 PurchaseProcessingResult.Pending

客户端

要完成购买流程,您可以使用 ConfirmPendingPurchase 方法通知 now.gg IAP服务,告知应用已经记录下该购买行为。

public void ConfirmPendingPurchase(string purchasetoken, ProductType productType) {
   if (productType == ProductType.Consumable) {
       ConsumeProduct(purchasetoken);
   } else {
       AcknowledgePurchase(purchasetoken);
   }
 }

参考资料:

服务端

要想完成购买流程,且使用您的应用后端服务器对购买进行授权,则需要调用以下API:

重要信息

  • 待处理的购买一经确认,那么 now.gg IAP 服务将不会通知应用关于此提及过的购买。
    • 如果有任何待处理的购买,它们将在您的应用/游戏下次启动时提醒用户。
  • 订阅型产品的有效期自被确认的当天起生效。
  • 如果权利在购买的三日之内未被授予,那么该购买交易将被取消,并对用户发起退款。

6. 查询待处理的购买

如果您需要查询待处理的购买,您可以调用 NowGGPaymentsSdkManager  类的 QueryPendingPurchases 函数。此函数将会查询所有待处理的购买,并调用 OnPurchaseProduct 回调函数,返回待处理的购买。

NowGGPaymentsSdkManager.Instance.QueryPendingPurchases();

参考资料:OnPurchaseProduct.


7. 获取其他产品

如果您想要获取其他产品以供购买,或是想要刷新现有产品的详细信息/元数据,那么您可以使用 FetchAdditionalProducts 函数,如下所示:

var newProducts = new System.Collections.Generic.Dictionary<string, ProductType>();
 newProducts.Add("coin2", ProductType.Consumable);
 newProducts.Add("coin3", ProductType.Consumable);

 NowGGPaymentsSdkManager.Instance.FetchAdditionalProducts(newProducts,
       () =>
       {
           //在获取了其他产品后, 用户就可以购买它们。
           Debug.Log($"Successfully fetched additional products");
           Product coin1 = NowGGPaymentsSdkManager.Instance.GetProductWithID("coin1");
           string price = coin1.price;
           string currencyCode = coin1.priceCurrencyCode;
       },
      reason =>
      {
          Debug.Log($"Fetching additional products failed: {reason}");
      });

8. 处理失败的购买

购买可能会由于各种各样的原因而导致失败,其中包括:

  • 网络/连接问题
  • 支付失败
  • 配置问题

您可以通过参考下面的代码实现来对失败的购买进行调查和处理:

public void OnPurchaseFailed(int errorCode, string errorMessage)
 {
    Debug.Log($"OnPurchaseFailed: errorCode: {errorCode} and msg: {errorMessage}");
 }

注意:


9. 订阅状态回调API

(由开发者提供)

本章节说明了 API 规范,以便您为我们提供 SubscriptionStatusCallback API,用于发送订阅状态的更新。

下述是相关工作流程:

  • nowStudio将会使用此API来发送请求数据到您游戏的后端。
  • 您的游戏后端可以通过使用我们提供的API密钥(Webhook API Key)来验证请求。
  • 您可以根据订阅的当前状态(定义于此)来分配用户其购买的权利。
  • 通过使用您所提供的回调URL,在我们发送请求数据之后,我们将会等待您API的响应。
    • 如果我们没有收到状态代码为200且值为true的成功状态,那么我们将会在一段时间内持续进行尝试。

参考资料:Subscription Status Callback API



购买验证

通过验证购买,您可以确认购买的真实性。减少欺诈的最佳做法是在将产品分配给用户之前对每次购买都进行验证。

您可以使用一下两种方法之一来验证购买:

  • 使用购买验证API(Verify Purchase API)。
  • 使用公钥(Public key)。

1. 使用VerifyPurchase API

验证购买的第一种方法是使用 verifyPurchase API。您可以使用此 API 向我们的后端服务器验证购买。

为验证购买, 从您应用的后端服务器用 purchaseToken 作为参数,调用 verifyPurchase API,如以下示例请求代码所示:

curl --location 'https://cloud-api.bluestacks.cn/v2/seller/order/verifyPurchase' \
 --header 'Authorization: <payment_api_key_here>' \
 --header 'Content-Type: application/x-www-form-urlencoded' \
 --data-urlencode 'purchaseToken=<nowgg_purchase_token>'
import requests

  url = "https://cloud-api.bluestacks.cn/v2/seller/order/verifyPurchase"

  payload = 'purchaseToken=<nowgg_purchase_token>'
  headers = {
  'Authorization': '<payment_api_key_here>',
  'Content-Type': 'application/x-www-form-urlencoded'
  }

  response = requests.request("POST", url, headers=headers, data=payload)

  print(response.text)

重要信息

  • verifyPurchase API 必须从您应用的后端服务器调用。
  • 购买成功后,将返回 purchaseToken,详细信息您可以参考以下文档:

2. 使用您的公钥验证购买

您可以在本地验证购买,也可以使用后端服务器,但是我们建议您使用后端服务器来验证购买。

您可以按照 此处列出的步骤 来生成公钥。

以下代码分别演示了在本地和使用后端服务器进行购买验证。您可以参考 演示应用程序工程(Demo project)了解更多详情。

private PurchaseProcessingResult OnPurchaseProduct(PurchasedProduct purchasedProduct) {
    // 使用此示例代码进行本地验证
    bool isValidPurchase = PurchaseVerification.Instance.VerifyPurchaseLocally(
        BASE_64_ENCODED_PUBLIC_KEY,
        purchasedProduct.originalJson,
        purchasedProduct.signature); 

    // 我们推荐使用您的后端服务器进行验证
    // 您需要发送签名和原始数据到您的后端服务器进行验证。
    PurchaseVerification.Instance.VerifyValidSignatureOnBackend(
        purchasedProduct.originalJson,
        purchasedProduct.signature);

    // 用户买了可消耗型的产品
    if (String.Equals(purchasedProduct.productId, "coin1", StringComparison.Ordinal))
    {
        Debug.Log(string.Format("OnPurchaseProduct: PASS. Product: '{0}'", purchasedProduct.productId));
        // 可消耗产品被成功购买, 为玩家添加100的游戏内货币。
        // coin += 100;
    } 
    else if (String.Equals(purchasedProduct.productId, "coin2", StringComparison.Ordinal)) 
    {
        Debug.Log(string.Format("OnPurchaseProduct: PASS. Product: '{0}'", purchasedProduct.productId));
        // 可消耗产品被成功购买, 为玩家添加200的游戏内货币。
        // coin += 200;
    } 
    else 
    {
        Debug.Log(string.Format("OnPurchaseProduct: FAIL. Unrecognized product: '{0}'", purchasedProduct.productId));
    }

    return PurchaseProcessingResult.Complete;
}

服务器验证

下载包 包含了一个实现示例,用于使用后端服务器验证购买,您也可以参考编写自己的实现。

示例实现包括:

  • PurchaseVerification 类:位于演示应用程序工程(Demo Project)中,它包含了特定的Unity代码,用于将购买数据和签名发送到后端服务器。
  • Server.py:在下载包中独立存放,它包含了用于运行本地服务器和执行后端验证的Python示例代码。

本地验证

我们在下载包中提供了一个示例实现,用于本地验证购买的情况,您可以使用提供的示例来编写自己的实现。

在示例实现中:

  • 您可以参考 PurchaseVerification 类的 VerifyPurchaseLocally 函数。

重要信息

×
文本已复制到剪贴板
copyLinkText
有疑问?请通过以下方式联系我们: dev-support@now.gg