⌈iOS⌋IAP 价格国际化与优惠问题
对于商品落地页而言,价格无疑是最重要的信息。而 IAP 商品却是在 App Store Connect 后台进行管理的,Server 是无法拿到相关信息的。一种最简单的方式是:在商品创建的同时,将商品的价格信息注册到 Server,然后 Frontend 与 Server 通信获取落地页信息。但这显然存在问题,因为它无法处理实时价格、价格国际化和折扣优惠。目前唯一的解决方式是 Native 通过 StoreKit 获取商品信息,并将其告知 Frontend。
价格国际化
如果你的 App 只在某一个地区或者国家上架且不会进行商品价格的调整,那么向 Server 注册价格让 Frontend 去获取的方式是最简单的展示价格的方式。但如果前提条件不成立的话,那么这就不是一个好的方式,而是应当让 Native 通过以下方式去获取并以 Javascript 回调同步给 Frontend:
1 |
|
其中 SKProduct 中包含了价格信息、货币单位和符号:1
2
3
4class SKProduct: NSObject {
var price: NSDecimalNumber { get } // price.doubleValue
var priceLocale: Locale { get } // priceLocale.currencySymbol(¥) / priceLocale.currencyCode(CNY/JPY)
}
注意,这里的价格地区与 AppleID 分区相关。StoreKit 本身存在缓存,首次获取相对较慢。如果数据没有刷新,可以重新登录 AppleID 进行重试。
优惠
通常出于运营获客的目的,商品在特定时间段内购买可以享受折扣或者优惠。在 App Store Connect 后台,我们可以为订阅型商品创建「推介促销优惠(Introductory Offers)」和「促销优惠(Promotional Offers)」。前者每个 Apple ID 只能享受一次,后者由开发者的 Server 管理享受资格。因为官方的数据分析会有一定延迟,所以产品会希望 Server 能够准确打点用户的实际购买支付价格(需要考虑优惠)用以分析产品运营活动。很遗憾地是 Server 无法知道用户的实际支付价格,只能通过解析收据从 is_trial_period
和 is_in_intro_offer_period
判断用户是否享受了「推介促销优惠」,即需要 Native 将「推介促销优惠」后的价格上报给 Server。大体流程如下:
- 在验证收据时,通过 SKPaymentTransaction.payment.productIdentifier 获取到商品 ID。
- 使用 SKProductsRequest 通过商品 ID 获取到商品现存的优惠或者折扣信息。
- 如果存在「推介促销优惠」,则在验证收据时带上优惠后的价格信息,Server 通过分析收据,判断用户的实付价格并上报打点。
SKProduct 中的优惠信息如下:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21class SKProduct: NSObject {
// iOS 11.2+
var introductoryPrice: SKProductDiscount? { get } // 推介促销优惠,同一地区同一时间短只会存在一个。
// iOS 12.2+
var discounts: [SKProductDiscount] { get } // 促销优惠
}
// iOS 11.2+
class SKProductDiscount : NSObject {
var price: NSDecimalNumber { get }
var priceLocale: Locale { get }
// iOS 12.2+,推介促销优惠为 nil
var identifier: String? { get }
// 优惠周期
var subscriptionPeriod: SKProductSubscriptionPeriod { get }
var numberOfPeriods: Int { get }
// 支付方式:免费试用/先用后付/随用随付
var paymentMode: SKProductDiscount.PaymentMode { get }
// iOS 12.2+,优惠类型:推介促销优惠/促销优惠
var type: SKProductDiscount.`Type` { get }
}
促销优惠的使用相对更为复杂,这里是官方文档,流程描述如下:
- 在 App Store Connect 后台创建订阅密钥,下载该密钥并交给 Server。
- 在用户购买商品时,Server 判断用户可以享受的优惠信息。
- Native 通过商品 ID 获取所有的促销优惠信息,如果该用户可以使用其中某个优惠,则将其 ID 信息发送给 Server 让其通过订阅密钥进行签名。
- Native 通过签名信息生成 SKPaymentDiscount 实例对象,在将购买加入到 IAP 队列之前,赋值给 payment.paymentDiscount。
- 在验证收据时,Native 自然就可以通过 SKPaymentTransaction.payment.paymentDiscount.identifier 匹配到具体的促销优惠信息。(如果是「推介促销优惠」,paymentDiscount 为 nil。)
总结
其实从流程上来看,整个价格和优惠的适配过程并不复杂,关键在于可回归测试版本让人莫名其妙。最开始在购买过程中,Debug、AdHoc 和 TestFlight 版本上均无法正确展示「推介促销优惠」,在已经上线的 App Store 版本上可以使用优惠。在这个用于测试的版本上线后,TestFlight 版本就可以正常展示「推介促销优惠」了!WTF!相关论坛有不少人提出了如何测试优惠的相关问题(TestFlight 不可用),保不准是因为延迟或者其他乱七八糟的缓存问题导致的,或许我们都已经习惯了 IAP 带来的各种“惊喜”,🤣