学如逆水行舟,不进则退。
今天和大家来聊聊iOS内购即In-App Purchase,内购分为消耗型、非消耗型、自动订阅、非自动订阅型。
内购流程
配置App内购买项目(可以参考苹果官方文档)
- 在iTC后台接收付费协议
- 创建App内购买项目
- 创建沙盒账号,用于测试
代码实现
- 从苹果请求商品详情
- (void)requestIAPProducts:(NSSet *)productIds
{
SKProductsRequest *productReq = [[SKProductsRequest alloc] initWithProductIdentifiers:productIds];
productReq.delegate = self;// SKProductsRequestDelegate
[productReq start];
}
- 实现SKProductsRequestDelegate代理,如果获取到商品的话就执行购买行为
#pragma mark SKProductsRequestDelegate
- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response
{
[response.products enumerateObjectsUsingBlock:^(SKProduct * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
}];
[response.invalidProductIdentifiers enumerateObjectsUsingBlock:^(NSString * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
}];
// 开始购买
if (response.products.count > 0) {
SKProduct *product = response.products.firstObject;
SKMutablePayment *payment = [[SKMutablePayment alloc] init];
payment.applicationUsername = @"uid";
payment.productIdentifier = product.productIdentifier;
payment.quantity = 1;
[[SKPaymentQueue defaultQueue] addPayment:payment];
}
}
- (void)requestDidFinish:(SKRequest *)request
{
}
- (void)request:(SKRequest *)request didFailWithError:(NSError *)error
{
}
- 监听商品支付结果:SKPaymentTransactionObserver
#pragma mark SKPaymentTransactionObserver
- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions
{
for (SKPaymentTransaction *transaction in transactions) {
switch (transaction.transactionState) {
// 1、购买成功
// 2、购买成功,但是你没有finish掉,没有消耗
case SKPaymentTransactionStatePurchased: {
//自动订阅订单抛出,只有自动订阅订单originalTransaction才会有值
if (transaction.originalTransaction) {
} else {
}
// 对于成功的订单需要先到后台校验 成功后才可以消单
// [[SKPaymentQueue defaultQueue] finishTransaction:transaction];
break;
}
case SKPaymentTransactionStateFailed: {
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
break;
}
case SKPaymentTransactionStateRestored: {
// [[SKPaymentQueue defaultQueue] finishTransaction:transaction];
break;
}
case SKPaymentTransactionStatePurchasing: {
break;
}
case SKPaymentTransactionStateDeferred: {
break;
}
default: {
break;
}
}
}
}
- 后台校验订单
沙盒订单校验:https://sandbox.itunes.apple.com/verifyReceipt
正式订单校验:https://buy.itunes.apple.com/verifyReceipt
凭证校验结果格式说明
{
"receipt": {
"receipt_type": "ProductionSandbox",
"adam_id": 0,
"app_item_id": 0,
"bundle_id": "",
"application_version": "7.0",
"download_id": 0,
"version_external_identifier": 0,
"receipt_creation_date": "2022-05-20 02:37:42 Etc/GMT",
"receipt_creation_date_ms": "1653014262000",
"receipt_creation_date_pst": "2022-05-19 19:37:42 America/Los_Angeles",
"request_date": "2022-05-31 06:46:57 Etc/GMT",
"request_date_ms": "1653979617874",
"request_date_pst": "2022-05-30 23:46:57 America/Los_Angeles",
"original_purchase_date": "2013-08-01 07:00:00 Etc/GMT",
"original_purchase_date_ms": "1375340400000",
"original_purchase_date_pst": "2013-08-01 00:00:00 America/Los_Angeles",
"original_application_version": "1.0",
"in_app": [
{
"quantity": "1",
"product_id": "xxxx",
"transaction_id": "xx",
"original_transaction_id": "xxx",
"purchase_date": "2022-05-20 02:37:41 Etc/GMT",
"purchase_date_ms": "1653014261000",
"purchase_date_pst": "2022-05-19 19:37:41 America/Los_Angeles",
"original_purchase_date": "2022-05-20 02:37:41 Etc/GMT",
"original_purchase_date_ms": "1653014261000",
"original_purchase_date_pst": "2022-05-19 19:37:41 America/Los_Angeles",
"is_trial_period": "false",
"in_app_ownership_type": "PURCHASED" // 代表成功
}
]
},
"environment": "Sandbox",
"status": 0
}
Demo 已经上传至Github ,记得给个star
发布上线
代码实现开发完成后,可以跟着版本一起发布,也可以单独审核内购,看具体需求
内购常见错误
- 获取不到商品信息:检查itc商品审核以及下线情况,检查设备知否支持内购
- 无法连接: 网络问题,切记沙盒环境下不可开vpn或者网络代理
- 21000 App Store无法读取你提供的JSON数据
- 21002 收据数据不符合格式
- 21003 收据无法被验证
- 21004 你提供的共享密钥和账户的共享密钥不一致
- 21005 收据服务器当前不可用
- 21006 收据是有效的,但订阅服务已经过期。当收到这个信息时,解码后的收据信息也包含在返回内容中
- 21007 收据信息是测试用(sandbox),但却被发送到产品环境中验证
- 21008 收据信息是产品环境中使用,但却被发送到测试环境中验证
如果觉得我写的还不错的话,记得给个关注哦。有任何疑问❓可以留言咨询哦,看到会回复
参考资料:
- App内购买项目类型