1.概念介绍

<1>苹果内购:

App内购买是指在苹果的 App Store 中购买应用程序的方式。
在玩一些游戏类应用软件,这些应用都可以免费下载,但是在玩的过程中就会需要在应用内付费,否则就只能玩几关之类的。有时候会不小心点击到一些内购按钮,或是小孩乱点导致扣费的情况。
另外苹果手机系统默认的 Apple ID 的密码时效为 15 分钟,意思就是当输入了一次 Apple ID 之后,在接下来的 15 分钟内,若是点击一些付费项目的话,系统就会直接使用 Apple ID 来购买了。

 

2.登录iTunes Connect,进入具体的app,点击右上角的功能,创建以供测试的内购产品

2024iOS 内购配置_内购

3.登录iTunes Connect,进入用户职能,点击沙箱技术测试员,创建测试员账号

2024iOS 内购配置_移动开发_02

注意:

<1>将要创建的测试员账号必须是之前没有注册过App Store的,所以要谨慎注册,谨慎删除。

<2>创建成功之后,我们必须得登录这个邮箱,完成App Store的邮箱验证。

<3>退出当前iPhone的iCloud,App Store的所有账号。

完成以上的操作,即可开始苹果内购的测试。

4.打开Xcode运行项目,开始代码层的编写;

我们先理一下内购的逻辑:

<1>定义好正式和测试的环境;

#if DEBUG
//沙盒测试环境验证
#define SANDBOX @"https://sandbox.itunes.apple.com/verifyReceipt"

#else
//正式环境验证
#define AppStore @"https://buy.itunes.apple.com/verifyReceipt"

#endif

<2>检查当前iPhone是否支持苹果内购;

-(void)startUserIAP{
    [[SKPaymentQueue defaultQueue] addTransactionObserver:self];
    _currentProId = @"yearmoneytest";
    if([SKPaymentQueue canMakePayments]){
        [self requestProductData:@"yearmoneytest"];
    }else{
        NSLog(@"不允许程序内付费");
    }
}

<3>去苹果服务器请求当前app里面的内购产品,如果请求成功,找到自己要购买的产品,并开始支付;

//去苹果服务器请求商品
- (void)requestProductData:(NSString *)type{
    NSLog(@"-------------请求对应的产品信息----------------");
    NSArray *product = [[NSArray alloc] initWithObjects:type,nil];
    NSSet *nsset = [NSSet setWithArray:product];
    SKProductsRequest *request = [[SKProductsRequest alloc] initWithProductIdentifiers:nsset];
    request.delegate = self;
    [request start];
}

//收到产品返回信息
- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response{
    
    NSLog(@"--------------收到产品反馈消息---------------------");
    NSArray *product = response.products;
    if([product count] == 0){
        NSLog(@"--------------没有商品------------------");
        return;
    }
    
    NSLog(@"productID:%@", response.invalidProductIdentifiers);
    NSLog(@"产品付费数量:%lu",(unsigned long)[product count]);
    
    SKProduct *p = nil;
    for (SKProduct *pro in product) {
        NSLog(@"%@", [pro description]);
        NSLog(@"%@", [pro localizedTitle]);
        NSLog(@"%@", [pro localizedDescription]);
        NSLog(@"%@", [pro price]);
        NSLog(@"%@", [pro productIdentifier]);
        
        if([pro.productIdentifier isEqualToString:_currentProId]){
            p = pro;
        }
    }
    
    SKPayment *payment = [SKPayment paymentWithProduct:p];
    
    NSLog(@"发送购买请求");
    [[SKPaymentQueue defaultQueue] addPayment:payment];
}


//请求失败
- (void)request:(SKRequest *)request didFailWithError:(NSError *)error{
    NSLog(@"------------------错误-----------------:%@", error);
}

- (void)requestDidFinish:(SKRequest *)request{
    NSLog(@"------------反馈信息结束-----------------");
}

<4>监听购买的结果,如果购买成功,我们再去苹果服务器验证凭证;

//监听购买结果
- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transaction{
    for(SKPaymentTransaction *tran in transaction){
        switch (tran.transactionState) {
            case SKPaymentTransactionStatePurchased:{
                NSLog(@"交易完成");
                // 发送到苹果服务器验证凭证
                [self verifyPurchaseWithPaymentTransaction];
                [[SKPaymentQueue defaultQueue] finishTransaction:tran];
                
            }
                break;
            case SKPaymentTransactionStatePurchasing:
                NSLog(@"商品添加进列表");
                
                break;
            case SKPaymentTransactionStateRestored:{
                NSLog(@"已经购买过商品");
                
                [[SKPaymentQueue defaultQueue] finishTransaction:tran];
            }
                break;
            case SKPaymentTransactionStateFailed:{
                NSLog(@"交易失败");
                [[NSNotificationCenter defaultCenter] postNotificationName:@"PaymentFailed" object:nil];
                [[SKPaymentQueue defaultQueue] finishTransaction:tran];
            }
                break;
            default:
                break;
        }
    }
}

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

- (void)dealloc{
    [[SKPaymentQueue defaultQueue] removeTransactionObserver:self];
}
/**
 *  验证购买,避免越狱软件模拟苹果请求达到非法购买问题
 *
 */
-(void)verifyPurchaseWithPaymentTransaction{
    //从沙盒中获取交易凭证并且拼接成请求体数据
    NSURL *receiptUrl=[[NSBundle mainBundle] appStoreReceiptURL];
    NSData *receiptData=[NSData dataWithContentsOfURL:receiptUrl];
    
    NSString *receiptString=[receiptData base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithLineFeed];//转化为base64字符串
    
    NSString *bodyString = [NSString stringWithFormat:@"{\"receipt-data\" : \"%@\"}", receiptString];//拼接请求数据
    NSData *bodyData = [bodyString dataUsingEncoding:NSUTF8StringEncoding];
    
    
    //创建请求到苹果官方进行购买验证
    NSURL *url=[NSURL URLWithString:SANDBOX];
    NSMutableURLRequest *requestM=[NSMutableURLRequest requestWithURL:url];
    requestM.HTTPBody=bodyData;
    requestM.HTTPMethod=@"POST";
    
    
    //创建连接并发送同步请求
    [[NSURLSession sharedSession] dataTaskWithRequest:requestM completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
        if (error) {
            NSLog(@"验证购买过程中发生错误,错误信息:%@",error.localizedDescription);
            return;
        }
        
        NSDictionary *dic=[NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:nil];
        NSLog(@"%@",dic);
        
        if([dic[@"status"] intValue]==0){
            NSLog(@"购买成功!");
            [[NSNotificationCenter defaultCenter] postNotificationName:@"PaymentSuccess" object:nil];
            NSDictionary *dicReceipt= dic[@"receipt"];
            NSDictionary *dicInApp=[dicReceipt[@"in_app"] firstObject];
            NSString *productIdentifier= dicInApp[@"product_id"];//读取产品标识
            //如果是消耗品则记录购买数量,非消耗品则记录是否购买过
            NSUserDefaults *defaults=[NSUserDefaults standardUserDefaults];
            if ([productIdentifier isEqualToString:@"yearmoneytest"]) {
                NSInteger purchasedCount=[defaults integerForKey:productIdentifier];//已购买数量
                [defaults setInteger:(purchasedCount+1) forKey:productIdentifier];
            }else{
                [defaults setBool:YES forKey:productIdentifier];
            }
            [defaults synchronize];
            //在此处对购买记录进行存储,可以存储到开发商的服务器端
        }else{
            [[NSNotificationCenter defaultCenter] postNotificationName:@"PaymentFailed" object:nil];
            NSLog(@"购买失败,未通过验证!");
        }
    }];
    
}

以上即是我分享的苹果内购总结,感谢阅读,欢迎指正。为方便大家使用,封装好了一套代码,一句话调用即可,下面是文件代码。

//
//  IAPManager.h
//  traffic
//
//  Created by Tommy on 2017/6/10.
//  Copyright © 2017年 Mqch295. All rights reserved.
//

#import <Foundation/Foundation.h>

@interface IAPManager : NSObject

/***该类的对象必须在内存中一直存在,才可以执行完整个内购的流程***/
-(void)startUserIAP;

@end
//
//  IAPManager.m
//  traffic
//
//  Created by Tommy on 2017/6/10.
//  Copyright © 2017年 Mqch295. All rights reserved.
//

#if DEBUG
//沙盒测试环境验证
#define SANDBOX @"https://sandbox.itunes.apple.com/verifyReceipt"

#else
//正式环境验证
#define AppStore @"https://buy.itunes.apple.com/verifyReceipt"

#endif

#import "IAPManager.h"
#import <StoreKit/StoreKit.h>

@interface IAPManager()<SKPaymentTransactionObserver,SKProductsRequestDelegate>

@property (nonatomic,copy) NSString *currentProId;

@end

@implementation IAPManager

#pragma mark 公有方法

-(void)startUserIAP{
    [[SKPaymentQueue defaultQueue] addTransactionObserver:self];
    _currentProId = @"yearmoneytest";
    if([SKPaymentQueue canMakePayments]){
        [self requestProductData:@"yearmoneytest"];
    }else{
        NSLog(@"不允许程序内付费");
    }
}


#pragma mark 私有方法

//去苹果服务器请求商品
- (void)requestProductData:(NSString *)type{
    NSLog(@"-------------请求对应的产品信息----------------");
    NSArray *product = [[NSArray alloc] initWithObjects:type,nil];
    NSSet *nsset = [NSSet setWithArray:product];
    SKProductsRequest *request = [[SKProductsRequest alloc] initWithProductIdentifiers:nsset];
    request.delegate = self;
    [request start];
}

//收到产品返回信息
- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response{
    
    NSLog(@"--------------收到产品反馈消息---------------------");
    NSArray *product = response.products;
    if([product count] == 0){
        NSLog(@"--------------没有商品------------------");
        return;
    }
    
    NSLog(@"productID:%@", response.invalidProductIdentifiers);
    NSLog(@"产品付费数量:%lu",(unsigned long)[product count]);
    
    SKProduct *p = nil;
    for (SKProduct *pro in product) {
        NSLog(@"%@", [pro description]);
        NSLog(@"%@", [pro localizedTitle]);
        NSLog(@"%@", [pro localizedDescription]);
        NSLog(@"%@", [pro price]);
        NSLog(@"%@", [pro productIdentifier]);
        
        if([pro.productIdentifier isEqualToString:_currentProId]){
            p = pro;
        }
    }
    
    SKPayment *payment = [SKPayment paymentWithProduct:p];
    
    NSLog(@"发送购买请求");
    [[SKPaymentQueue defaultQueue] addPayment:payment];
}


//请求失败
- (void)request:(SKRequest *)request didFailWithError:(NSError *)error{
    NSLog(@"------------------错误-----------------:%@", error);
}

- (void)requestDidFinish:(SKRequest *)request{
    NSLog(@"------------反馈信息结束-----------------");
}

/**
 *  验证购买,避免越狱软件模拟苹果请求达到非法购买问题
 *
 */
-(void)verifyPurchaseWithPaymentTransaction{
    //从沙盒中获取交易凭证并且拼接成请求体数据
    NSURL *receiptUrl=[[NSBundle mainBundle] appStoreReceiptURL];
    NSData *receiptData=[NSData dataWithContentsOfURL:receiptUrl];
    
    NSString *receiptString=[receiptData base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithLineFeed];//转化为base64字符串
    
    NSString *bodyString = [NSString stringWithFormat:@"{\"receipt-data\" : \"%@\"}", receiptString];//拼接请求数据
    NSData *bodyData = [bodyString dataUsingEncoding:NSUTF8StringEncoding];
    
    
    //创建请求到苹果官方进行购买验证
    NSURL *url=[NSURL URLWithString:SANDBOX];
    NSMutableURLRequest *requestM=[NSMutableURLRequest requestWithURL:url];
    requestM.HTTPBody=bodyData;
    requestM.HTTPMethod=@"POST";
    
    
    //创建连接并发送同步请求
    [[NSURLSession sharedSession] dataTaskWithRequest:requestM completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
        if (error) {
            NSLog(@"验证购买过程中发生错误,错误信息:%@",error.localizedDescription);
            return;
        }
        
        NSDictionary *dic=[NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:nil];
        NSLog(@"%@",dic);
        
        if([dic[@"status"] intValue]==0){
            NSLog(@"购买成功!");
            [[NSNotificationCenter defaultCenter] postNotificationName:@"PaymentSuccess" object:nil];
            NSDictionary *dicReceipt= dic[@"receipt"];
            NSDictionary *dicInApp=[dicReceipt[@"in_app"] firstObject];
            NSString *productIdentifier= dicInApp[@"product_id"];//读取产品标识
            //如果是消耗品则记录购买数量,非消耗品则记录是否购买过
            NSUserDefaults *defaults=[NSUserDefaults standardUserDefaults];
            if ([productIdentifier isEqualToString:@"yearmoneytest"]) {
                NSInteger purchasedCount=[defaults integerForKey:productIdentifier];//已购买数量
                [defaults setInteger:(purchasedCount+1) forKey:productIdentifier];
            }else{
                [defaults setBool:YES forKey:productIdentifier];
            }
            [defaults synchronize];
            //在此处对购买记录进行存储,可以存储到开发商的服务器端
        }else{
            [[NSNotificationCenter defaultCenter] postNotificationName:@"PaymentFailed" object:nil];
            NSLog(@"购买失败,未通过验证!");
        }
    }];
    
}
//监听购买结果
- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transaction{
    for(SKPaymentTransaction *tran in transaction){
        switch (tran.transactionState) {
            case SKPaymentTransactionStatePurchased:{
                NSLog(@"交易完成");
                // 发送到苹果服务器验证凭证
                [self verifyPurchaseWithPaymentTransaction];
                [[SKPaymentQueue defaultQueue] finishTransaction:tran];
                
            }
                break;
            case SKPaymentTransactionStatePurchasing:
                NSLog(@"商品添加进列表");
                
                break;
            case SKPaymentTransactionStateRestored:{
                NSLog(@"已经购买过商品");
                
                [[SKPaymentQueue defaultQueue] finishTransaction:tran];
            }
                break;
            case SKPaymentTransactionStateFailed:{
                NSLog(@"交易失败");
                [[NSNotificationCenter defaultCenter] postNotificationName:@"PaymentFailed" object:nil];
                [[SKPaymentQueue defaultQueue] finishTransaction:tran];
            }
                break;
            default:
                break;
        }
    }
}

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

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

@end