In App Purchase总结

In App Purchase属于iPhone SDK3.0的新特性,用于在应用程序中购买付费道具,增加新功能,订阅杂志。是应用程序除了植入广告外的另一种取得收益的方式。 虽然Apple的官方文档已经对In App Purhcase这一特性做了比较详尽的解释,但就某些细节方面还是需要编程人员进行尝试和推敲,今天我就对之前项目中实现In App Purchase功能做下简单的总结。

一.In App Purchasep注册流程

1.登陆Apple开发者帐号

2.创建一个新的Apple ID或是选用一个已存在的Apple ID,确定Apple ID的In App Purchase功能可使用:

3.创建develop(用于沙盒测试)和distribution(用于发布)的profile,创建时选择刚才创建的Apple ID。

4.登陆itunes connect,创建一个新的App或选用一个已存在的App,App的Bundle ID要使用步骤2中选用的App Id(注:Bundle ID只能在App创建时指定,且App创建后不能不能被修改);

5. 进入App Information页面,点击“Manage In-App Purchases”按钮,进入 In-App Purchases管理页面:

5.点击“Create New”按钮开始创建一个新的Iap产品,目前苹果提供的iap产品有5类:

  • Consumable:消耗类,可重复购买,每次使用都需要收费
  • Non-Consumable:非消耗类,购买一次,永久使用,重复购买不收费;
  • Auto-Renewable Subscriptions:自动更新订阅,购买后有使用期限,App Store会自动在使用期限到了后提示使用者重新购买,我们的程序需要有一套机制验证subscription的有效性来决定使用者是否能继续使用;
  • Free Subscription:
  • Non-Renewing Subscription:

6. 以Non-Consumable为例,创建一个iap产品:

在iap创建页面有若干配置需要我们填写:

  • Reference Name:在使用in-app purchase的时候会显示在iTunes Connect和销售报表里面,而不会显示在程序里;
  • Product ID:也叫做“product identifier”,这是一个唯一的字符串,用来标识当前的in-app purchase产品,通常的做法是,使用应用的bundle id,然后在最后加一个唯一的字符串;
  • Add Language:用户购买时弹出窗口显示的内容,可以设置多个国家的语言实现本地化显示;
  • Cleared for Sale:当应用程序上架的时候,程序内置购买功能购买记录清空。
  • Price Tier:设置程序内置购买的价钱。

7. 创建了几个Iap产品:

 

二.在程序中增加 In-App Purchases功能ECPurchase

通过上面的配置,我们已经完成了In-App Purchases服务端的的注册,在程序中,我们可以使用IOS内置库StoreKit.framework里提供的Api实现In-App Purchases产品的购买功能。但如果你不想根据文档再自己写purchase功能,那么有一个第三方的库ECPurchase会适合你。 ECPurchase库封装了purchase的内在逻辑,并且提供了几种验证方式(用于防止iap破解),调用简单方便。ECPurchase库可在文章后面我提供的例子里获得。ECPurchase提供了下面的接口需要开发者自己完成:

1.在App Delegate中添加Observer
  1. [[ECPurchase shared] addTransactionObserver];  

 

2.设置ECPurchase的product delegate(产品列表代理),transaction delegate(购买结果代理),验证方式
  1. [[ECPurchase shared] setProductDelegate:self];   
  2. [[ECPurchase shared] setTransactionDelegate:self];   
  3. [[ECPurchase shared] setVerifyRecepitMode:ECVerifyRecepitModeiPhone];  

 

3.请求商品列表
  1. [[ECPurchase shared] requestProductData:identifiers];  
  实现代理函数绘制UI
  1. [[ECPurchase shared] requestProductData:identifiers];  

 

4.购买商品

 

  1. [[ECPurchase shared] addPayment:proIdentifier];  

 

 

5.确认结果

 

如果不需要收据认证实现代理函数:
  1. -(void)didFailedTransaction:(NSString *)proIdentifier;   
  2. -(void)didRestoreTransaction:(NSString *)proIdentifier;   
  3. -(void)didCompleteTransaction:(NSString *)proIdentifier;  
否则实现代理函数:
  1. -(void)didCompleteTransactionAndVerifySucceed:(NSString *)proIdentifier;   
  2. -(void)didCompleteTransactionAndVerifyFailed:(NSString *)proIdentifier withError:(NSString *)error;  

 

 

三.使用ECPurchase实现IAP的例子

下面我会以一个简单的例子演示程序端如何使用ECPurchase完成IAP功能,该例子实现了以下功能:从App Store上获取In App Purchase产品列表,并显示在一个表格(UITableView)上,点击表格上某一个产品名右边的“buy”按钮能购买对应的产品。这个例子主要包含两个类:ProductsViewController 和IAPHandler。

ProductsViewController为UI类,用于显示Iap产品列表和弹出购买结果;

IAPHandler实现ECPurchase与的两个代理接口:ECPurchaseTransactionDelegate和ECPurchaseProductDelegate,ECPurchase的执行结果会被IAPHandler接收处理。 IAPHandler被设计为单例类,目的是防止在iap请求过程中IAPHandler的实例被销毁,导致iap购买结果返回后找不到处理的实例对象。

我们可以在IAPHandler里加入自己的业务逻辑,如购买某个金币产品成功后给玩家帐号增加对应的金币数、购买解锁道具后给游戏解锁等逻辑等。IAPHandler处理了玩家的购买请求后会使用消息中心(NSNotificationCenter)对外发送一条消息,我们可以在相关的视图里接收该消息,更新视图。

首先我们需要创建一个项目,主要项目里设置的Bundle identifier要与itunes connect里指定的一样;

导入以下库:
  • StoreKit.framework
  • CFNetwork.framework
  • SystemConfiguration.framework
  • libz.1.2.5.dylib
把ECPurchase库拷贝到项目里(可从下载的例子里获得)

编写下面的代码:
ProductsViewController.h
  1. //   
  2. //  ProductsViewController.h   
  3. //  IAPDemo   
  4. //   
  5. //  Created by luoyl on 12-3-24.   
  6. //  Copyright (c) 2012年 http://luoyl.info. All rights reserved.   
  7. //   
  8.   
  9. #import <UIKit/UIKit.h>   
  10. #import "ECPurchase.h"   
  11.   
  12. @interface ProductsViewController : UITableViewController   
  13. {   
  14.     NSArray *products_;   
  15. }   
  16.   
  17. @end  

 

ProductsViewController.m
  1. //   
  2. //  ProductsViewController.m   
  3. //  IAPDemo   
  4. //   
  5. //  Created by luoyl on 12-3-24.   
  6. //  Copyright (c) 2012年 http://luoyl.info. All rights reserved.   
  7. //   
  8.   
  9. #import "ProductsViewController.h"   
  10. #import "IAPHandler.h"   
  11.   
  12. @interface ProductsViewController ()   
  13. - (void)registIapObservers;   
  14. @end   
  15.   
  16. @implementation ProductsViewController   
  17.   
  18. - (void)viewDidLoad   
  19. {   
  20.     [super viewDidLoad];     
  21.     self.title = @"IAP Demo";   
  22.     [self registIapObservers];   
  23.     [IAPHandler initECPurchaseWithHandler];   
  24.     //iap产品编号集合,这里你需要替换为你自己的iap列表   
  25.     NSArray *productIds = [NSArray arrayWithObjects:@"info.luoyl.iap.item1",   
  26.                                                     @"info.luoyl.iap.item2",   
  27.                                                     @"info.luoyl.iap.item3", nil];   
  28.     //从AppStore上获取产品信息   
  29.     [[ECPurchase shared]requestProductData:productIds];   
  30. }   
  31.   
  32. - (void)viewWillUnload   
  33. {   
  34.     [[NSNotificationCenter defaultCenter]removeObserver:self];   
  35. }   
  36.   
  37. - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section   
  38. {   
  39.     return products_ ? [products_ count] : 0;   
  40. }   
  41.   
  42. - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath   
  43. {   
  44.     static NSString *CellIdentifier = @"Cell";   
  45.        
  46.     UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];   
  47.     if (cell == nil) {   
  48.         cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];   
  49.         cell.selectionStyle = UITableViewCellSelectionStyleNone;   
  50.         cell.accessoryType =  UITableViewCellAccessoryNone;   
  51.     } else {   
  52.         for (UIView *view in [cell.contentView subviews]) {   
  53.             [view removeFromSuperview];   
  54.         }   
  55.     }   
  56.     SKProduct *product = [products_ objectAtIndex:indexPath.row];   
  57.     //产品名称   
  58.     UILabel *localizedTitle = [[UILabel alloc]initWithFrame:CGRectMake(10, 10, 130, 20)];   
  59.     localizedTitle.text = product.localizedTitle;   
  60.     //产品价格   
  61.     UILabel *localizedPrice = [[UILabel alloc]initWithFrame:CGRectMake(150, 10, 100, 20)];   
  62.     localizedPrice.text = product.localizedPrice;   
  63.     //购买按钮   
  64.     UIButton *buyButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];   
  65.     buyButton.tag = indexPath.row;   
  66.     buyButton.frame = CGRectMake(250, 10, 50, 20);   
  67.     [buyButton setTitle:@"Buy" forState:UIControlStateNormal];   
  68.     [buyButton addTarget:self action:@selector(buy:) forControlEvents:UIControlEventTouchUpInside];   
  69.   
  70.     [cell.contentView addSubview:localizedTitle];   
  71.     [cell.contentView addSubview:localizedPrice];   
  72.     [cell.contentView addSubview:buyButton];   
  73.     return cell;   
  74. }   
  75.   
  76. - (void)getedProds:(NSNotification*)notification   
  77. {   
  78.     NSLog(@"通过NSNotificationCenter收到信息:%@,", [notification object]);   
  79. }   
  80.   
  81.   
  82. - (void)buy:(UIButton*)sender   
  83. {   
  84.     SKProduct *product = [products_ objectAtIndex:sender.tag];   
  85.     NSLog(@"购买商品:%@", product.productIdentifier);   
  86.     [[ECPurchase shared]addPaymentWithProduct:product];   
  87. }   
  88.   
  89.   
  90. - (void)viewDidUnload   
  91. {   
  92.     [super viewDidUnload];   
  93. }   
  94.   
  95. - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation   
  96. {   
  97.     return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);   
  98. }   
  99.   
  100. //接收从app store抓取回来的产品,显示在表格上   
  101. -(void) receivedProducts:(NSNotification*)notification   
  102. {   
  103.     if (products_) {   
  104.         [products_ release];   
  105.         products_ = nil;   
  106.     }   
  107.     products_ = [[NSArray alloc]initWithArray:[notification object]];   
  108.     [self.tableView reloadData];    
  109. }   
  110.   
  111. // 注册IapHander的监听器,并不是所有监听器都需要注册,   
  112. // 这里可以根据业务需求和收据认证模式有选择的注册需要   
  113. - (void)registIapObservers   
  114. {   
  115.     [[NSNotificationCenter defaultCenter]addObserver:self    
  116.                                             selector:@selector(receivedProducts:)    
  117.                                                 name:IAPDidReceivedProducts    
  118.                                               object:nil];   
  119.       
  120.     [[NSNotificationCenter defaultCenter]addObserver:self   
  121.                                             selector:@selector(failedTransaction:)   
  122.                                                 name:IAPDidFailedTransaction    
  123.                                               object:nil];   
  124.        
  125.     [[NSNotificationCenter defaultCenter]addObserver:self   
  126.                                             selector:@selector(restoreTransaction:)    
  127.                                                 name:IAPDidRestoreTransaction    
  128.                                               object:nil];   
  129.       
  130.     [[NSNotificationCenter defaultCenter]addObserver:self    
  131.                                             selector:@selector(completeTransaction:)   
  132.                                                 name:IAPDidCompleteTransaction object:nil];   
  133.        
  134.     [[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(completeTransactionAndVerifySucceed:)    
  135.                                                 name:IAPDidCompleteTransactionAndVerifySucceed    
  136.                                               object:nil];   
  137.       
  138.     [[NSNotificationCenter defaultCenter]addObserver:self    
  139.                                             selector:@selector(completeTransactionAndVerifyFailed:)    
  140.                                                 name:IAPDidCompleteTransactionAndVerifyFailed    
  141.                                               object:nil];   
  142. }   
  143.   
  144. -(void)showAlertWithMsg:(NSString*)message   
  145. {   
  146.     UIAlertView *alert = [[UIAlertView alloc]initWithTitle:@"IAP反馈"    
  147.                                                    message:message    
  148.                                                   delegate:nil    
  149.                                          cancelButtonTitle:@"OK"    
  150.                                          otherButtonTitles:nil, nil];   
  151.     [alert show];   
  152.     [alert release];   
  153. }   
  154.   
  155. -(void) failedTransaction:(NSNotification*)notification   
  156. {   
  157.     [self showAlertWithMsg:[NSString stringWithFormat:@"交易取消(%@)",[notification name]]];    
  158. }   
  159.   
  160. -(void) restoreTransaction:(NSNotification*)notification   
  161. {   
  162.     [self showAlertWithMsg:[NSString stringWithFormat:@"交易恢复(%@)",[notification name]]];    
  163. }   
  164.   
  165. -(void )completeTransaction:(NSNotification*)notification   
  166. {   
  167.     [self showAlertWithMsg:[NSString stringWithFormat:@"交易成功(%@)",[notification name]]];    
  168. }   
  169.   
  170. -(void) completeTransactionAndVerifySucceed:(NSNotification*)notification   
  171. {   
  172.     NSString *proIdentifier = [notification object];   
  173.     [self showAlertWithMsg:[NSString stringWithFormat:@"交易成功,产品编号:%@",proIdentifier]];   
  174. }   
  175.   
  176. -(void) completeTransactionAndVerifyFailed:(NSNotification*)notification   
  177. {   
  178.     NSString *proIdentifier = [notification object];   
  179.     [self showAlertWithMsg:[NSString stringWithFormat:@"产品%@交易失败",proIdentifier]];   
  180. }   
  181.   
  182. @end   
IAPHandler.h
  1. //   
  2. //  IAPHandler.h   
  3. //  IAPDemo   
  4. //   
  5. //  Created by luoyl on 12-3-24.   
  6. //  Copyright (c) 2012年 http://luoyl.info. All rights reserved.   
  7. //   
  8.   
  9. #define IAPDidReceivedProducts                      @"IAPDidReceivedProducts"   
  10. #define IAPDidFailedTransaction                     @"IAPDidFailedTransaction"   
  11. #define IAPDidRestoreTransaction                    @"IAPDidRestoreTransaction"   
  12. #define IAPDidCompleteTransaction                   @"IAPDidCompleteTransaction"   
  13. #define IAPDidCompleteTransactionAndVerifySucceed   @"IAPDidCompleteTransactionAndVerifySucceed"  
  14. #define IAPDidCompleteTransactionAndVerifyFailed    @"IAPDidCompleteTransactionAndVerifyFailed"  
  15. #import <Foundation/Foundation.h>   
  16. #import "ECPurchase.h"   
  17.   
  18. @interface IAPHandler : NSObject<ECPurchaseTransactionDelegate, ECPurchaseProductDelegate>   
  19.   
  20. + (void)initECPurchaseWithHandler;   
  21. @end  

 

IAPHandler.m

 

  1. //   
  2. //  IAPHandler.m   
  3. //  IAPDemo   
  4. //   
  5. //  Created by luoyl on 12-3-24.   
  6. //  Copyright (c) 2012年 http://luoyl.info. All rights reserved.   
  7. //   
  8.   
  9. #import "IAPHandler.h"   
  10.   
  11. @interface IAPHandler()   
  12. -(void)afterProductBuyed:(NSString*)proIdentifier;   
  13. @end   
  14. @implementation IAPHandler   
  15.   
  16. static IAPHandler *DefaultHandle_ = nil;   
  17.   
  18. + (void)initECPurchaseWithHandler   
  19. {   
  20.     @synchronized(self)     {   
  21.         if (!DefaultHandle_) {   
  22.             DefaultHandle_ = [[IAPHandler alloc]init];   
  23.         }   
  24.     }       
  25. }   
  26.   
  27. - (id)init   
  28. {   
  29.     if (self = [super init]) {   
  30.         [[ECPurchase shared] addTransactionObserver];   
  31.         [[ECPurchase shared] setProductDelegate:self];   
  32.         [[ECPurchase shared] setTransactionDelegate:self];   
  33.         [[ECPurchase shared] setVerifyRecepitMode:ECVerifyRecepitModeiPhone];   
  34.     }   
  35.     return self;   
  36. }   
  37.   
  38. #pragma mark - ECPurchaseProductDelegate   
  39. //从App Store请求产品列表后返回的产品列表   
  40. - (void)didReceivedProducts:(NSArray *)products   
  41. {   
  42.     [[NSNotificationCenter defaultCenter] postNotificationName:IAPDidReceivedProducts object:products];   
  43. }   
  44.   
  45. #pragma mark - ECPurchaseTransactionDelegate   
  46. // 如果不需要收据认证, 则实现以下3个代理函数   
  47. // 即 ECVerifyRecepitModeNone 模式下   
  48. -(void)didFailedTransaction:(NSString *)proIdentifier   
  49. {   
  50. //   NSLog(@"交易取消");   
  51.     [[NSNotificationCenter defaultCenter] postNotificationName:IAPDidFailedTransaction object:proIdentifier];   
  52. }   
  53.   
  54. -(void)didRestoreTransaction:(NSString *)proIdentifier   
  55. {   
  56.     //NSLog(@" 交易恢复 ");   
  57.     [[NSNotificationCenter defaultCenter] postNotificationName:IAPDidRestoreTransaction object:proIdentifier];   
  58. }   
  59.   
  60. -(void)didCompleteTransaction:(NSString *)proIdentifier   
  61. {   
  62. //  NSLog(@" 交易成功 ");   
  63.     [self afterProductBuyed:proIdentifier];   
  64.     [[NSNotificationCenter defaultCenter] postNotificationName:IAPDidCompleteTransaction object:proIdentifier];   
  65. }   
  66.   
  67. // 否则, 需要收据认证, 实现以下2个代理函数   
  68. // ECVerifyRecepitModeiPhone 和 ECVerifyRecepitModeServer模式下   
  69. -(void)didCompleteTransactionAndVerifySucceed:(NSString *)proIdentifier   
  70. {   
  71.     [self afterProductBuyed:proIdentifier];   
  72.     [[NSNotificationCenter defaultCenter] postNotificationName:IAPDidCompleteTransactionAndVerifySucceed object:proIdentifier];   
  73. }   
  74.   
  75. -(void)didCompleteTransactionAndVerifyFailed:(NSString *)proIdentifier withError:(NSString *)error   
  76. {   
  77.     [[NSNotificationCenter defaultCenter] postNotificationName:IAPDidCompleteTransactionAndVerifyFailed object:proIdentifier];   
  78.   
  79. }   
  80.   
  81. //用户购买某件商品成功后的处理逻辑   
  82. -(void)afterProductBuyed:(NSString*)proIdentifier   
  83. {   
  84.     //写下你的逻辑, 加金币 or 解锁 or ...   
  85. }   
  86. @end   

本文例子项目

DEMO


【原文:http://iphone.tgbus.com/dev/iosdev/201205/20120523111744.shtml】

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值