iOS 内购IAP(In-App Purchases)代码实现(上)

iOS 内购IAP(In-App Purchases)代码实现(上)

iOS 内购,也叫内支付,是在iOS应用内部,向苹果服务器发起购买请求的过程。我们在这边来讲一讲代码的实现过程。还有,在做内购的时候,常常会有丢单现象发生,每到这时候,我的内心几乎是崩溃的。所以后面我们来讲讲如何有效地防止丢单。

这里写图片描述

先简述一下内购过程。比如说游戏里面,你要买一个装备,这时候你点击了购买按钮;游戏向苹果服务器发送购买请求,弹出loading框;手机弹出苹果账户和密码输入框;输入完账户密码后,钱打到苹果那边,然后提示你购买成功或者失败;游戏loading框消失,成功给你发放商品,失败提示你购买失败。整个购买过程结束。

当然,游戏方必须事先在苹果iTunes后台,配置好相应的商品和价格。具体的配置过程,网络上有很多教程,这边我们就不再赘述。

这里写图片描述

配置好以后,我们会获得一个产品ID。这个东西,我们待会代码中会用到。

准备

先要将StoreKit.framework加入工程中。
这里写图片描述

然后工程中创建一个类,我们把它称为SDKAppStore。 import StoreKit头文件。

#import <StoreKit/StoreKit.h>

然后在头部写上StoreKit的协议

@interface SDKAppStore : NSObject<SKProductsRequestDelegate,SKPaymentTransactionObserver>

SKProductsRequestDelegate是商品请求回调,用来告诉你有没有这个商品。
SKPaymentTransactionObserver是交易观察者,用来告诉你交易进行到哪个步骤了。

接下来使用单例的形式

#pragma mark - 获取单例
+ (instancetype)sharedInstance {
    static SDKAppStore* instance = nil;
    static dispatch_once_t onceToken = 0;
    dispatch_once(&onceToken, ^{
        instance = [[SDKAppStore alloc] init];
    });
    return instance;
}

请求商品信息

交易开始之前,我们先要用productId去请求一下商品的信息。

#pragma mark - 开始支付
- (void)startPay:(SDKPayInfo*)payInfo productId:(NSString*)productId {

    self.payInfo = payInfo;
    self.productId = productId;

    if ([SKPaymentQueue canMakePayments]) {
        [self requestProducts:productId];
    } else {
        //不允许程序内付费购买;
        [self.appStoreDelegate sdkAppStoreNotAllowPay];
    }
}

#pragma mark - 请求商品信息
- (void)requestProducts:(NSString*)productId {

    NSSet *productIds = [NSSet setWithObject:productId];
    SKProductsRequest *productsRequest = [[SKProductsRequest alloc] initWithProductIdentifiers:productIds];
    productsRequest.delegate = self;
    [productsRequest start];
}

当程序调用startPay这个方法,整个购买交易就开始了。payInfo是记录了一些用户信息,到时候要传到游戏服务器去的。productId就是上面说的商品ID。
首先用[SKPaymentQueue canMakePayments]判断一下程序是否可以交易。
然后将productId放到SKProductsRequest里面,调用一下start,这时候商品ID就被发送到苹果服务器了。
在此之前,我们要先设置好回调,不然接受不到返回来的商品信息

productsRequest.delegate = self;

然后重写回调方法

pragma mark - appstore回调 请求商品信息回调
- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response {

    NSArray *products = response.products;
    SKProduct *product = [products count] > 0 ? [products objectAtIndex:0] : nil;
    if (product) {
        //添加付款请求到队列
        [[SKPaymentQueue defaultQueue] addPayment:payment];
    } else {
        //无法获取商品信息
        [self.appStoreDelegate sdkAppStoreNoProductInfo];
        SDKLog(@"无法获取商品信息");
    }   
}

这边我们先把返回来的商品信息包装一下,然后放到交易队列里面去
[[SKPaymentQueue defaultQueue] addPayment:payment];
这时候就开始交易啦!

交易回调

商品信息放到交易队列里面以后,会回调paymentQueue: updatedTransactions:这个方法这个方法。这个方法的作用是告诉你交易进行到哪个步骤了。

#pragma mark - appstore回调 付款请求回调
- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transaction {
    for(SKPaymentTransaction *tran in transaction){

        switch (tran.transactionState) {
            case SKPaymentTransactionStatePurchasing:
                //购买中
                [self.appStoreDelegate sdkAppStorePaying];
                break;
            case SKPaymentTransactionStateDeferred:
                //购买中 交易被推迟
                [self.appStoreDelegate sdkAppStorePaying];
                break;
            case SKPaymentTransactionStateFailed:
                //购买监听 交易失败
                [self failedTransaction:tran];
                break;
            case SKPaymentTransactionStatePurchased:
                //购买监听 交易完成
                [self completeTransaction:tran];
                break;
            case SKPaymentTransactionStateRestored:
                //购买监听 恢复成功
                [self restoreTransaction:tran];
                break;
            default:
                break;
        }
    }
}

这边是一个switch,分别对应调用交易的各个步骤:

  • SKPaymentTransactionStatePurchasing 购买中。这时候你可以弹出一个loading框,提示用户交易正在进行。
  • SKPaymentTransactionStateDeferred 交易被推迟。loading框还在。
  • SKPaymentTransactionStateFailed 交易失败。我们调用交易失败的事务,比如通知用户交易失败。取消交易也在交易失败的范畴。
  • SKPaymentTransactionStatePurchased 交易成功。我们调用交易成功的事务,比如到服务器验证票据和订单信息。
  • SKPaymentTransactionStateRestored 恢复成功。这一个项目在游戏中通常是没有用到的。我们可以忽略。
#pragma mark - 交易事务处理
// 交易成功
- (void)completeTransaction:(SKPaymentTransaction *)transaction {
    [self checkReceipt:transaction];
    [self finishTransaction:transaction wasSuccessful:YES];
}
// 交易失败
- (void)failedTransaction:(SKPaymentTransaction *)transaction {
    [self.appStoreDelegate sdkAppStorePayComplete:NO];
    [self finishTransaction:transaction wasSuccessful:NO];
}
// 交易恢复
- (void)restoreTransaction:(SKPaymentTransaction *)transaction {
    [self.appStoreDelegate sdkAppStorePayComplete:YES];
    [self finishTransaction:transaction wasSuccessful:YES];
}
//结束交易事务
- (void)finishTransaction:(SKPaymentTransaction *)transaction wasSuccessful:(BOOL)wasSuccessful {
    [[SKPaymentQueue defaultQueue] finishTransaction:transaction];
}

所有的事务,到最后都要调用一下finishTransaction这个方法来结束事务。这个方法里面,我们把刚刚记录下来的订单删除。并且调用一下SKPaymentQueue的finishTransaction。这样一个完整的交易才算结束。
如果没有调用SKPaymentQueue的finishTransaction,交易不会关闭。

在这边我们把交易的大概流程走了一遍。下一篇我们来讲讲如何验证票据和防止丢单。

  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值