2022 iOS 内购详解最新最全In-App Purchase(附代码)

学如逆水行舟,不进则退。

今天和大家来聊聊iOS内购即In-App Purchase,内购分为消耗型、非消耗型、自动订阅、非自动订阅型。

内购流程

配置App内购买项目(可以参考苹果官方文档)

  1. 在iTC后台接收付费协议
  2. 创建App内购买项目
  3. 创建沙盒账号,用于测试

代码实现

  1. 从苹果请求商品详情
- (void)requestIAPProducts:(NSSet *)productIds
{
    SKProductsRequest *productReq = [[SKProductsRequest alloc] initWithProductIdentifiers:productIds];
    productReq.delegate = self;// SKProductsRequestDelegate
    [productReq start];
}

  1. 实现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
{
}
  1. 监听商品支付结果: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;
            }
        }
    }
}
  1. 后台校验订单
沙盒订单校验: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 收据信息是产品环境中使用,但却被发送到测试环境中验证

如果觉得我写的还不错的话,记得给个关注哦。有任何疑问❓可以留言咨询哦,看到会回复

参考资料:

  1. App内购买项目类型

你可能感兴趣的:(2022 iOS 内购详解最新最全In-App Purchase(附代码))