内购项目-代码篇

  • 一、分步骤说明
    • 1、获取商品列表
    • 2、苹果服务器返回的可购买商品
    • 3、下单购买商品
    • 4、购买队列状态变化,判断购买状态是否成功
    • 5、交易验证
    • 6、拿到的收据信息是,此App所有购买的记录
    • 7、恢复商品
  • 二、详细代码
  • 三、内购项目-App Store Connect 详解篇
    • 祝您好运~

一、分步骤说明

1、获取商品列表

由于苹果服务器返回很慢,并且一般我们都会有一个自己的商店界面,就不必向苹果服务器去请求商品列表了。
购买时传要购买商品的ID(在App Store Connect 创建的产品ID)就可以了。

/// 请求苹果的服务器能够销售的商品
/// @param products 【产品ID】
- (void)requestProductsWithProductArray:(NSArray *)products
{NSSet *set = [[NSSet alloc] initWithArray:products];// "异步"请求苹果能否销售SKProductsRequest *request = [[SKProductsRequest alloc] initWithProductIdentifiers:set];request.delegate = self;// 启动请求[request start];
}

2、苹果服务器返回的可购买商品

#pragma mark - SKProductsRequestDelegate/// 获取请求结果,把商品加入到自己的商品列表
/// @param request 请求
/// @param response 返回结果
- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response
{if (self.productDict == nil) {self.productDict = [NSMutableDictionary dictionaryWithCapacity:response.products.count];}NSMutableArray *productArray = [NSMutableArray array];for (SKProduct *product in response.products) {//NSLog(@"%@", product.productIdentifier);[self.productDict setObject:product forKey:product.productIdentifier];[productArray addObject:product];}// 通知代理[self.delegate IAPToolGotProducts:productArray];
}

3、下单购买商品

拿到了苹果服务器返回的可购买商品后,下单进行购买。

/// 下单购买商品
/// @param productID 商品ID
- (void)buyProduct:(NSString *)productID
{// 从自己的商品列表中取出要购买的商品SKProduct *product = self.productDict[productID];// 要购买的产品生成单据SKPayment *payment = [SKPayment paymentWithProduct:product];// 加入队列准备付款购买[[SKPaymentQueue defaultQueue] addPayment:payment];
}

4、购买队列状态变化,判断购买状态是否成功

typedef NS_ENUM(NSInteger, SKPaymentTransactionState) {SKPaymentTransactionStatePurchasing,    //交易被添加到服务器队列中SKPaymentTransactionStatePurchased,     // 交易正在排队,用户已被收费。客户应完成交易SKPaymentTransactionStateFailed,        // 交易在添加到服务器队列之前被取消或失败SKPaymentTransactionStateRestored,      // 交易已从用户的购买历史中恢复SKPaymentTransactionStateDeferred,   // 等待外部操作
};
#pragma mark - SKPaymentTransaction Observer
#pragma mark 购买队列状态变化,判断购买状态是否成功/// 当交易数组发生更改(添加或状态更改)时发送。客户端应该检查交易的状态并适当地完成
/// @param queue 队列
/// @param transactions 交易
- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions
{// 处理结果for (SKPaymentTransaction *transaction in transactions) {NSLog(@"队列状态变化 %@", transaction);// 如果收据状态是购买完成switch (transaction.transactionState) {case SKPaymentTransactionStatePurchased: { // 完成交易//NSLog(@"购买完成 %@", transaction.payment.productIdentifier);if (self.CheckAfterPay) {// 需要向苹果服务器验证一下// 通知代理[self.delegate IAPToolBeginCheckingdWithProductID:transaction.payment.productIdentifier];// 验证购买凭据[self verifyPruchaseWithID:transaction.payment.productIdentifier];} else {// 不需要向苹果服务器验证// 验证凭据,获取到苹果返回的交易凭据// appStoreReceiptURL iOS7.0增加的,购买交易完成后,会将凭据存放在该地址NSURL *receiptURL = [[NSBundle mainBundle] appStoreReceiptURL];// 从沙盒中获取到购买凭据NSData *receiptData = [NSData dataWithContentsOfURL:receiptURL];NSString *encodeStr = [receiptData base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithLineFeed];// 通知代理[self.delegate IAPToolBoughtProductSuccessedWithProductID:transaction.payment.productIdentifierandInfo:nil receipt:encodeStr];}// 将交易从交易队列中删除[[SKPaymentQueue defaultQueue] finishTransaction:transaction];}break;case SKPaymentTransactionStateRestored: { // 恢复购买//NSLog(@"恢复成功 :%@", transaction.payment.productIdentifier);// 通知代理[self.delegate IAPToolRestoredProductID:transaction.payment.productIdentifier];// 将交易从交易队列中删除[[SKPaymentQueue defaultQueue] finishTransaction:transaction];}break;case SKPaymentTransactionStateFailed: { // 加入队列之前取消或失败// 将交易从交易队列中删除[[SKPaymentQueue defaultQueue] finishTransaction:transaction];//NSLog(@"交易失败");[self.delegate IAPToolCanceldWithProductID:transaction.payment.productIdentifier];}break;case SKPaymentTransactionStatePurchasing: { // 交易被添加到服务器队列中NSLog(@"正在购买");}break;default: {NSLog(@"state:%ld",(long)transaction.transactionState);// 将交易从交易队列中删除[[SKPaymentQueue defaultQueue] finishTransaction:transaction];}break;}}
}

5、交易验证

// 发送网络POST请求,对购买凭据进行验证
// 沙盒测试 https://sandbox.itunes.apple.com/verifyReceipt
// 正式环境 https://buy.itunes.apple.com/verifyReceipt

当SKPaymentTransactionStatePurchased 完成交易时,我们需要验证一下。
a、拿到收据上传到自己的服务器进行验证。

NSURL *receiptURL = [[NSBundle mainBundle] appStoreReceiptURL];// 从沙盒中获取到购买凭据NSData *receiptData = [NSData dataWithContentsOfURL:receiptURL];NSString *encodeStr = [receiptData base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithLineFeed];

b、如果是单机就本地向苹果服务器请求验证。

/// 验证购买凭据
/// @param ProductID 商品ID
- (void)verifyPruchaseWithID:(NSString *)ProductID
{// 验证凭据,获取到苹果返回的交易凭据// appStoreReceiptURL iOS7.0增加的,购买交易完成后,会将凭据存放在该地址NSURL *receiptURL = [[NSBundle mainBundle] appStoreReceiptURL];// 从沙盒中获取到购买凭据NSData *receiptData = [NSData dataWithContentsOfURL:receiptURL];// 发送网络POST请求,对购买凭据进行验证//In the test environment, use https://sandbox.itunes.apple.com/verifyReceipt//In the real environment, use https://buy.itunes.apple.com/verifyReceipt// Create a POST request with the receipt data.NSURL *url = [NSURL URLWithString:checkURL];NSLog(@"checkURL:%@",checkURL);// 国内访问苹果服务器比较慢,timeoutInterval需要长一点NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:20.0f];request.HTTPMethod = @"POST";NSString *encodeStr = [receiptData base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithLineFeed];NSString *payload = [NSString stringWithFormat:@"{\"receipt-data\" : \"%@\"}", encodeStr];NSData *payloadData = [payload dataUsingEncoding:NSUTF8StringEncoding];request.HTTPBody = payloadData;// 提交验证请求,并获得官方的验证JSON结果[[[NSURLSession sharedSession] dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {NSData *result = data;// 官方验证结果为空if (result == nil) {//NSLog(@"验证失败");//验证失败,通知代理[self.delegate IAPToolCheckFailedWithProductID:ProductIDandInfo:result];}NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:resultoptions:NSJSONReadingAllowFragments error:nil];//NSLog(@"RecivedVerifyPruchaseDict:%@", dict);if (dict != nil) {// 验证成功,通知代理[self.delegate IAPToolBoughtProductSuccessedWithProductID:ProductIDandInfo:dict receipt:encodeStr];} else {//验证失败,通知代理[self.delegate IAPToolCheckFailedWithProductID:ProductIDandInfo:result];}}] resume];
}

6、拿到的收据信息是,此App所有购买的记录

{environment = Sandbox;receipt =     {"adam_id" = 0;"app_item_id" = 0;"application_version" = 5;"bundle_id" = "com.fly.app";"download_id" = 0;"in_app" =         ({"is_trial_period" = false;"original_purchase_date" = "2020-07-04 12:56:09 Etc/GMT";"original_purchase_date_ms" = 1587214569000;"original_purchase_date_pst" = "2020-07-04 05:56:09 America/Los_Angeles";"original_transaction_id" = 1000000653555670;"product_id" = VIP1;"purchase_date" = "2020-07-04 12:56:09 Etc/GMT";"purchase_date_ms" = 1587214569000;"purchase_date_pst" = "2020-07-04 05:56:09 America/Los_Angeles";quantity = 1;"transaction_id" = 1000000653555670;},{"is_trial_period" = false;"original_purchase_date" = "2020-07-04 14:38:05 Etc/GMT";"original_purchase_date_ms" = 1587220685000;"original_purchase_date_pst" = "2020-04-18 07:38:05 America/Los_Angeles";"original_transaction_id" = 1000000653568586;"product_id" = VIP2;"purchase_date" = "2020-07-04 14:38:05 Etc/GMT";"purchase_date_ms" = 1587220685000;"purchase_date_pst" = "2020-07-04 07:38:05 America/Los_Angeles";quantity = 1;"transaction_id" = 1000000653568586;});"original_application_version" = "1.0";"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";"receipt_creation_date" = "2020-07-04 07:08:53 Etc/GMT";"receipt_creation_date_ms" = 1593832014000;"receipt_creation_date_pst" = "2020-07-04 00:08:53 America/Los_Angeles";"receipt_type" = ProductionSandbox;"request_date" = "2020-07-04 07:08:55 Etc/GMT";"request_date_ms" = 1593832035030;"request_date_pst" = "2020-07-04 00:08:55 America/Los_Angeles";"version_external_identifier" = 0;};status = 0;
}

7、恢复商品

非消耗型项目一定要有恢复商品的功能,不会被拒绝哦~

/// 恢复商品
- (void)restorePurchase
{// 恢复已经完成的所有交易.(仅限永久有效商品)[[SKPaymentQueue defaultQueue] restoreCompletedTransactions];
}

二、详细代码

封装内购工具类
FSInAppPurchaseTool.h

#import <Foundation/Foundation.h>
#import <StoreKit/StoreKit.h>NS_ASSUME_NONNULL_BEGIN/// 内购工具的代理
@protocol FSInAppPurchaseToolDelegate <NSObject>/// 系统错误
-(void)IAPToolSysWrong;/// 可购买商品
/// @param products 商品数组
-(void)IAPToolGotProducts:(NSMutableArray *)products;/// 购买成功
/// @param productID 购买成功的商品ID
/// @param infoDic 官方验证结果
/// @param receipt 凭证
-(void)IAPToolBoughtProductSuccessedWithProductID:(NSString *)productIDandInfo:(nullable NSDictionary *)infoDic receipt:(nonnull NSString *)receipt;/// 取消购买
/// @param productID 商品ID
-(void)IAPToolCanceldWithProductID:(NSString *)productID;/// 购买成功,开始验证购买
/// @param productID 商品ID
-(void)IAPToolBeginCheckingdWithProductID:(NSString *)productID;/// 验证失败
/// @param productID 商品ID
/// @param infoData 官方验证结果
-(void)IAPToolCheckFailedWithProductID:(NSString *)productIDandInfo:(NSData *)infoData;/// 恢复了已购买的商品(永久性商品)
/// @param productID 商品ID
-(void)IAPToolRestoredProductID:(NSString *)productID;/// 恢复了已购买的商品(永久性商品)
/// @param products 商品信息
/// @param receipt 凭证
-(void)IAPToolPaymentQueueRestoreCompletedTransactionsFinished:(NSArray *)products receipt:(nonnull NSString *)receipt;@optional/// 连接itunes store 错误
/// @param error 错误信息
-(void)IAPToolPaymentQueueRestoreCompletedTransactionsFailedWithError:(NSString *)error;@end#pragma mark -FSInAppPurchaseTool/// 内购工具
@interface FSInAppPurchaseTool : NSObject@property (nonatomic, weak) id <FSInAppPurchaseToolDelegate> delegate;/// 购买完后是否在iOS端向服务器验证一次,默认为YES
@property (nonatomic, assign) BOOL CheckAfterPay;+ (FSInAppPurchaseTool *)defaultTool;/// 询问苹果的服务器能够销售哪些商品
/// @param products 商品ID的数组
- (void)requestProductsWithProductArray:(NSArray *)products;/// 用户决定购买商品
/// @param productID 商品ID
- (void)buyProduct:(NSString *)productID;/// 恢复商品(仅限永久有效商品)
- (void)restorePurchase;@endNS_ASSUME_NONNULL_END

FSInAppPurchaseTool.m

#import "FSInAppPurchaseTool.h"/// 苹果服务器购买凭据进行验证
#ifdef DEBUG
#define checkURL @"https://sandbox.itunes.apple.com/verifyReceipt"
#else
#define checkURL @"https://buy.itunes.apple.com/verifyReceipt"
#endif@interface FSInAppPurchaseTool ()<SKPaymentTransactionObserver,SKProductsRequestDelegate>/// 商品字典
@property(nonatomic,strong)NSMutableDictionary *productDict;@end@implementation FSInAppPurchaseToolstatic FSInAppPurchaseTool *storeTool;+ (FSInAppPurchaseTool *)defaultTool{if(!storeTool){storeTool = [FSInAppPurchaseTool new];[storeTool setup];}return storeTool;
}#pragma mark  初始化- (void)setup{self.CheckAfterPay = YES;// 设置购买队列的监听器[[SKPaymentQueue defaultQueue] addTransactionObserver:self];
}#pragma mark 请求苹果的服务器能够销售的商品/// 请求苹果的服务器能够销售的商品
/// @param products 产品
- (void)requestProductsWithProductArray:(NSArray *)products
{// 能够销售的商品NSSet *set = [[NSSet alloc] initWithArray:products];// "异步"请求苹果能否销售SKProductsRequest *request = [[SKProductsRequest alloc] initWithProductIdentifiers:set];request.delegate = self;// 启动请求[request start];
}#pragma mark - SKProductsRequestDelegate/// 获取请求结果,把商品加入到自己的商品列表
/// @param request 请求
/// @param response 返回结果
- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response
{if (self.productDict == nil) {self.productDict = [NSMutableDictionary dictionaryWithCapacity:response.products.count];}NSMutableArray *productArray = [NSMutableArray array];for (SKProduct *product in response.products) {//NSLog(@"%@", product.productIdentifier);[self.productDict setObject:product forKey:product.productIdentifier];[productArray addObject:product];}// 通知代理[self.delegate IAPToolGotProducts:productArray];
}#pragma mark - 下单购买商品/// 下单购买商品
/// @param productID 商品ID
- (void)buyProduct:(NSString *)productID
{// 从自己的商品列表中取出要购买的商品SKProduct *product = self.productDict[productID];// 要购买的产品生成单据SKPayment *payment = [SKPayment paymentWithProduct:product];// 加入队列准备付款购买[[SKPaymentQueue defaultQueue] addPayment:payment];
}#pragma mark - SKPaymentTransaction Observer
#pragma mark 购买队列状态变化,判断购买状态是否成功/// 当交易数组发生更改(添加或状态更改)时发送。客户端应该检查事务的状态并适当地完成
/// @param queue 队列
/// @param transactions 交易
- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions
{// 处理结果for (SKPaymentTransaction *transaction in transactions) {NSLog(@"队列状态变化 %@", transaction);// 如果收据状态是购买完成switch (transaction.transactionState) {case SKPaymentTransactionStatePurchased: { // 完成交易//NSLog(@"购买完成 %@", transaction.payment.productIdentifier);if (self.CheckAfterPay) {// 需要向苹果服务器验证一下// 通知代理[self.delegate IAPToolBeginCheckingdWithProductID:transaction.payment.productIdentifier];// 验证购买凭据[self verifyPruchaseWithID:transaction.payment.productIdentifier];} else {// 不需要向苹果服务器验证// 验证凭据,获取到苹果返回的交易凭据// appStoreReceiptURL iOS7.0增加的,购买交易完成后,会将凭据存放在该地址NSURL *receiptURL = [[NSBundle mainBundle] appStoreReceiptURL];// 从沙盒中获取到购买凭据NSData *receiptData = [NSData dataWithContentsOfURL:receiptURL];NSString *encodeStr = [receiptData base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithLineFeed];// 通知代理[self.delegate IAPToolBoughtProductSuccessedWithProductID:transaction.payment.productIdentifierandInfo:nil receipt:encodeStr];}// 将交易从交易队列中删除[[SKPaymentQueue defaultQueue] finishTransaction:transaction];}break;case SKPaymentTransactionStateRestored: { // 恢复购买//NSLog(@"恢复成功 :%@", transaction.payment.productIdentifier);// 通知代理[self.delegate IAPToolRestoredProductID:transaction.payment.productIdentifier];// 将交易从交易队列中删除[[SKPaymentQueue defaultQueue] finishTransaction:transaction];}break;case SKPaymentTransactionStateFailed: { // 加入队列之前取消或失败// 将交易从交易队列中删除[[SKPaymentQueue defaultQueue] finishTransaction:transaction];//NSLog(@"交易失败");[self.delegate IAPToolCanceldWithProductID:transaction.payment.productIdentifier];}break;case SKPaymentTransactionStatePurchasing: { // 交易被添加到服务器队列中NSLog(@"正在购买");}break;default: {NSLog(@"state:%ld",(long)transaction.transactionState);// 将交易从交易队列中删除[[SKPaymentQueue defaultQueue] finishTransaction:transaction];}break;}}
}/// 当用户购买历史中的所有事务都已成功添加回队列时发送。
/// @param queue 队列
- (void)paymentQueueRestoreCompletedTransactionsFinished:(SKPaymentQueue *)queue {NSMutableArray *products = [[NSMutableArray alloc] init];NSLog(@"received restored transactions: %lu", (unsigned long)queue.transactions.count);for (SKPaymentTransaction *transaction in queue.transactions){[products addObject:transaction.payment.productIdentifier];}NSURL *receiptURL = [[NSBundle mainBundle] appStoreReceiptURL];NSData *receiptData = [NSData dataWithContentsOfURL:receiptURL];NSString *encodeStr = [receiptData base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithLineFeed];[self.delegate IAPToolPaymentQueueRestoreCompletedTransactionsFinished:products receipt:encodeStr];
}/// 当事务从队列中移除时发送(通过finishTransaction:)
/// @param queue 队列
/// @param transactions 交易
- (void)paymentQueue:(SKPaymentQueue *)queue removedTransactions:(NSArray<SKPaymentTransaction *> *)transactions API_AVAILABLE(ios(3.0), macos(10.7)) {}/// 在将用户购买历史记录中的事务添加回队列时遇到错误时发送
/// @param queue 队列
/// @param error 错误信息
- (void)paymentQueue:(SKPaymentQueue *)queue restoreCompletedTransactionsFailedWithError:(NSError *)error API_AVAILABLE(ios(3.0), macos(10.7)) {NSDictionary *userinfo = [[NSDictionary alloc] initWithDictionary:error.userInfo];if(userinfo) {NSString *str = userinfo[NSLocalizedDescriptionKey];if (str.length) {if ([self.delegate respondsToSelector:@selector(IAPToolPaymentQueueRestoreCompletedTransactionsFailedWithError:)]) {[self.delegate IAPToolPaymentQueueRestoreCompletedTransactionsFailedWithError:str];}}} else {if ([self.delegate respondsToSelector:@selector(IAPToolPaymentQueueRestoreCompletedTransactionsFailedWithError:)]) {[self.delegate IAPToolPaymentQueueRestoreCompletedTransactionsFailedWithError:@""];}}
}#pragma mark - 恢复商品/// 恢复商品
- (void)restorePurchase
{// 恢复已经完成的所有交易.(仅限永久有效商品)[[SKPaymentQueue defaultQueue] restoreCompletedTransactions];
}#pragma mark 验证购买凭据/// 验证购买凭据
/// @param ProductID 商品ID
- (void)verifyPruchaseWithID:(NSString *)ProductID
{// 验证凭据,获取到苹果返回的交易凭据// appStoreReceiptURL iOS7.0增加的,购买交易完成后,会将凭据存放在该地址NSURL *receiptURL = [[NSBundle mainBundle] appStoreReceiptURL];// 从沙盒中获取到购买凭据NSData *receiptData = [NSData dataWithContentsOfURL:receiptURL];// 发送网络POST请求,对购买凭据进行验证//In the test environment, use https://sandbox.itunes.apple.com/verifyReceipt//In the real environment, use https://buy.itunes.apple.com/verifyReceipt// Create a POST request with the receipt data.NSURL *url = [NSURL URLWithString:checkURL];NSLog(@"checkURL:%@",checkURL);// 国内访问苹果服务器比较慢,timeoutInterval需要长一点NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:20.0f];request.HTTPMethod = @"POST";NSString *encodeStr = [receiptData base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithLineFeed];NSString *payload = [NSString stringWithFormat:@"{\"receipt-data\" : \"%@\"}", encodeStr];NSData *payloadData = [payload dataUsingEncoding:NSUTF8StringEncoding];request.HTTPBody = payloadData;// 提交验证请求,并获得官方的验证JSON结果[[[NSURLSession sharedSession] dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {NSData *result = data;// 官方验证结果为空if (result == nil) {//NSLog(@"验证失败");//验证失败,通知代理[self.delegate IAPToolCheckFailedWithProductID:ProductIDandInfo:result];}NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:resultoptions:NSJSONReadingAllowFragments error:nil];//NSLog(@"RecivedVerifyPruchaseDict:%@", dict);if (dict != nil) {// 验证成功,通知代理[self.delegate IAPToolBoughtProductSuccessedWithProductID:ProductIDandInfo:dict receipt:encodeStr];} else {//验证失败,通知代理[self.delegate IAPToolCheckFailedWithProductID:ProductIDandInfo:result];}}] resume];
}@end

应用内购工具类

// 创建单例
{FSInAppPurchaseTool *IAPTool = [FSInAppPurchaseTool defaultTool];IAPTool.delegate = self;
}/// 请求store产品
/// @param payno 服务器订单号
/// @param pid store 产品id
- (void)startApplePayWithPayno:(NSString*)payno PID:(NSString*)pid {if (!payno.length) {ALERT(@"下订单失败,请稍后操作!");return;}if (!pid.length) {ALERT(@"请稍后操作!");return;}[self showHUD];[[FSInAppPurchaseTool defaultTool] requestProductsWithProductArray:@[pid]];
}/// 恢复购买
- (IBAction)onRestoreButtonClick:(id)sender {[self showHUD];//检查是否有恢复购买项[[FSInAppPurchaseTool defaultTool] restorePurchase];
}#pragma mark -------- FSInAppPurchaseToolDelegate/// 苹果返回可购买的商品,前往购买
/// @param products 商品数组【SKProduct】
-(void)IAPToolGotProducts:(NSMutableArray *)products {NSLog(@"GotProducts:%@",products);[self hideHUD];if (products.count) {SKProduct *product = products[0];[self showHUD];[[FSInAppPurchaseTool defaultTool] buyProduct:product.productIdentifier];}//    for (SKProduct *product in products){
//        NSLog(@"localizedDescription:%@\nlocalizedTitle:%@\nprice:%@\npriceLocale:%@\nproductID:%@",
//              product.localizedDescription,
//              product.localizedTitle,
//              product.price,
//              product.priceLocale,
//              product.productIdentifier);
//        NSLog(@"--------------------------");
//    }
}/// 支付失败/取消
/// @param productID 商品id
-(void)IAPToolCanceldWithProductID:(NSString *)productID {NSLog(@"canceld:%@",productID);[self hideHUD];
}/// 支付成功 本地向苹果服务器进行验证 (CheckAfterPay为YES 执行此步骤)
/// @param productID 商品id
-(void)IAPToolBeginCheckingdWithProductID:(NSString *)productID {FSLog(@"BeginChecking:%@",productID);[self hideHUD];
}/// 支付成功,拿到收据传到自己的服务器进行验证 (CheckAfterPay为NO 执行此步骤,为YES时,验证成功也会执行)
/// @param productID 商品id
/// @param infoDic 验证结果
/// @param receipt 收据
-(void)IAPToolBoughtProductSuccessedWithProductID:(NSString *)productIDandInfo:(nullable NSDictionary *)infoDic receipt:(nonnull NSString *)receipt {FSLog(@"BoughtSuccessed:%@",productID);FSLog(@"successedInfo:%@",infoDic);[self hideHUD];NSString *payno = self.payinfo[productID];if (payno.length) {// 请求自己服务器进行验证[self requestPortCheckApplePay:receipt Payno:payno];} else {FSLog(@"订单号有误");}
}/// 支付成功了,但向苹果服务器验证失败了
/// @param productID 商品id
/// @param infoData 验证结果
-(void)IAPToolCheckFailedWithProductID:(NSString *)productIDandInfo:(NSData *)infoData {FSLog(@"CheckFailed:%@",productID);[self hideHUD];
}/// 挨个返回已购买的商品(仅限永久有效商品)
/// @param productID 商品id
-(void)IAPToolRestoredProductID:(NSString *)productID {FSLog(@"Restored:%@",productID);
}/// 返回所有已购买的记录
/// @param products 商品数组
/// @param receipt 收据
-(void)IAPToolPaymentQueueRestoreCompletedTransactionsFinished:(NSArray *)products receipt:(NSString *)receipt {FSLog(@"Restored Finished%@",products);[self hideHUD];self.restoreProducts = products;self.restoreReceipt = receipt;if (products.count) {/// 有购买记录就显示恢复购买self.restoreButton.hidden = NO;if (self.restoreReceipt.length) {// 向自己服务器请求恢复购买[self requestPortRestore:self.restoreReceipt];}} else {ALERT(@"没有购买记录,无需购买恢复");}
}/// 恢复购买失败 (登录appleid 弹窗 取消)
- (void)IAPToolPaymentQueueRestoreCompletedTransactionsFailedWithError:(NSString *)error {FSLog(@"Restored Failed%@",error);[self hideHUD];
}//内购系统错误了
-(void)IAPToolSysWrong {FSLog(@"SysWrong");[self hideHUD];
}

三、内购项目-App Store Connect 详解篇

iOS App Store Connect 内购详解.

祝您好运~

iOS 内购详解-代码篇相关推荐

  1. 苹果服务器维护时间表2019,ios 内购详解(2019)

    #import "EInAppPurchasing.h" #import #if TARGET_IPHONE_SIMULATOR // 开发时模拟器使用的验证服务器地址 #defi ...

  2. IOS内购验证 (Java版)

    此处给各位贴出apple官方文档 App 内购买项目配置流程 apple 收据文档 apple 收据responseBody字段释义 IOS内购逻辑图 IOS内购验证相关代码 package xxxx ...

  3. iOS 内购(In-App Purchase)详解

    iOS 内购(In-App Purchase)详解 概述 IAP 全称:In-App Purchase,是指苹果 App Store 的应用内购买,是苹果为 App 内购买虚拟商品或服务提供的一套交易 ...

  4. iVX低代码平台系列详解 -- 概述篇(二)

    写在前面 ivx动手尝试电梯:ivx在线编辑器 iVX系列教程持续更新中 上篇文章可看:iVX低代码平台系列详解 – 概述篇(一) ivx目录 写在前面 一.iVX优势 1.快速学习 2.快速开发 3 ...

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

    iOS 内购IAP(In-App Purchases)代码实现(上) iOS 内购,也叫内支付,是在iOS应用内部,向苹果服务器发起购买请求的过程.我们在这边来讲一讲代码的实现过程.还有,在做内购的时 ...

  6. IOS 多线程04-GCD详解 底层并发 API

    IOS 多线程04-GCD详解 底层并发 API 注:本人是翻译过来,并且加上本人的一点见解. 前言 想要揭示出表面之下深层次的一些可利用的方面.这些底层的 API 提供了大量的灵活性,随之而来的是大 ...

  7. iOS 2D绘图详解(Quartz 2D)之路径(点,直线,虚线,曲线,圆弧,椭圆,矩形)

    前言:一个路径可以包含由一个或者多个shape以及子路径subpath,quartz提供了很多方便的shape可以直接调用.例如:point,line,Arc(圆弧),Curves(曲线),Ellip ...

  8. iOS核心动画详解swift版----基础动画

    2019独角兽企业重金招聘Python工程师标准>>> iOS核心动画详解swift版---基础动画 创建工程,添加2个ViewController,通过rootViewContro ...

  9. iOS内购-防越狱破解刷单

    ---------------------------2018.10.16更新--------------------------- 最近我们公司丢单率上涨,尤其是10月份比9月份来说丢单率翻了3倍, ...

最新文章

  1. android 按下home键执行什么,Android下得到Home键按下的消息
  2. 六、配置Oracle数据库的网络环境
  3. How to sign app
  4. .NET Core 容器化调查
  5. linux终端关闭时为什么会导致在其上启动的进程退出?
  6. C#算法设计之知识储备
  7. logistic公式形式的由来,从广义线性回归说起
  8. 解决摹客iDoc插件在Sketch中无法正常使用,切图和标注尺寸不一致的问题
  9. 理解 LSTM 及其图示
  10. matlab中小波工具箱下载,matlab小波工具箱小波分析步骤
  11. 小米路由器mini刷lede_小米 mini 路由器刷 openwrt
  12. 微信小程序底部导航栏——tabBar
  13. 05JavaScript输出
  14. 武汉为什么进不了互联网第一梯队?
  15. 解读 | 自监督视觉特征学习综述
  16. Python高效编程的19个技巧
  17. 家族谱树形数据结构实现
  18. copy(copy)
  19. python画log图
  20. python dialect='excel'是什么意思_python excel自动化写入大数据量数据

热门文章

  1. php filereader,new FileReader()
  2. 必胜客联合创办人去世 享年82岁
  3. IBatis之Iterate
  4. 22年11月-自研-面试题
  5. 游戏开发学习交流群,欢迎加入(875867499)
  6. 【分享】身为一个资深的“收藏程序猿”必须知道的一些网址(建议收藏)
  7. 微信企业号开发(7)--自定义菜单
  8. 【前端面试知识题】- 3. HTML CSS
  9. 北大计算机专业胡亮,胡亮-吉林大学计算机科学与技术学院
  10. SQL Server 分布式重播(Distributed Replay)