iOS 应用内购买(IAP)

一、什么情况下需要使用内购?

当你的应用中包括类似订阅、会员或者需要购买才能给到的服务以及开放功能使用等功能时就要考虑内购了

二、应用内购买需要做哪些准备?

1、签署 Paid Applications agreement(《付费应用程序协议》)
2、在 iTunes Connect 中配置 App 内购买项目
3、在 Xcode 中启用 App 内购买项目
4、设计并创建 App 内购买项目
详细内容可参考 App 内购买项目配置流程

三、内购API购买流程

1、通过SKPaymentQueue的canMakePayments方法判断是否可进行支付
2、通过SKPaymentQueue的addTransactionObserver:添加交易对象观察者
3、通过SKProductsRequest发起支付请求,并添加代理SKProductsRequestDelegate
4、当请求响应是通过- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response;方法回调
5、在上述代理方法中创建SKPayment对象并添加至SKPaymentQueue中,
6、当交易结束时会通过- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transaction;方法回调,在交易成功后,需要验证交易凭证、与服务器交互订单交易状态等信息

四、代码实现

#import "ApplePayOperation.m"
#import 

#define VerifyReceipt @"https://sandbox.itunes.apple.com/verifyReceipt"
//#define VerifyReceipt @"https://buy.itunes.apple.com/verifyReceipt"

@interface ApplePayOperation () 
{
    /** 当前支付事务 */
    SKPaymentTransaction *_currentTransaction;
}
@end

@implementation ApplePayOperation

#pragma mark - Life Cycle
+ (instancetype)payOperation
{
    return [ApplePayOperation new];
}

- (instancetype)init
{
    if (self = [super init])
    {
        [[SKPaymentQueue defaultQueue] addTransactionObserver:self];
    }
    
    return self;
}

- (void)dealloc
{
    [[SKPaymentQueue defaultQueue] removeTransactionObserver:self];
}

#pragma mark - Public Method
- (void)payWithProductID:(NSString *)productID
{
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        
        if ([SKPaymentQueue canMakePayments])
        {
            [self _payWithProductID:productID];
        }
    });
}

- (void)payEnd
{
    if (_currentTransaction)
    {
        [[SKPaymentQueue defaultQueue] finishTransaction:_currentTransaction];
    }
}

#pragma mark - Private Method
- (void)_payWithProductID:(NSString *)productID
{
    SKProductsRequest *request = [[SKProductsRequest alloc] initWithProductIdentifiers:[NSSet setWithArray:[NSArray arrayWithObject:productID]]];
    request.delegate = self;
    [request start];
}

- (void)_payFailed
{
    if ([_delegate respondsToSelector:@selector(applePayOperationFailed)])
    {
        [_delegate applePayOperationFailed];
    }
}

- (void)_verifyPurchaseWithPaymentTransaction:(SKPaymentTransaction *)transaction
{
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
       
        // 从沙盒中获取交易凭证并且拼接成请求体数据
        NSURL *receiptUrl = [[NSBundle mainBundle] appStoreReceiptURL];
        NSData *receiptData = [NSData dataWithContentsOfURL:receiptUrl];
        
        // 转化为base64字符串
        NSString *receiptString = [receiptData base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithLineFeed];
        
        // 拼接请求数据
        NSString *bodyString = [NSString stringWithFormat:@"{\"receipt-data\" : \"%@\"}", receiptString];
        NSData *bodyData = [bodyString dataUsingEncoding:NSUTF8StringEncoding];
        
        // 创建请求到苹果官方进行购买验证
        NSURL *url = [NSURL URLWithString:VerifyReceipt];
        NSMutableURLRequest *requestM = [NSMutableURLRequest requestWithURL:url];
        requestM.HTTPBody = bodyData;
        requestM.HTTPMethod = @"POST";
        
        // 创建连接并发送同步请求
        NSError *error = nil;
        NSData *responseData = [NSURLConnection sendSynchronousRequest:requestM returningResponse:nil error:&error];
        
        if (error)
        {
            
            NSLog(@"验证购买过程中发生错误,错误信息:%@", error.localizedDescription);
            return;
        }
        
        NSDictionary *dic = [NSJSONSerialization JSONObjectWithData:responseData options:NSJSONReadingAllowFragments error:nil];
        NSLog(@"%@",dic);
        
        dispatch_async(dispatch_get_main_queue(), ^{
            
            NSDictionary *dicReceipt = dic[@"receipt"];
            NSDictionary *dicInApp = [dicReceipt[@"in_app"] firstObject];
            NSString *payID = dicInApp[@"product_id"];
           
            // 成功验证
            if ([dic[@"status"] intValue] == 0)
            {
                // 交易成功后需要做的在这里写
            }
            else
            {
                NSLog(@"购买失败,未通过验证!");
                
                [self _payFailed];
                [[SKPaymentQueue defaultQueue] finishTransaction:transaction];
            }
        });
    });
}

#pragma mark - Delegate
#pragma mark -SKProductsRequestDelegate
- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response
{
    if (response.products.count > 0)
    {
        SKPayment *payment = [SKPayment paymentWithProduct:response.products[0]];
        [[SKPaymentQueue defaultQueue] addPayment:payment];
    }
    else
    {
        [self _payFailed];
    }
}

- (void)completeTransaction:(SKPaymentTransaction *)transaction
{
    NSLog(@"交易结束");
    [[SKPaymentQueue defaultQueue] finishTransaction:transaction];
}

#pragma mark -SKPaymentTransactionObserver
#pragma mark -购买结果
- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transaction
{
    for (SKPaymentTransaction *tran in transaction)
    {
        _currentTransaction = tran;
        
        switch (tran.transactionState)
        {
            case SKPaymentTransactionStatePurchased:
            {
                NSLog(@"交易完成");
                // 验证凭证
                [self _verifyPurchaseWithPaymentTransaction:tran];
            }
                break;
                
            case SKPaymentTransactionStatePurchasing:
            {
                NSLog(@"商品添加进列表");
            }
                break;
                
            case SKPaymentTransactionStateRestored:
            {
                NSLog(@"已经购买过商品");
                [[SKPaymentQueue defaultQueue] finishTransaction:tran];
            }
                break;
                
            case SKPaymentTransactionStateFailed:
            {
                NSLog(@"交易失败");
                
                [self _payFailed];
                [[SKPaymentQueue defaultQueue] finishTransaction:tran];
            }
                break;
                
            default:
                break;
        }
    }
}

@end

五、内购常见问题

1、由于服务器响应失效问题,经常会出现丢单现象,为了避免此现象可以通过记录交易凭证和验证交易凭证来解决此问题
2、苹果内购收入苹果转账时间一般会在交易完成(交易150美元后)当月最后一天之后的 45 日内,想要拿到响应的汇款需要准备相应的资料到银行才能取到汇款,资料一般包括以下部分:
a、产品上架业务协议(互联网邮件对话拷屏);
b、苹果介面有公司产品持股帮;
c、与苹果清算协议

你可能感兴趣的:(iOS 应用内购买(IAP))