iOS开发内购详细

一、最近公司很多的项目用到了内购,抽空整理下内购的详细内容吧。

如对你有帮助,请不要吝惜打赏和喜欢,谢谢!

一....iOS开发内购全套图文教程


======================第一部分协议===============


第一步.png

第二步.jpg

第三步.jpg

第四步.png

第五步.png

第六步.png

第七步.jpg

第八步.jpg

第九步.jpg

第十步.png

CNAPS CODE 查询地址
https://e.czbank.com/CORPORBANK/query_unionBank_index.jsp


十一步.jpg

十二步.jpg

十三步.png

十四步.png

十五步.jpg

十七步.jpg

十八步.jpg

十九步.png

2016/11/18号更新


十九步(1).png

十九步(2).png

没显示的都是可以不填的,主要是打钩 title 和最后面的Self


二十步.png

=============第二部分创建内购项目============


1.png

2.png

3.png

4.png

5.png

6.png

7.png

===========第三部分贴加内购项目测试账号==========


创建测试账号.png

沙盒测试员.png

账号信息.png

=============第四部分主要实现代码==========

首先导入StoreKit.framework

.h文件

#import <StoreKit/StoreKit.h>

enum{
IAP0p20=20,
IAP1p100,
IAP4p600,
IAP9p1000,
IAP24p6000,
}buyCoinsTag;

//代理
@interface RechargeVC : UIViewController <SKPaymentTransactionObserver,SKProductsRequestDelegate >

{
int buyType;
}

- (void) requestProUpgradeProductData;

-(void)RequestProductData;

-(void)buy:(int)type;

- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions;

-(void) PurchasedTransaction: (SKPaymentTransaction *)transaction;

- (void) completeTransaction: (SKPaymentTransaction *)transaction;

- (void) failedTransaction: (SKPaymentTransaction *)transaction;

-(void) paymentQueueRestoreCompletedTransactionsFinished: (SKPaymentTransaction *)transaction;

-(void) paymentQueue:(SKPaymentQueue *) paymentQueue restoreCompletedTransactionsFailedWithError:(NSError *)error;

- (void) restoreTransaction: (SKPaymentTransaction *)transaction;

-(void)provideContent:(NSString *)product;

-(void)recordTransaction:(NSString *)product;

@end

.m文件

#import "RechargeVC.h"

//在内购项目中创的商品单号
#define ProductID_IAP0p20 @"Nada.JPYF01"//20
#define ProductID_IAP1p100 @"Nada.JPYF02" //100
#define ProductID_IAP4p600 @"Nada.JPYF03" //600
#define ProductID_IAP9p1000 @"Nada.JPYF04" //1000
#define ProductID_IAP24p6000 @"Nada.JPYF05" //6000

@interface RechargeVC ()

@end

@implementation RechargeVC

- (void)viewDidLoad {

    [super viewDidLoad];

    [[SKPaymentQueue defaultQueue] addTransactionObserver:self];
    [self buy:IAP0p20];

}

-(void)buy:(int)type
{
    buyType = type;
    if ([SKPaymentQueue canMakePayments]) {
    [self RequestProductData];
    NSLog(@"允许程序内付费购买");
}
else
{
    NSLog(@"不允许程序内付费购买");
    UIAlertView *alerView =  [[UIAlertView alloc] initWithTitle:@"提示"
    message:@"您的手机没有打开程序内付费购买"
    delegate:nil cancelButtonTitle:NSLocalizedString(@"关闭",nil) otherButtonTitles:nil];

    [alerView show];

    }
}

-(void)RequestProductData
{
    NSLog(@"---------请求对应的产品信息------------");
    NSArray *product = nil;
    switch (buyType) {
        case IAP0p20:
        product=[[NSArray alloc] initWithObjects:ProductID_IAP0p20,nil];
        break;
        case IAP1p100:
        product=[[NSArray alloc] initWithObjects:ProductID_IAP1p100,nil];
        break;
        case IAP4p600:
        product=[[NSArray alloc] initWithObjects:ProductID_IAP4p600,nil];
        break;
        case IAP9p1000:
        product=[[NSArray alloc] initWithObjects:ProductID_IAP9p1000,nil];
        break;
        case IAP24p6000:
        product=[[NSArray alloc] initWithObjects:ProductID_IAP24p6000,nil];
        break;

        default:
        break;
}
    NSSet *nsset = [NSSet setWithArray:product];
    SKProductsRequest *request=[[SKProductsRequest alloc] initWithProductIdentifiers: nsset];
    request.delegate=self;
    [request start];

}

//<SKProductsRequestDelegate> 请求协议
//收到的产品信息
- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response{

    NSLog(@"-----------收到产品反馈信息--------------");
    NSArray *myProduct = response.products;
    NSLog(@"产品Product ID:%@",response.invalidProductIdentifiers);
    NSLog(@"产品付费数量: %d", (int)[myProduct count]);
    // populate UI
    for(SKProduct *product in myProduct){
    NSLog(@"product info");
    NSLog(@"SKProduct 描述信息%@", [product description]);
    NSLog(@"产品标题 %@" , product.localizedTitle);
    NSLog(@"产品描述信息: %@" , product.localizedDescription);
    NSLog(@"价格: %@" , product.price);
    NSLog(@"Product id: %@" , product.productIdentifier);
}
    SKPayment *payment = nil;
    switch (buyType) {
        case IAP0p20:
        payment  = [SKPayment paymentWithProductIdentifier:ProductID_IAP0p20];    //支付25
        break;
        case IAP1p100:
        payment  = [SKPayment paymentWithProductIdentifier:ProductID_IAP1p100];    //支付108
        break;
        case IAP4p600:
        payment  = [SKPayment paymentWithProductIdentifier:ProductID_IAP4p600];    //支付618
        break;
        case IAP9p1000:
        payment  = [SKPayment paymentWithProductIdentifier:ProductID_IAP9p1000];    //支付1048
        break;
        case IAP24p6000:
        payment  = [SKPayment paymentWithProductIdentifier:ProductID_IAP24p6000];    //支付5898
        break;
        default:
        break;
}
    NSLog(@"---------发送购买请求------------");
    [[SKPaymentQueue defaultQueue] addPayment:payment];

}
- (void)requestProUpgradeProductData
{
    NSLog(@"------请求升级数据---------");
    NSSet *productIdentifiers = [NSSet setWithObject:@"com.productid"];
    SKProductsRequest* productsRequest = [[SKProductsRequest alloc] initWithProductIdentifiers:productIdentifiers];
    productsRequest.delegate = self;
    [productsRequest start];

}
//弹出错误信息
- (void)request:(SKRequest *)request didFailWithError:(NSError *)error{
    NSLog(@"-------弹出错误信息----------");
    UIAlertView *alerView =  [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"Alert",NULL) message:[error localizedDescription]
    delegate:nil cancelButtonTitle:NSLocalizedString(@"Close",nil) otherButtonTitles:nil];
    [alerView show];

}

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

}

-(void) PurchasedTransaction: (SKPaymentTransaction *)transaction{
    NSLog(@"-----PurchasedTransaction----");
    NSArray *transactions =[[NSArray alloc] initWithObjects:transaction, nil];
    [self paymentQueue:[SKPaymentQueue defaultQueue] updatedTransactions:transactions];
}

//<SKPaymentTransactionObserver> 千万不要忘记绑定,代码如下:
//----监听购买结果
//[[SKPaymentQueue defaultQueue] addTransactionObserver:self];

- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions//交易结果
{
    NSLog(@"-----paymentQueue--------");
    for (SKPaymentTransaction *transaction in transactions)
    {
        switch (transaction.transactionState)
        {
            case SKPaymentTransactionStatePurchased:{//交易完成
            [self completeTransaction:transaction];
            NSLog(@"-----交易完成 --------");

            UIAlertView *alerView =  [[UIAlertView alloc] initWithTitle:@""
            message:@"购买成功"
            delegate:nil cancelButtonTitle:NSLocalizedString(@"关闭",nil) otherButtonTitles:nil];

            [alerView show];

        } break;
        case SKPaymentTransactionStateFailed://交易失败
            { [self failedTransaction:transaction];
            NSLog(@"-----交易失败 --------");
            UIAlertView *alerView2 =  [[UIAlertView alloc] initWithTitle:@"提示"
            message:@"购买失败,请重新尝试购买"
            delegate:nil cancelButtonTitle:NSLocalizedString(@"关闭",nil) otherButtonTitles:nil];

            [alerView2 show];

        }break;
        case SKPaymentTransactionStateRestored://已经购买过该商品
            [self restoreTransaction:transaction];
            NSLog(@"-----已经购买过该商品 --------");
            case SKPaymentTransactionStatePurchasing:      //商品添加进列表
            NSLog(@"-----商品添加进列表 --------");
            break;
            default:
            break;
        }
    }
}
- (void) completeTransaction: (SKPaymentTransaction *)transaction

{
    NSLog(@"-----completeTransaction--------");
    // Your application should implement these two methods.
    NSString *product = transaction.payment.productIdentifier;
    if ([product length] > 0) {

    NSArray *tt = [product componentsSeparatedByString:@"."];
    NSString *bookid = [tt lastObject];
    if ([bookid length] > 0) {
    [self recordTransaction:bookid];
    [self provideContent:bookid];
}
}

    // Remove the transaction from the payment queue.

    [[SKPaymentQueue defaultQueue] finishTransaction: transaction];

}

//记录交易
-(void)recordTransaction:(NSString *)product{
    NSLog(@"-----记录交易--------");
}

//处理下载内容
-(void)provideContent:(NSString *)product{
    NSLog(@"-----下载--------");
}

- (void) failedTransaction: (SKPaymentTransaction *)transaction{
    NSLog(@"失败");
    if (transaction.error.code != SKErrorPaymentCancelled)
    {

    }
    [[SKPaymentQueue defaultQueue] finishTransaction: transaction];

}
-(void) paymentQueueRestoreCompletedTransactionsFinished: (SKPaymentTransaction *)transaction{

}

- (void) restoreTransaction: (SKPaymentTransaction *)transaction
{
    NSLog(@" 交易恢复处理");

}

-(void) paymentQueue:(SKPaymentQueue *) paymentQueue restoreCompletedTransactionsFailedWithError:(NSError *)error{
    NSLog(@"-------paymentQueue----");
}

#pragma mark connection delegate
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
    NSLog(@"%@",  [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]);
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection{

}

- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response{
    switch([(NSHTTPURLResponse *)response statusCode]) {
        case 200:
        case 206:
        break;
        case 304:
        break;
        case 400:
        break;
        case 404:
        break;
        case 416:
        break;
        case 403:
        break;
        case 401:
        case 500:
        break;
        default:
        break;
    }
}

- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
    NSLog(@"test");
}

-(void)dealloc
{
    [[SKPaymentQueue defaultQueue] removeTransactionObserver:self];//解除监听

}

@end

二......iOS开发内购详细版本说明

1、先从内购的iTunesConnect里配置说起吧,我们先进入苹果的iTunesConnect链接https://itunesconnect.apple.com,然后进入入下界面。



银行信息填写

填写好银行卡信息和公司地址等信息以后,第一步算完成了。

2、进入iTunesConnect选择我的APP模块,创建新的APP,绑定好你在苹果开发者中心创建的apple IDS还有bundle id,那么就创建成功了一个新的APP应用。如下图:



创建APP

3、进入新创建的APP应用,点击如图所示功能按钮:



我的APP“功能”

4、进入功能以后我们就可以创建我们想要的内购产品的ID了,一般都会存在如下几个选择项:



选择类型

5、我们公司的项目由于都是直播类型的课程购买,所以用的是消耗型的项目,选择好然后就进入创建界面里去创建产品了。



需要填写的几项

6、填写好这几项,一个新的内购产品就创建成功了,我们需要记录下每个产品的内购ID,也就是唯一ID,为以后购买产品做准备。

7、我们需要在工程里配置好证书,测试证书是必须的因为我们内购需要连接到苹果的App Store的,需要正式的测试证书才能测试,同时把下图工程中的这一配置打开:



这是很重要的一步

二、讲完上面基本的配置以后,我们进入我们最重要的部分,那就是我们的代码部分。

1、要使用苹果的内购功能,我们需要引入苹果的头件“#import<StoreKit/StoreKit.h>”,引入进来以后,我们就需要引入"SKProductsRequestDelegate,SKPaymentTransactionObserver"这两个代理,我们需要在内购的那个页面viewDidLoad方法里直接调用方法,如下图:



开启内购检测

然后接下来就是几个最重要的代理方法了,如果正常的内购能够走通,那么这几个代理方法就会很流畅的运行过去,并且返回你所购买的商品的信息。让我们一步步来分析:



内购购买(1)



内购购买(2)



内购购买(3)



内购购买(4)



内购购买(5)



内购购买(6)



内购完成

1.必须用真机测试。
2.测试的时候必须退出自己的apple ID。弹出页面后登陆沙盒的测试apple id。

#import "TestPayController.h"

// 1.首先导入支付包
#import <StoreKit/StoreKit.h>

// 2.设置代理服务
@interface TestPayController ()<SKPaymentTransactionObserver,SKProductsRequestDelegate>

@end

@implementation TestPayController

- (void)viewDidLoad {
    [super viewDidLoad];
    self.view.backgroundColor = [UIColor whiteColor];

    //3.创建测试按钮
    UIButton *testBtn = [[UIButton alloc] initWithFrame:CGRectMake(100, 100, 100, 100)];
    testBtn.backgroundColor = [UIColor redColor];
    [testBtn addTarget:self action:@selector(clickTestBtnAction) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:testBtn];

    // 4.设置支付服务
    [[SKPaymentQueue defaultQueue] addTransactionObserver:self];


}

//点击测试按钮
- (void)clickTestBtnAction
{

    // 5.点击按钮的时候判断app是否允许apple支付

    //如果app允许applepay
    if ([SKPaymentQueue canMakePayments]) {
        NSLog(@"yes");

        // 6.请求苹果后台商品
        [self getRequestAppleProduct];
    }
    else
    {
        NSLog(@"not");
    }
}

//请求苹果商品
- (void)getRequestAppleProduct
{
    // 7.这里的com.czchat.CZChat01就对应着苹果后台的商品ID,他们是通过这个ID进行联系的。
    NSArray *product = [[NSArray alloc] initWithObjects:@"com.czchat.CZChat01",nil];

    NSSet *nsset = [NSSet setWithArray:product];

    // 8.初始化请求
    SKProductsRequest *request = [[SKProductsRequest alloc] initWithProductIdentifiers:nsset];
    request.delegate = self;

    // 9.开始请求
    [request start];
}

// 10.接收到产品的返回信息,然后用返回的商品信息进行发起购买请求
- (void) productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response
{
    NSArray *product = response.products;

    //如果服务器没有产品
    if([product count] == 0){
        NSLog(@"nothing");
        return;
    }

    SKProduct *requestProduct = nil;
    for (SKProduct *pro in product) {

        NSLog(@"%@", [pro description]);
        NSLog(@"%@", [pro localizedTitle]);
        NSLog(@"%@", [pro localizedDescription]);
        NSLog(@"%@", [pro price]);
        NSLog(@"%@", [pro productIdentifier]);

        // 11.如果后台消费条目的ID与我这里需要请求的一样(用于确保订单的正确性)
        if([pro.productIdentifier isEqualToString:@"com.czchat.CZChat01"]){
            requestProduct = pro;
        }
    }

    // 12.发送购买请求
    SKPayment *payment = [SKPayment paymentWithProduct:requestProduct];
    [[SKPaymentQueue defaultQueue] addPayment:payment];
}

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

//反馈请求的产品信息结束后
- (void)requestDidFinish:(SKRequest *)request{
    NSLog(@"信息反馈结束");
}

// 13.监听购买结果
- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transaction{
    for(SKPaymentTransaction *tran in transaction){

        switch (tran.transactionState) {
            case SKPaymentTransactionStatePurchased:
                NSLog(@"交易完成");

                break;
            case SKPaymentTransactionStatePurchasing:
                NSLog(@"商品添加进列表");

                break;
            case SKPaymentTransactionStateRestored:
                NSLog(@"已经购买过商品");

                break;
            case SKPaymentTransactionStateFailed:
                NSLog(@"交易失败");

                break;
            default:
                break;
        }
    }
}

// 14.交易结束,当交易结束后还要去appstore上验证支付信息是否都正确,只有所有都正确后,我们就可以给用户方法我们的虚拟物品了。
- (void)completeTransaction:(SKPaymentTransaction *)transaction
{
    NSString * str=[[NSString alloc]initWithData:transaction.transactionReceipt encoding:NSUTF8StringEncoding];

    NSString *environment=[self environmentForReceipt:str];
    NSLog(@"----- 完成交易调用的方法completeTransaction 1--------%@",environment);


    // 验证凭据,获取到苹果返回的交易凭据
    // appStoreReceiptURL iOS7.0增加的,购买交易完成后,会将凭据存放在该地址
    NSURL *receiptURL = [[NSBundle mainBundle] appStoreReceiptURL];
    // 从沙盒中获取到购买凭据
    NSData *receiptData = [NSData dataWithContentsOfURL:receiptURL];
    /**
     20      BASE64 常用的编码方案,通常用于数据传输,以及加密算法的基础算法,传输过程中能够保证数据传输的稳定性
     21      BASE64是可以编码和解码的
     22      */
    NSString *encodeStr = [receiptData base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithLineFeed];

    NSString *sendString = [NSString stringWithFormat:@"{\"receipt-data\" : \"%@\"}", encodeStr];
    NSLog(@"_____%@",sendString);
    NSURL *StoreURL=nil;
    if ([environment isEqualToString:@"environment=Sandbox"]) {

        StoreURL= [[NSURL alloc] initWithString: @"https://sandbox.itunes.apple.com/verifyReceipt"];
    }
    else{

        StoreURL= [[NSURL alloc] initWithString: @"https://buy.itunes.apple.com/verifyReceipt"];
    }
    //这个二进制数据由服务器进行验证;zl
    NSData *postData = [NSData dataWithBytes:[sendString UTF8String] length:[sendString length]];

    NSLog(@"++++++%@",postData);
    NSMutableURLRequest *connectionRequest = [NSMutableURLRequest requestWithURL:StoreURL];

    [connectionRequest setHTTPMethod:@"POST"];
    [connectionRequest setTimeoutInterval:50.0];//120.0---50.0zl
    [connectionRequest setCachePolicy:NSURLRequestUseProtocolCachePolicy];
    [connectionRequest setHTTPBody:postData];

    //开始请求
    NSError *error=nil;
    NSData *responseData=[NSURLConnection sendSynchronousRequest:connectionRequest returningResponse:nil error:&error];
    if (error) {
        NSLog(@"验证购买过程中发生错误,错误信息:%@",error.localizedDescription);
        return;
    }
    NSDictionary *dic=[NSJSONSerialization JSONObjectWithData:responseData options:NSJSONReadingAllowFragments error:nil];
    NSLog(@"请求成功后的数据:%@",dic);
//这里可以等待上面请求的数据完成后并且state = 0 验证凭据成功来判断后进入自己服务器逻辑的判断,也可以直接进行服务器逻辑的判断,验证凭据也就是一个安全的问题。楼主这里没有用state = 0 来判断。
    //    [[SKPaymentQueue defaultQueue] finishTransaction: transaction];

    NSString *product = transaction.payment.productIdentifier;

    NSLog(@"transaction.payment.productIdentifier++++%@",product);

    if ([product length] > 0)
    {
        NSArray *tt = [product componentsSeparatedByString:@"."];

        NSString *bookid = [tt lastObject];

        if([bookid length] > 0)
        {

            NSLog(@"打印bookid%@",bookid);
//这里可以做操作吧用户对应的虚拟物品通过自己服务器进行下发操作,或者在这里通过判断得到用户将会得到多少虚拟物品,在后面([self getApplePayDataToServerRequsetWith:transaction];的地方)上传上面自己的服务器。
        }
    }
//此方法为将这一次操作上传给我本地服务器,记得在上传成功过后一定要记得销毁本次操作。调用[[SKPaymentQueue defaultQueue] finishTransaction: transaction];
    [self getApplePayDataToServerRequsetWith:transaction];
}

//结束后一定要销毁
- (void)dealloc
{
    [[SKPaymentQueue defaultQueue] removeTransactionObserver:self];
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
}

-(NSString * )environmentForReceipt:(NSString * )str
{
    str= [str stringByReplacingOccurrencesOfString:@"\r\n" withString:@""];

    str = [str stringByReplacingOccurrencesOfString:@"\n" withString:@""];

    str = [str stringByReplacingOccurrencesOfString:@"\t" withString:@""];

    str=[str stringByReplacingOccurrencesOfString:@" " withString:@""];

    str=[str stringByReplacingOccurrencesOfString:@"\"" withString:@""];

    NSArray * arr=[str componentsSeparatedByString:@";"];

    //存储收据环境的变量
    NSString * environment=arr[2];
    return environment;
}

@end


2、进过我这一堆的代码组合,是否已经明白了内购的方式了呢,只要把我列举的这几个方法,统统的导入进你的工程,那么就基本上可以了。

三、常见内购错误,自己做内购总结的几个常见错误。

1、请求不到内购的产品信息。

解决办法:(1)、先看看bundle id,和测试证书之类的东西配置的都对不对,然后看看产品的唯一ID和iTunesConnect里的能不能对应上。如果都没有问题,那么看下面的。

                  (2)、去看看iTunesConnect里的协议里面的公司的地址信息和银行卡信息是否填写正确,只要没有报错,报红就可以。基本上上面这几点弄好了也就能请求到商品了。

2、手机提示无法连接到itunesStore

解决办法:把手机的Apple ID先注销掉,然后购买的时候重新填写Apple ID。


发布了95 篇原创文章 · 获赞 20 · 访问量 15万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章