苹果内购(IAP)使用

2020-12-09  本文已影响0人  _DN

0.前言:

实在躲不过去了,只能妥协了。😸

1.准备工作:

1.1.在ASC配置协议、税务和银行业务的信息,这一步可以交给PM完成。
1.2.在ASC里面配置项目的内购项。首次添加内购项时,内购项填写完整后需要和主项目一起提交审核。后期新增内购项时可以在内购项列表里面单独添加。


1.2.内购项配置.png

注意:
①内购项配置时的产品ID必须唯一,不能重复。(和已删除的也不要重复)
②根据自己的实际业务选择消费类型。


消费类型.png

2.配置沙箱账号:

2.1.登录ASC,选择“用户和访问”,选择“沙盒”里面的“测试员”,点击“+”弹出配置页,如图2.1.


2.1.沙盒测试账号配置页.png

注意事项:
①里面的所有信息均不必是真实信息,可以随便填写。
②电子邮件:可以随便填写,但必须不能和现有的真实账号重复(尽量蒙个唯一的)。

3.代码集成

3.1.新建一个iap的单例类:iapTool。
说明:之所以用单例来实现,就是为了保证订单的生命周期,防止交易中,由于当前类销毁导致的一系列问题。

3.2.在iapTool.m中引入系统的内购头文件

import <StoreKit/StoreKit.h>

3.3.遵循两个代理

<SKPaymentTransactionObserver,
SKProductsRequestDelegate>

3.4.在iapTool初始化里面添加支付监听。
说明:之所以在此处添加监听是为了保证监听的完整性以及监听的可复用性。

[[SKPaymentQueue defaultQueue] addTransactionObserver:self];

3.5.根据内购项ID(ASC里面自己配置的),去苹果服务器请求产品信息。

//检测是否允许内购
if ([SKPaymentQueue canMakePayments]) 
{
    NSSet *productSet = [NSSet setWithArray:@[@"自己的内购ID"]];
    SKProductsRequest *productRequest = [[SKProductsRequest alloc] initWithProductIdentifiers:productSet];
    productRequest.delegate = self;
    [productRequest start];
} else {
//已禁止内购
}

3.6.执行相关代理

- (void) productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response
{
    SKProduct *requestProduct = nil;
    for (SKProduct *product in response.products) {
        if([product.productIdentifier isEqualToString:@"自己的内购ID"]) {
            requestProduct = product;
        }
    }
    if (requestProduct) {
        //开始下单
        SKPayment *payment = [SKPayment paymentWithProduct:requestProduct];
        [[SKPaymentQueue defaultQueue] addPayment:payment];
    } else {
        //没有查询到相应的产品信息。
    }
}

- (void)request:(SKRequest *)request didFailWithError:(NSError *)error
{
    NSLog(@"请求动作失败");
}

- (void)requestDidFinish:(SKRequest *)request
{
    NSLog(@"请求动作完成");
}

3.7.监听下单结果

- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transaction
{
    for(SKPaymentTransaction *payment in transaction) {
        switch (payment.transactionState) {
            case SKPaymentTransactionStatePurchased:
            {
               NSLog(@"交易完成");
              //结束交易
               [[SKPaymentQueue defaultQueue] finishTransaction:payment];
              //获取收据
                NSData *data = [NSData dataWithContentsOfFile:[[[NSBundle mainBundle] appStoreReceiptURL] path]];
                NSString *receipt = [data base64EncodedStringWithOptions:0];
                 NSLog(@"获取收据 receipt , 发给本地服务器,用于交易验证,根据验证结果下发商品");
                break;
            }
            case SKPaymentTransactionStatePurchasing:
                NSLog(@"交易中");
                break;
            case SKPaymentTransactionStateRestored:
                NSLog(@"恢复购买");
                break;
            case SKPaymentTransactionStateFailed:
            {
               [[SKPaymentQueue defaultQueue] finishTransaction:payment];
                NSLog(@"交易失败");
                if(payment.error.code != SKErrorPaymentCancelled)
                {
                  NSLog(@"交易失败:%@", payment.error.localizedDescription); 
                } else
                {
                    NSLog(@"交易失败:取消了交易"); 
                }
                break;
            }
            case SKPaymentTransactionStateDeferred:
              [[SKPaymentQueue defaultQueue] finishTransaction:payment];
              NSLog(@"未知错误");
                break;
            default:
                break;
        }
    }
}

3.8.将收据发给本地服务器
将交易完成后的收据信息(receipt)发送给自己的服务器,并存储。同时本地服务器须再次校验订单信息,确保准确,并根据校验结果做对应处理(下发对应的商品,或者给出失败原因)
说明:服务器请求苹果的订单校验接口时的请求时间较长,未报错就耐心等待😸

4.注意事项:

4.1.监听到支付结果后,务必要将交易置为完成状态,防止无效监听。

//将交易置为完成状态
[[SKPaymentQueue defaultQueue] finishTransaction:payment];

4.2.用沙箱进行调试的过程中及其不稳定,例如:某些机型调不通、循环弹出验证或ID的登录页面、每次的步骤不一样、二次验证巨慢等一系列问题。
不要慌!,这些基本是苹果服务器的问题,和本地代码关系不大。
如果不放心可以选择给苹果的技术支持反馈一下(反馈周期巨长😢)。


4.3.首次上线内购项,记得将已经通过批准的内购项目添加到app的提交审页面里面,一起提交审核。


4.4.如果需要做消费类型为“自动续订型”的业务,需要单独处理,本篇文章未涉及。


4.5.开始调起支付的时候,需提前检测一下订单,将已完成的订单结束交易。

//检查订单,若有已完成未结束的交易,须首先结束交易。直到符合条件后再开始新的交易。
    NSArray *transactions = [SKPaymentQueue defaultQueue].transactions;
    if (transactions.count > 0) {
        SKPaymentTransaction *transaction = [transactions firstObject];
        if (transaction.transactionState == SKPaymentTransactionStatePurchased) {
            [[SKPaymentQueue defaultQueue] finishTransaction:transaction];
            NSLog(@"find unfinish transacion and finish this transacion");
            return;
        }
    }

说明:
①注意代码中 return 的使用,要适时返回😏。

②注意当前代码的使用位置,要放在请求内购详情之前😏


5.如有需要,欢迎讨论

支付完整上线思路,脱坑指南


嘚嘚

@end

上一篇 下一篇

猜你喜欢

热点阅读