iOS开发 内购流程

作者: 贝勒老爷 | 来源:发表于2016-09-22 17:29 被阅读1982次
注意必读
做了很多电商的项目了,都在用各大第三方支付,苹果已经在强制推行内购了,简单说明一下,如果你购买的商品,是在本app中使用和消耗的虚拟货币,就一定要用内购,否则会被拒绝上线,例如:游戏币,在线书籍,app中使用的道具等。如果购买的就是普通的商品,例如淘宝买东西等,就不需要用内购
现在苹果有一个 bug 就是你填写了银行卡信息之后修改不了只能发邮件给苹果等那边重置,发邮件给他们处理有多慢你懂得....

一.向appStore提交资料
第一步


1749914-225b1c250f5c5382.png

第二步


1749914-f446608344ff5775.png
第三步
1749914-36a3a9752f7f5f09.png
操作完第三步然后记得保存
1749914-880a5bfbd6dbcfd9.png

第四步


1749914-6f05cc110112bc39.png
第五步
先点击Contact Info 的Set Up
1749914-f154d3324adb13b8.png
第六步
1749914-2602d087074b8edc.png
第七步
都填写完记得保存,然后回到上一个页面
1749914-016ab4e0306b73ff.png
第八步
1749914-6187ffdd8a9be141.png

第九步


1749914-3b216495c5385c19.png
第十步
1749914-f4cd66f1a9ed0174.png
第十一步
1749914-3ade39e8d4e7829e.png 步
第十二步
填写银行卡信息

第十三步


1749914-3773f5c84faae624.png

第十四步


1749914-1defa02638af70b7.png
第十五步
1749914-e8dc793dacabe69c.png

第十六步


1749914-0f12a7caa8d83cae.png
第十七步
1749914-8bdcf11af6a38bd7.png
第十八步
1749914-523d414a44dc9293.png
第十九步
1749914-8345169d6d89b17a.png
第二十步
1749914-5a77feb067f7db7f.png

第二十一步


1749914-bc89f24567bc0b01.png

恭喜你现在你完成了添加的信息,下面创建内购项目
二.创建内购项目


1749914-7c4f22c9a13ac343.png

第一步


1749914-99a1f3573a5c1d9a.png
第二步
根据自己app的需要选择类型

第三步


1749914-e7b6de6a4931ea3c.png

第四步

一直下一步到结尾

三、添加项目内购测试帐号


1749914-84662a6fd31a7e7c.png

第一步


1749914-bdb0ef4137eb404f.png
四、上代码
第一步导入StoreKit.framework库

然后先看.h文件

#import <StoreKit/StoreKit.h>

typedef NS_ENUM(NSInteger, MyJellyShowType)
{
    MyJellyShowType_Push = 0,
    MyJellyShowType_Present = 1,
};

@interface MyJellyCurrencyViewController : BaseReuqestTableViewController<SKPaymentTransactionObserver,SKProductsRequestDelegate>
{
    int buyType;
}
@property (nonatomic) MyJellyShowType showType;

- (void)RequestProductData;

- (void)buy:(int)type;

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

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

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

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

@end

然后看.m文件

//在内购项目中创的商品单号
#define ProductID_IAP0p600 @"guodong600"//60
#define ProductID_IAP1p1200 @"guodong1200" //1200
#define ProductID_IAP2p5000 @"guodong5000" //5000


enum{
    IAP0p600 = 0,
    IAP1p1200,
    IAP4p5000,
} buyCoinsT

#pragma mark -  点击购买按钮
-(void)buttonClickIndex:(NSInteger)index
{
    [[SKPaymentQueue defaultQueue] addTransactionObserver:self];
    if (index == 0)
    {
        buyCoinsTag = IAP0p600;
    }
    else if (index == 1)
    {
        buyCoinsTag = IAP1p1200;

    }else if (index == 2)
    {
        buyCoinsTag = IAP4p5000;
    }
    coinNum = [jellyMutAry objectAtIndex:index];
    [LoadingTool showLoadingTo:self.view isAfterDelay:NO];
    mainTableView.userInteractionEnabled = NO;
    [self buy:buyCoinsTag];
    

}

-(void)buy:(int)type{
    buyType = type;
    if ([SKPaymentQueue canMakePayments])
    {
        //允许程序内付费购买
        [self RequestProductData];
    }
    else
    {
        //不允许程序内付费购买
        mainTableView.userInteractionEnabled = YES;
        [LoadingTool hideProgressHud:self];
        UIAlertView *alerView = [[UIAlertView alloc] initWithTitle:@"提示" message:@"您的手机没有打开程序内付费购买"
                                                          delegate:nil cancelButtonTitle:NSLocalizedString(@"关闭",nil) otherButtonTitles:nil];
        [alerView show];
    }
}
#pragma mark - 请求对应的产品信息
-(void)RequestProductData
{
    NSArray *product = nil;
    switch (buyType)
    {
        case IAP0p600:
            product=[[NSArray alloc] initWithObjects:ProductID_IAP0p600,nil];
            break;
            
        case IAP1p1200:
            product=[[NSArray alloc] initWithObjects:ProductID_IAP1p1200,nil];
            break;
            
        case IAP4p5000:
            product=[[NSArray alloc] initWithObjects:ProductID_IAP2p5000,nil];
            break;
            
        default:
            break;
    }
    
    NSSet *nsset = [NSSet setWithArray:product];
    SKProductsRequest *request=[[SKProductsRequest alloc] initWithProductIdentifiers: nsset];
    request.delegate=self;
    [request start];
}
#pragma mark - 收到产品反馈信息
- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response{
    
    
    SKProduct * selectedProduct = nil;
    selectedProduct = [response.products objectAtIndex:0];
    SKPayment *payment = [SKPayment paymentWithProduct:selectedProduct];
    [[SKPaymentQueue defaultQueue] addPayment:payment];
    
}
#pragma mark - 先商品添加进列表 再交易
- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions//交易结果
{
    for (SKPaymentTransaction *transaction in transactions) {
        switch (transaction.transactionState) {
            case SKPaymentTransactionStatePurchased://交易完成
            {
               
                [self  completeTransaction:transaction];
            }
                break;
            case SKPaymentTransactionStateFailed://交易失败
            {
                //交易失败
                [self failedTransaction:transaction];
                [WarningTool showToastHintWithText:@"购买失败,请重试!"];
            }
                break;
            case SKPaymentTransactionStateRestored://已经购买过该商品
                [self restoreTransaction:transaction];
                break;
            case SKPaymentTransactionStatePurchasing://商品添加进列表
                break;
            default:
                break;
        }
    }
    [LoadingTool hideProgressHud:self];
    mainTableView.userInteractionEnabled = YES;
}

#pragma mark - 交易完成调用
- (void) completeTransaction: (SKPaymentTransaction *)transaction{
    NSString *product = transaction.payment.productIdentifier;
    if ([product length] > 0)
    {
        NSArray *tt = [product componentsSeparatedByString:@"."];
        NSString *bookid = [tt lastObject];
        if ([bookid length] > 0)
        {
            [self recordTransaction:transaction];
        }
    }
    // Remove the transaction from the payment queue.结束交易
    [[SKPaymentQueue  defaultQueue] finishTransaction: transaction];
   
}

#pragma mark - 记录交易
-(void)recordTransaction:(SKPaymentTransaction *)transaction
{
    transactionIdentifier = transaction.transactionIdentifier;
    [self verifyPruchase];
    
//    NSString *product = transaction.payment.productIdentifier;
//    NSString *applicationUsername = transaction.payment.applicationUsername;
//    NSString *transactionIdentifier = transaction.transactionIdentifier;
   
//    // 验证凭据,获取到苹果返回的交易凭据
//    // appStoreReceiptURL iOS7.0增加的,购买交易完成后,会将凭据存放在该地址
//    NSURL *receiptURL = [[NSBundle mainBundle] appStoreReceiptURL];
//    // 从沙盒中获取到购买凭据
//    NSData *receiptData = [NSData dataWithContentsOfURL:receiptURL];
//    NSString *encodeStr = [receiptData base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithLineFeed];
//    NSString *result  =[[ NSString alloc] initWithData:transaction.transactionReceipt encoding:NSUTF8StringEncoding];
//    NSString *base64Str = [transaction.transactionReceipt base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithLineFeed];
    
}

- (void)verifyPruchase
{
    
    [LoadingTool showLoadingTo:self.view isAfterDelay:NO];
    // 验证凭据,获取到苹果返回的交易凭据
    // appStoreReceiptURL iOS7.0增加的,购买交易完成后,会将凭据存放在该地址
    NSURL *receiptURL = [[NSBundle mainBundle] appStoreReceiptURL];
    // 从沙盒中获取到购买凭据
    NSData *receiptData = [NSData dataWithContentsOfURL:receiptURL];
    // 发送网络POST请求,对购买凭据进行验证
    NSURL *url = [NSURL URLWithString:XTY_IAP_VerifyReceipt];
    // 国内访问苹果服务器比较慢,timeoutInterval需要长一点
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:10.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结果
    NSData *result = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];
    // 官方验证结果为空验证失败
    if (result == nil)
    {
        [LoadingTool hideProgressHud:self];
        [WarningTool showToastHintWithText:@"验证失败"];
        return;
    }
    NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:result options:NSJSONReadingAllowFragments error:nil];
    //验证成功
    if ([[dict objectForKey:@"status"] integerValue] == 0) {
        // 比对字典中以下信息基本上可以保证数据安全
        // bundle_id&application_version&product_id&transaction_id
        [self addJelly];
    }else if ([[dict objectForKey:@"status"] integerValue] == 21007){
        // 验证凭据,获取到苹果返回的交易凭据
        // appStoreReceiptURL iOS7.0增加的,购买交易完成后,会将凭据存放在该地址
        NSURL *receiptURL = [[NSBundle mainBundle] appStoreReceiptURL];
        // 从沙盒中获取到购买凭据
        NSData *receiptData = [NSData dataWithContentsOfURL:receiptURL];
        // 发送网络POST请求,对购买凭据进行验证
        NSURL *url = [NSURL URLWithString:@"https://sandbox.itunes.apple.com/verifyReceipt"];
        // 国内访问苹果服务器比较慢,timeoutInterval需要长一点
        NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:10.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结果
        NSData *result = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];
        // 官方验证结果为空验证失败
        if (result == nil)
        {
            [LoadingTool hideProgressHud:self];
            [WarningTool showToastHintWithText:@"验证失败"];
            return;
        }
        NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:result options:NSJSONReadingAllowFragments error:nil];
        if ([[dict objectForKey:@"status"] integerValue] == 0) {
             [self addJelly];
        }else{
            [LoadingTool hideProgressHud:self];
            [WarningTool showToastHintWithText:@"验证失败"];
        }
        
        
    }
    else{
        [LoadingTool hideProgressHud:self];
        [WarningTool showToastHintWithText:@"验证失败"];

    }
}
//失败
- (void) failedTransaction: (SKPaymentTransaction *)transaction{
    if (transaction.error.code != SKErrorPaymentCancelled){}
    [[SKPaymentQueue defaultQueue] finishTransaction: transaction];
}

//交易恢复处理
- (void) restoreTransaction: (SKPaymentTransaction *)transaction{
//    [self PurchasedTransaction:transaction];
    [[SKPaymentQueue defaultQueue] finishTransaction: transaction];
//     [[SKPaymentQueue defaultQueue] restoreCompletedTransactions];
}
- (void)paymentQueueRestoreCompletedTransactionsFinished:(SKPaymentQueue *)queue
{
    
}
-(void) paymentQueue:(SKPaymentQueue *) paymentQueue restoreCompletedTransactionsFailedWithError:(NSError *)error{

}
-(void) PurchasedTransaction: (SKPaymentTransaction *)transaction{
    
    NSArray *transactions =[[NSArray alloc] initWithObjects:transaction, nil];
    [ self paymentQueue:[SKPaymentQueue defaultQueue] updatedTransactions:transactions];
    
}
-(void)dealloc{ 
    [[SKPaymentQueue defaultQueue] removeTransactionObserver:self];
    //解除监听
    
}
- (void)addJelly
{
    NSMutableDictionary *mutDic = [[NSMutableDictionary alloc]init];
    [mutDic setObject:transactionIdentifier forKey:@"flowNO"];
    [mutDic setObject:coinNum forKey:@"coinNum"];
    [[NetworkRequests sharedClient]requestWithName:XTY_CoinCharge withParameters:mutDic successCallBack:^(MyJellyModel *myJellyModel) {
        [LoadingTool hideProgressHud:self];
        if ([myJellyModel.status integerValue] == 1)
        {
            [self beginRefreshing];
        }
        else
        {
            [WarningTool showToastHintWithText:myJellyModel.error];
        }
    } failCallback:^(NSString *error) {
        [LoadingTool hideProgressHud:self];
        [WarningTool showToastNetError];
    }];
}



相关文章

  • iOS 苹果内购流程

    本文参考: iOS开发之内购完全笔记 iOS开发内购全套图文教程 iOS应用程序内购/内付费(一) 代码...

  • iOS支付

    支付宝支付 支付宝支付支付宝补充 微信支付 微信支付 内购 iOS开发 内购流程

  • iOS开发 内购流程

    一.向appStore提交资料第一步 第二步 第四步 第九步 第十三步 第十四步 第十六步 第二十一步 恭喜你现在...

  • iOS内购流程文档-Lion

    iOS内购流程: iOS内购 什么时候用到呢? 虚拟产品就需要用到iOS内购;购买的商品,是在本app中...

  • iOS-内购

    前言:关于iOS内购,参考两篇博文 iOS-iOS内购流程(手把手图文教程)iOS内购你看我就够了(埋坑篇) 我自...

  • IOS内购服务端技术方案

    IOS内购服务端技术方案 IOS购买vip流程 IOS内购服务器模式的主要流程如下所示: 服务端验证注意点 苹果A...

  • iOS内购之服务器类型机制

    iOS开发中用到内购模式,一般都使用服务器类型机制,其基本流程如图:

  • 【7】iOS开发·内购流程

    说明:涉及到金额交易,苹果审核的一般严格许多。苹果在涉及需要支付中间币的购买必须走苹果内购(例:点券、钻石、K币等...

  • iOS直播类APP开发流程解析(内附源码详解)

    iOS直播类APP开发流程解析(内附源码详解) iOS直播类APP开发流程解析(内附源码详解)

  • iOS应用程序内购(IAP)

    参考:iOS开发内购全套图文教程

网友评论

  • 邢泽:// [self PurchasedTransaction:transaction];
    [[SKPaymentQueue defaultQueue] finishTransaction: transaction];
    // [[SKPaymentQueue defaultQueue] restoreCompletedTransactions];

    请问 这两句注释的代码 不用吗?
  • 和尚用飘柔_dfdd:学习了?请问凭证怎么处理的?
  • 5f0938f9a4af:不错!收藏了
  • listen_to:很详细,下次可以根据步骤试试

本文标题:iOS开发 内购流程

本文链接:https://www.haomeiwen.com/subject/tpbzettx.html