我有一个应用程序,每个用户有几个实体。用户可以为每个实体执行IAP。当我将付款添加到SKPaymentQueue时,我知道购买是为哪个实体进行的。
如何从updatedTransactions
回调中获取此信息?
我已尝试将购买交易中的交易标识符与 已购买购买我已尝试使用应用程序用户名: 但文件中提到,它不可靠,仅用于欺诈检测。 它在大多数情况下都有效,但苹果不保证在回调交易中返回。func buyProduct(_ product: SKProduct) {
let payment = SKMutablePayment(product: product)
payment.applicationUsername = "character ID"
SKPaymentQueue.default().add(payment)
}
产品类型
您可以提供四种产品类型:
- 耗材
- 非消耗品
- 自动续订
- 不续订订阅
让我们跳过这里的订阅,专注于(非)耗材。有什么区别?
- 耗材
- 用户可以多次购买
- 它们未同步,无法恢复
- 一个例子-在应用程序货币中,你可以购买任何金额,重复
- 非消耗品
- 用户可以购买一次(数量仅为1)
- 它们已同步并且可以恢复
- 一个例子-解锁应用程序功能,捆绑功能
标识符
每个产品都有一个唯一的标识符(productIdentifier
)。它可以从任何地方访问:
SKProduct.productIdentifier
SKPayment.productIdentifier
SKPaymentTransaction.payment
,它为您提供SKPayment
,您可以从那里获得productIdentifier
自定义数据
您能为事务分配自定义数据吗?不,只是你提到的applicationUsername
。但它也有缺陷,比如:
applicationUsername
属性不保证在将支付事务添加到队列和队列更新事务之间持续存在请勿将此属性用于除提供欺诈检测之外的其他目的
您不能将其用于自定义数据。即使你试图滥用它,它仍然没有用,因为它不能保证持续下去。
购买非消耗品
这是容易的部分,因为它允许用户只购买一次。你有productIdentifier
,到处都有,然后你可以解锁功能,下载内容。。。
但这显然不是你想要的。无论如何,你也可以通过这种方式实现你想要的,但你必须为每个实体和实体创造一个独特的产品;用户组合。这可能导致数以百万计的产品标识符。我可以想象这将是一场维护噩梦。
购买消耗品
这部分比较棘手,因为作为应用程序开发人员,你要负责:
- 将其转换为任何应用程序内商品(货币、游戏角色…)
- 使其可在所有用户的设备上使用
- 使用户能够恢复过去的购买
换句话说,耗材的行为与任何其他支付网关(Stripe,…)一样-您知道用户为特定的productIdentifier
向您付款,仅此而已-其他一切都必须在您的应用程序、服务器上处理。。。
一个例子
假设你有一个游戏,用户可以购买一个新的游戏角色。实现这一点有两种方法。
非消耗品
- 每个游戏角色都有一个唯一的
productIdentifier
- 用户可以只购买一次每个角色
- 您可以恢复这些购买
优点:
- 你的工作量很小
缺点:
productIdentifier
的列表可能会增长很多,尤其是如果你有很多字符,它们确实会因每个用户而异,等等
消耗品
- 您有一个自定义的应用程序货币,用户可以使用它来兑换任何游戏角色
- 您可以提供应用内购买产品,如
- 学分10
- 信用50
- 信用100
- 您必须在
StoreKit
之上建立自己的商店- 向用户显示他有多少信用
- 允许他购买任何游戏角色
- 足够的信用?只需将其标记为已购买
- 没有足够的信用?通知用户并让他购买更多信用
- 同时,将商店存放在他想购买特定游戏角色的地方
- 当他有足够的信用(在应用程序购买中)时,查看你的存储并将其兑换为游戏角色
优点:
- 灵活性
productIdentifier
短列表
缺点:
- 同步由您负责
- 恢复由您负责
StoreKit
顶部的定制商店由您负责StoreKit
充当您的任何其他支付网关
在苹果的API中没有办法将事务与特定实体相关联,因此您必须自己进行关联。
我只能想到两种方法:
- 您可以注册一个有状态回调处理程序来处理特定实体,但您必须在应用程序中阻止来自同一用户的多个并发购买。一旦购买完成(成功/失败),您就可以移除处理程序
- 如果您有有限的实体数量(例如,每个用户最多10个),可以订购,您可以注册10种产品(产品形式-1、产品形式-2等-每个实体一个),并在用户为编号实体购买时购买正确的产品。通过这种方式,您可以知道订阅应用于哪个实体
除此之外,苹果的API不将启动的事务与完成的事务关联起来(例如,通过事务id或允许元数据),这使得很难将用户操作与其初始原因关联起来。
就用户体验而言,这是非常糟糕的,因为用户必须在一个潜在的长时间运行的过程中进行两次交互,而没有明显的原因。