如何判断用于支付的Apple ID是否曾订阅过iOS应用?
判断iOS支付Apple ID的订阅历史(解决Codename One wasPurchased方法局限性)
要准确判断用于支付的Apple ID是否曾订阅过你的应用,不能依赖Codename One客户端的wasPurchased(String sku)方法——正如你测试的那样,它仅能识别当前设备的购买记录,无法关联Apple ID的跨设备订阅信息。正确的解决方式是通过Apple官方的收据验证机制或原生StoreKit API来实现,具体步骤如下:
方案1:服务器端验证Apple收据(推荐)
这是最安全可靠的方式,所有订阅状态最终由Apple服务器确认,避免客户端篡改:
- 客户端通过Codename One的
InAppPurchase获取应用收据,再发送到你的后端服务器:// Codename One中获取收据示例 String receipt = InAppPurchase.getInstance().getReceipt(); // 将receipt发送到后端服务器做验证 - 后端服务器向Apple的验证接口发送POST请求:沙盒环境用
https://sandbox.itunes.apple.com/verifyReceipt,生产环境用https://buy.itunes.apple.com/verifyReceipt,请求体包含收据数据。 - 解析Apple返回的响应,重点查看
latest_receipt_info数组:- 遍历数组中的每条记录,检查
product_id是否匹配目标SKU,同时确认expires_date判断是否为当前订阅或历史订阅。
- 遍历数组中的每条记录,检查
- 服务器将验证结果(是否有过订阅)返回给客户端,客户端据此展示introductory offer(新用户)或promotional offer(非新用户)。
方案2:通过Codename One原生扩展调用StoreKit API
如果需要在客户端直接判断(仍建议配合服务器验证),可以编写iOS原生扩展:
- 创建Codename One的
NativeInterface实现,在iOS原生代码中调用StoreKit刷新收据并解析:// 刷新收据 SKReceiptRefreshRequest *refreshRequest = [[SKReceiptRefreshRequest alloc] initWithReceiptProperties:nil]; refreshRequest.delegate = self; [refreshRequest start]; // 解析收据 NSURL *receiptURL = [[NSBundle mainBundle] appStoreReceiptURL]; NSData *receiptData = [NSData dataWithContentsOfURL:receiptURL]; // 解析receiptData中的订阅信息,或发送到服务器验证 - 将解析后的订阅状态通过
NativeInterface回调给Codename One的Java层,用于后续逻辑判断。
关键注意事项
- Apple的introductory offer资格本身由Apple自动校验:当你创建支付请求并指定优惠时,Apple会自动判断当前Apple ID是否符合新用户条件,无需提前判断——但如果需要提前展示不同优惠选项,还是得通过收据验证实现。
- 永远不要信任客户端本地存储的订阅状态,必须通过Apple服务器验证,防止用户篡改数据绕过判断。
内容的提问来源于stack exchange,提问作者Renz
相关产品推荐
相关产品推荐

