开发者控制台

IAP应用的收据验证

IAP应用的收据验证

使用Receipt Verification Service (RVS),可以验证应用用户进行的购买。

RVS概述

下图显示了带有收据验证的购买工作流程。RVS在IAP API完成购买并将购买收据返回给应用后启动。

下表中的步骤与上图中的标注匹配

步骤 组件 任务
1 IAP API IAP API与用户交互以完成购买。IAP API向应用返回购买收据。
2 应用 应用将购买收据转发给应用服务器。
3 应用服务器 应用服务器向RVS服务器发送验证收据请求。
4 RVS服务器 RVS服务器确认收据是否有效。
5 应用服务器 应用服务器向用户提供内容。

只要是通过亚马逊购买,您还可以使用RVS访问在其他平台(如您的网站)上购买的订阅。以下情景描述了此工作流程:

  1. 应用用户从您的公司网站上通过亚马逊购买订阅。
  2. 应用收到所购买订阅的收据
  3. 为允许访问,应用会向您的服务器发送收据中的信息。最后,服务器通过查询RVS来验证此交易。

设置RVS

RVS提供了两个环境选项,具体取决于应用是处于开发/测试阶段,还是已发布到亚马逊应用商店:

  • RVS Cloud Sandbox: 在开发和测试应用时,请使用RVS沙盒环境验证App Tester测试工具生成的收据。要设置RVS Cloud Sandbox,请参阅使用RVS Cloud Sandbox
  • RVS生产服务器: 将应用发布到亚马逊应用商店后,您可以使用Amazon RVS生产服务器。请参阅RVS生产环境的说明

RVS请求语法

使用RVS来验证PurchaseResponse对象或PurchaseUpdatesResponse对象。可以从这些响应对象中提取一个UserId,它表示用户的唯一标识符。PurchaseResponse对象包含ReceiptId,它与UserId联合用于对购买执行带外服务器端验证。出于安全原因,来自您的服务器的请求需要传递共享密钥以确认您的身份。

这些请求使用以下格式:

<Protocol>//<Server>[/<sandbox>]/version/<Operation_version_number>/verifyReceiptId/developer/<Shared_Secret>/user/<UserId>/receiptId/<ReceiptId>

尖括号中的术语是请求参数,请将它们替换为待验证交易的以下值:

  • Protocol: 用于与服务器或沙盒通信的协议,如https:。
  • Server:​ 您要与之通信的RVS服务器URL。
    • RVS Cloud Sandbox服务器和RVS生产服务器都使用URL "appstore-sdk.amazon.com"。
  • sandbox: 如果使用RVS Cloud Sandbox服务器,请使用值"sandbox"。如果使用RVS生产服务器,请省略此参数。
  • Operation_version_number:​ verifyReceiptId操作版本号。此版本号独立于IAP版本号。当前verifyReceiptId版本号为“1.0”。
  • Shared_secret:​ 用于标识发出请求的开发者的共享密钥。可在亚马逊应用商店中您的开发者账户“Shared Key”(共享密钥)页面上找到共享密钥:https://developer.amazon.com/sdk/shared-key.html。对于RVSSandbox,共享密钥可以是任何非空字符串。
  • UserId:​ 代表亚马逊应用商店应用中不同亚马逊客户的ID: PurchaseResponse.getUserData().getUserId()
  • ReceiptId:​ 购买的唯一ID: PurchaseResponse.getReceipt().getReceiptId()PurchaseUpdatesResponse.getReceipts()Receipt.getReceiptId()

RVS响应语法

RVS提供了RESTful JSON API接口。作为最佳实践,使用JSON解析器类从RVS服务器读取JSON响应。

发出验证交易的请求后,RVS服务器或沙盒会返回响应代码来指示请求是否成功。如果成功,则返回的JSON响应包括有关交易的信息。

下例展示了一个成功响应:

   {
    "autoRenewing":false,
    "betaProduct":false,
    "cancelDate":null,
    "cancelReason":null,
    "freeTrialEndDate":null,
    "fulfillmentDate":null,
    "fulfillmentResult":null,
    "gracePeriodEndDate":null,
    "parentProductId":null,
    "productId":"com.amazon.iapsamplev2.gold_medal",
    "productType":"CONSUMABLE",
    "promotions":null,
    "purchaseDate":1399070221749,
    "purchaseMetadataMap":null,
    "quantity":1,
    "receiptId":"wE1EG1gsEZI9q9UnI5YoZ2OxeoVKPdR5bvPMqyKQq5Y=:1:11",
    "renewalDate":null,
    "term":null,
    "termSku":null,
    "testTransaction":true
    }

RVS响应代码

Receipt Verification Service会使用以下代码之一进行响应,这些代码可以指示验证检查的结果:

响应代码 描述
HTTP 200 成功: 收据ID、用户ID和共享密钥都是有效的。产品类型是以下项之一: “ENTITLED”、“CONSUMABLE”或“SUBSCRIPTION”
HTTP 400 receiptId表示的交易无效,或没有找到此receiptId的交易。
HTTP 410 receiptId表示的交易不再有效。请将其作为已取消的收据。
HTTP 429 该请求已被限制节流。请降低您的调用速率并稍后重试。
HTTP 496 sharedSecret无效
HTTP 497 用户ID无效
HTTP 500 出现内部服务器错误

成功交易的RVS响应字段

下表列出并描述了成功交易的RVS响应中包含的字段:

字段 数据类型 描述
autoRenewing 布尔值 表示客户的订阅是否会自动续订。
betaProduct 布尔值 指示所购买的产品是否是动态应用测试产品。
cancelDate 长整数 取消购买的日期,或订阅到期的日期。如果购买未取消,则此字段为null。时间以毫秒为单位。
cancelReason 整数 指示取消产品的原因。可能的值为null、0、1或2,其中每个整数分别代表一项取消原因:
null - 购买未取消。
0 - 当前无法提供取消原因,将在之后提供。
1 - 客户取消了订单。
2 - 亚马逊系统取消了购买。例如,客户用于购买订阅的付款无效,并且无法在宽限期内完成购买。如果亚马逊客户支持部门应客户要求取消订单,也会返回此代码。
freeTrialEndDate 长整数 表示订阅处于免费试用期内。提供订阅免费试用的结束日期,以epoch(毫秒)为单位。如果订阅不在免费试用期内,则此字段为null。
fulfillmentDate 长整数 在订阅购买中,为确认履行的日期。以纪元以后的毫秒数存储。如果未确认订阅履行,则为null。消费品和权利始终为null。
fulfillmentResult 字符串 在订阅购买中,履行的状态。有效值:
  • FULFILLED: 您提供了内容,并且客户使用了内容。
  • UNAVAILABLE: 您无法向客户提供内容。
如果未确认订阅履行,则为null。消费品和权利始终为null。
gracePeriodEndDate 长整数 表示订阅处于宽限期内。提供订阅宽限期的结束日期,以epoch(毫秒)为单位。如果订阅不在宽限期内,则此字段为null。
parentProductId 字符串 Null。预留以供将来使用。
productId 字符串 您在应用中为此商品定义的SKU。
productType 字符串 所购买产品的类型。有效产品类型为CONSUMABLESUBSCRIPTIONENTITLED
promotions List<Promotion> 订阅购买的促销定价详情。如果没有促销,则为Null。请参阅RVS中的促销定价
purchaseDate 长整数 购买日期,以纪元以后的毫秒数存储。对于订阅商品,purchaseDate代表首次购买日期,而不是后续续订的购买日期。
purchaseMetadataMap Map <String, String> 如果购买是通过快速订阅发起的,则值为{"QuickSubscribe":"true"}。否则为null。
quantity 整数 购买的数量。始终为null或1。
receiptId 字符串 购买的唯一标识符。
renewalDate 长整数 需要续订订阅购买的日期。日期以纪元以后的毫秒数存储。
term 字符串 订阅IAP将保持有效的持续时间(期限从购买之日开始)。期限由数字和时间段(天、周、月、年)构成,如1周2个月
termSku 字符串 对应于订阅期的唯一SKU。
testTransaction 布尔值 表明此购买是否作为亚马逊发布和测试过程的一部分进行。

RVS中的促销定价

有关如何设置促销定价优惠的详细信息,请参阅设置促销定价。如果客户以促销定价购买了订阅,则通过RVS返回的收据包括促销详情。上一节所述的JSON响应包含一个promotions(促销)字段。本节将更详细地介绍promotions字段。促销详情仅显示在与客户以促销定价购买的订阅相对应的收据上。

如果没有与收据相关联的促销,则promotions字段为空。否则,该字段将包含Promotion(促销)对象列表,其中包含以下字段。

字段 数据类型 描述
promotionType 字符串 促销类型。有效值: 试销价促销价。请参阅有效值描述
promotionStatus 字符串 该客户的促销状态。有效值: 已加入队列进行中已完成。请参阅有效值描述

示例:

"promotions": [
    {
            "promotionType":"试销价 - 所有客户",
            "promotionStatus":"已完成"
    }
]

有效值描述

promotionType字段有效的值为:

  • 试销价 - 所有客户 — 向所有客户(包括新客户和到期客户)提供的优惠。
  • 促销价 - 到期客户 — 仅对到期客户提供的优惠。.

promotionStatus字段有效的值为:

  • 已加入队列 — 客户使用促销优惠购买了订阅。目前,他们正在进行免费试用,尚未开始促销期。
  • 进行中 — 客户目前正在享受促销优惠。
  • 已完成 — 客户已完成促销期。

促销定价常见问题解答

问: 是否所有客户订阅收据都会提供促销详情?
不是,促销详情仅显示在以促销定价完成的订阅购买所对应的收据上。
问: 取消收据后是否显示促销详情?
是的,如果客户的订阅被取消,则促销详细信息显示为已完成
问: 如果客户在免费试用期间、续订为促销计划之前取消订阅,则促销状态是什么?
由于客户没有开始促销期,因此收据上不会显示任何与之相关联的促销详情。

取消日期和续订日期

renewalDate字段包含自动续订订阅购买下一次需要续订的日期。此字段仅适用于订阅购买。如果客户按月订阅,则订阅会每月在与客户首次订阅相同的日期续订。如果下个月不包括该确切日期,则预订日期为距其最近的前一个日期。例如:

  • 如果客户在1月2日订阅,则接下来的三个续订日期为2月2日、3月2日和4月2日。
  • 如果客户在1月31日订阅,接下来的三个续订日期为2月28日(如果是闰年,则为2月29日)、3月31日和4月30日。

cancelDate字段包含订阅购买到期的日期或亚马逊客户服务取消购买的日期。取消日期表示客户失去相应内容访问权限的日期。如果客户通过关闭自动续订来取消其订阅,则取消日期是之前原定的续订日期。

renewalDatecancelDate字段以毫秒为单位存储。可以使用java.util.Date(timeInMillis)将值转换为日期对象。

消费品或权利购买

在有效的收据中,取消日期和续订日期都包含null值。如果取消日期字段不为null,则会包含亚马逊客户服务取消购买的日期。

订阅购买

在有效的订阅收据中,取消日期为null。如果cancelDate字段不为null,则会包含订阅到期的日期或亚马逊客户服务取消购买的日期。

renewalDate字段包含自动续订订阅购买下一次需要续订的日期。如果订阅未设置为自动续订,则字段值为null。

在以下示例中,用户拥有已取消的订阅:

  • 订阅的有效期为2016年1月1日 – 2016年3月1日。在此收据中,此订阅的purchaseDate设置为2016/01/01,cancelDate设置为2016/03/01。
  • 如果此订阅后来于2016年4月1日重新激活,则订阅会具有第二个收据。第二个收据会显示purchaseDate为2016年4月1日,cancelDate为null。

RVS沙盒和生产示例

请参阅RVS示例


Last updated: 2023年12月6日