iOS应用内购/内付费

最近应用审核被拒绝了,缘由是由于使用了第三方支付,苹果说须要使用到应用内购买。可是查了下相关资料,太杂且不详细,好吧,因此如今本身来写博客咯,把我所知道的一一列出来,可能内容有点乱,你们就将就着些吧html

1、建立应用

首先进入苹果的ItunesConnection(https://itunesconnect.apple.com)点击左上角的加号新建一个App应用,点击后该网站会弹出一个信息编辑框,你们只要将上面的信息填充完毕点击save便可在苹果的app平台上拥有一个属于本身的App。ios

在套装ID的上,须要提早为该App申请一个AppID以及BundleID,只要是申请成功了就会在选择列表中显示出来。若是有人有疑问如何申请,请看我以前那一篇推送的博客,里面有详细的步骤。附上连接点击打开连接服务器

这里顺便多说一句这个ItunesConnect是用来干吗的,它是苹果公司给我的或企业提供管理本身App的一个平台。在这个平台上开发者能够新建,删除和管理本身的App应用,开发者能够根据需求对App应用进行上架与下架,编辑App信息,生成测试app所需的信息。具体操做我就不细说了。网络

2、填写协议、税务和银行业务

咱们打开ItunesConnect,进入协议、税务和银行业务,配置相关信息。数据结构

填写相关信息,由于我是已经申请成功了,因此看到了就是下图app

进入协议、税务和银行业务页面后,会有3种合同类型,若是你以前没有主动申请过去合同,那么通常你如今激活的合同只有iOS Free Application一种。ide

页面内容分为两块测试

  • Request Contracts(申请合同)
  • Contracts In Effect(已生效合同)。

合同类型分为3种网站

  • iOS Free Application(免费应用合同)
  • iOS Paid Application(付费应用合同)
  • iAd App笔者暂时只申请过付费应用合同,因此下面主要讲一下付费应用合同的申请流程。


一、填写联系方式

 

    • 咱们点击Contact Info下方的Set Up按钮能够进入联系方式填写页面,以下图:

若是你没有添加过联系人,你须要经过Add New Contact按钮来添加一个新的联系人。而后指定联系人的职务,职务以下:ui

      • Senior Management:高管
      • Financial:财务
      • Technical:技术支持
      • Legal:法务
      • Marketing:市场推广

若是你是独立开发者,能够所有填你本身一我的。

二、填写银行信息

  咱们点击Bank Info下方的Set Up按钮能够进入联系方式填写页面,以下图:  

  选择你的银行帐户,若是你没有,点击旁边的Add Bank Account添加一个帐户。下面是添加一个帐户的流程。

  2-一、选择银行所在的国家

  

 

  

  2-二、填写银行CNAPS Code
    若是你不知道CNAPS Code是多少,能够点击Look up Transit Number来查询,查询时会根据3个关键信息来查询,以下:

    • Bank Name:银行的英文名称(不能是拼音)
    • City:银行所在的城市英文名称(中国的城市用拼音)
    • Postal Code:邮编
      而后在下面就会出来备选的银行,选择正确的银行后,点击next,进入下一步。

    
    

  2-三、确认银行信息

    
  2-四、填写银行帐号信息

    • Bank Account Number:银行帐号
    • Confirm Bank Account Number:再次输入银行帐号
    • Account Holder Name:持卡人姓名,中文名用拼写,名在前,姓在后
    • Bank Account Currency:货币类型,通常国内的开发者选择CNY

    
  2-五、确认全部信息
    
 三、填写税务信息 

  税务信息这一块了解不是不少,不过由于是国内开发者,能够不用太费心,税务信息分3种:

  • U.S Tax Forms: 美国税务
  • Australia Tax Forms:澳大利亚税务
  • Canada Tax Forms: 加拿大税务

  

  我选择的是U.S Tax Forms,选择后会问你两个问题,第一个问题以下:询问你是不是美国居民,有没有美国伙伴关系或者美国公司,若是没有直接选择No。

  
  接下来第二个问题以下:询问你有没有在美国的商业性活动,没有也直接选No。

  

  而后填写你的税务信息,包括如下几点:

  • Individual or Organization Name:我的或者组织名称
  • Country of incorporation: 所在国家
  • Type of Beneficial Owner:受益方式,独立开发者选我的
  • Permanent Residence:居住地址
  • Mailing address:邮寄地址
  • Name of Person Making this Declaration:声明人
  • Title:头衔

  填写完这些信息后就能够提交了

  
  
 四、等待审核

  当你填写完全部资料后,合同状态就会变成Processing, 大概24小时内就会有结果。

3、建立购买项目

 进入ItunesConnect,点击你的App,选择上面“功能”中的"App内购买项目",就能够看到右边有一个+号,以下图(最近由于被IPV6的问题给拒绝了)

  
单击+号,选择你须要建立的购买类型

  • 一、消耗型项目
  • 二、非消耗型项目
  • 三、自动续订型项目
  • 四、免费订阅
  • 五、非续订订阅
      选择你须要建立的购买项目类型后,输入产品的参考名称、产品的ID,选择产品售价等级,而后单击添加语言输入你的产品相关信息,再上传屏幕预览,单击保存即建立购买项目成功。以下图:   

  在上图所示的编辑框中输入,商品名称,产品ID以及价格等级,在这边说明一下:

  1.商品名称根据你的消费道具的实际意义来讲明,好比“100颗宝石”,“100金币”等。

  2.产品ID是比较重要的,由项目自定义,只要惟一便可,像我通常都是用App的bundleID加一个后缀来表示,这样既跟项目关联又具备惟一性。

  3.价格等级的话“查看价格表”中有对应的说明,能够对照着表中每一个国家的货币价格与等级来选择。

  建立购买项目成功后,回到App内购买项目,就能够看到咱们刚刚建立的购买项目了。

4、添加应用购买测试账号

  咱们打开ItunesConnect,选择“用户和职能”选项, 咱们能够看到有一个“沙箱技术测试员”,咱们单击“+”号,添加咱们的测试账号,以下图:

  
  而后咱们的相关信息,我就不一一列举了,以下图:

  
单击“存储”,咱们的测试账号就建立成功了。下面开始撸代码了

5、撸代码咯

  1.首先在项目工程中加入“storekit.framework”,加入头文件#import <StoreKit/StoreKit.h>

  2.在进行使用App内购买页面.h文件中加入“SKPaymentTransactionObserver,SKProductsRequestDelegate”监听机制  

  我就开始贴代码吧

  1 - (void)viewDidLoad {
  2     
  3     [super viewDidLoad];
  4    
  5     // 设置购买队列的监听器
  6     [[SKPaymentQueue defaultQueue] addTransactionObserver:self];
  7     
  8     if([SKPaymentQueue canMakePayments]){
  9                     //productID就是你在建立购买项目时所填写的产品ID
 10                     [self requestProductData: productID];
 11                 }else{
 12                     self.ringIndicator.hidden = YES;
 13                     //                    NSLog(@"不容许程序内付费");
 14                     UIAlertView *alertError = [[UIAlertView alloc] initWithTitle:@"舒适提示"
 15                                                                          message:@"请先开启应用内付费购买功能。"
 16                                                                         delegate:nil
 17                                                                cancelButtonTitle:@"肯定"
 18                                                                otherButtonTitles: nil];
 19                     [alertError show];
 20                 }
 21 
 22 }
 23 #pragma mark - 请求商品
 24 //请求商品
 25 - (void)requestProductData:(NSString *)type{
 26     NSLog(@"-------------请求对应的产品信息----------------");
 27     NSArray *product = [[NSArray alloc] initWithObjects:type, nil];
 28     
 29     NSSet *nsset = [NSSet setWithArray:product];
 30     SKProductsRequest *request = [[SKProductsRequest alloc] initWithProductIdentifiers:nsset];
 31     request.delegate = self;
 32     [request start];
 33     //    [[SKPaymentQueue defaultQueue] addTransactionObserver:self];
 34 }
 35 
 36 #pragma mark 收到产品返回信息
 37 - (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response{
 38     self.ringIndicator.hidden = YES;
 39     NSLog(@"--------------收到产品反馈消息---------------------");
 40     NSArray *product = response.products;
 41     if([product count] == 0){
 42         [self showHUDTipWithTitle:@"没有该商品"];
 43         NSLog(@"--------------没有商品------------------");
 44         return;
 45     }
 46     
 47     SKProduct *p = nil;
 48     for (SKProduct *pro in product) {
 49         NSLog(@"pro info");
 50         NSLog(@"SKProduct 描述信息:%@", [pro description]);
 51         NSLog(@"localizedTitle 产品标题:%@", [pro localizedTitle]);
 52         NSLog(@"localizedDescription 产品描述信息:%@", [pro localizedDescription]);
 53         NSLog(@"price 价格:%@", [pro price]);
 54         NSLog(@"productIdentifier Product id:%@", [pro productIdentifier]);
 55         
 56         if([pro.productIdentifier isEqualToString: productID]){
 57             p = pro;
 58             money = [NSString stringWithFormat:@"%@",[pro price]];
 59         }else{
 60             NSLog(@"不不不相同");
 61         }
 62     }
 63     SKPayment *payment = [SKPayment paymentWithProduct:p];
 64     //    SKPayment *payment = [SKPayment paymentWithProductIdentifier:PayKey];
 65     NSLog(@"发送购买请求");
 66     [[SKPaymentQueue defaultQueue] addPayment:payment];
 67 }
 68 
 69 //请求失败
 70 - (void)request:(SKRequest *)request didFailWithError:(NSError *)error{
 71     //     [self showHUDTipWithTitle:@"请求失败,错误"];
 72     self.ringIndicator.hidden = YES;
 73     NSLog(@"------------------错误-----------------:%@", error);
 74     UIAlertView *alerView =  [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"Alert",NULL) message:[error localizedDescription]
 75                                                        delegate:nil cancelButtonTitle:NSLocalizedString(@"Close",nil) otherButtonTitles:nil];
 76     [alerView show];
 77 }
 78 
 79 - (void)requestDidFinish:(SKRequest *)request{
 80     //    [self showHUDTipWithTitle:@"反馈信息结束"];
 81     NSLog(@"------------反馈信息结束-----------------");
 82 }
 83 
 84 #pragma mark 监听购买结果
 85 //监听购买结果
 86 - (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions{
 87     self.ringIndicator.hidden = YES;
 88     NSLog(@" 监听购买结果 -----paymentQueue--------");
 89     for (SKPaymentTransaction *transaction in transactions)
 90     {
 91         switch (transaction.transactionState)
 92         {
 93             case SKPaymentTransactionStatePurchased:{
 94                 NSLog(@"-----交易完成 --------");
 95                 //交易完成
 96                 [self commitSeversSucceeWithTransaction:transaction];
 97                 
 98                 
 99             }
100                 break;
101             case SKPaymentTransactionStateFailed:{
102                 NSLog(@"-----交易失败 --------");
103                 //交易失败
104                 [self failedTransaction:transaction];
105                 
106             }
107                 break;
108             case SKPaymentTransactionStateRestored:{
109                 NSLog(@"-----已经购买过该商品(重复支付) --------");
110                 //已经购买过该商品
111                 [self restoreTransaction:transaction];
112                 //                 [self commitSeversSucceeWithTransaction:transaction];
113                 
114                 
115             }
116             case SKPaymentTransactionStatePurchasing:  {
117                 //商品添加进列表
118                 NSLog(@"-----商品添加进列表 --------");
119             }
120                 break;
121             default:
122                 break;
123         }
124     }
125 }
126 
127 //交易结束
128 - (void)completeTransaction: (SKPaymentTransaction *)transaction
129 {
130     NSLog(@" 交易结束 -----completeTransaction--------");
131     
132     // Remove the transaction from the payment queue.
133     [[SKPaymentQueue defaultQueue] finishTransaction: transaction];
134     
135 }
136 
137 - (void)commitSeversSucceeWithTransaction:(SKPaymentTransaction *)transaction
138 {
139     
140     NSString * productIdentifier = transaction.payment.productIdentifier;
141     NSLog(@"productIdentifier Product id:%@", productIdentifier);
142     NSString *transactionReceiptString= nil;
143     
144     //系统IOS7.0以上获取支付验证凭证的方式应该改变,切验证返回的数据结构也不同了。
145     
146     if(SYSTEMVERSION >= 7.0){
147         // 验证凭据,获取到苹果返回的交易凭据
148         // appStoreReceiptURL iOS7.0增长的,购买交易完成后,会将凭据存放在该地址
149         NSURLRequest * appstoreRequest = [NSURLRequest requestWithURL:[[NSBundle mainBundle]appStoreReceiptURL]];
150         NSError *error = nil;
151         NSData * receiptData = [NSURLConnection sendSynchronousRequest:appstoreRequest returningResponse:nil error:&error];
152         
153         transactionReceiptString = [receiptData base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithLineFeed];
154     }else{
155         
156         NSData * receiptData = transaction.transactionReceipt;
157         //        transactionReceiptString = [receiptData base64EncodedString];
158         transactionReceiptString = [receiptData base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithLineFeed];
159     }
160     //    NSLog(@"transactionReceiptString == %@",transactionReceiptString);
161     [[SKPaymentQueue defaultQueue] finishTransaction: transaction];
162     // 向本身的服务器验证购买凭证
163    // [self SendRequestWithtransactionReceiptString:transactionReceiptString Transaction:transaction];
164     
165     
166 }
167 //记录交易
168 -(void)recordTransaction:(NSString *)product{
169     NSLog(@"-----记录交易--------");
170 }
171 
172 //处理下载内容
173 -(void)provideContent:(NSString *)product{
174     NSLog(@"-----下载--------");
175 }
176 
177 - (void)failedTransaction:(SKPaymentTransaction *)transaction {
178     if(transaction.error.code != SKErrorPaymentCancelled) {
179         NSLog(@"购买失败");
180         UIAlertView *alerView2 =  [[UIAlertView alloc] initWithTitle:@"舒适提示"
181                                                              message:@"购买该套餐失败,请从新尝试购买"
182                                                             delegate:nil cancelButtonTitle:NSLocalizedString(@"关闭",nil) otherButtonTitles:nil];
183         
184         [alerView2 show];
185     } else {
186         NSLog(@"用户取消交易");
187         
188         UIAlertView *alerView2 =  [[UIAlertView alloc] initWithTitle:@"舒适提示"
189                                                              message:@"您已取消该购买"
190                                                             delegate:nil cancelButtonTitle:NSLocalizedString(@"关闭",nil) otherButtonTitles:nil];
191         
192         [alerView2 show];
193     }
194     [[SKPaymentQueue defaultQueue] finishTransaction: transaction];
195 }
196 
197 
198 -(void) paymentQueueRestoreCompletedTransactionsFinished: (SKPaymentTransaction *)transaction{
199     
200 }
201 
202 
203 - (void) restoreTransaction: (SKPaymentTransaction *)transaction
204 {
205     NSLog(@" 交易恢复处理");
206     [[SKPaymentQueue defaultQueue] finishTransaction: transaction];
207     
208 }
209 
210 -(void) paymentQueue:(SKPaymentQueue *) paymentQueue restoreCompletedTransactionsFailedWithError:(NSError *)error{
211     NSLog(@"-------paymentQueue----");
212 }
213 
214 #pragma mark connection delegate
215 - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
216 {
217     NSLog(@"connection==%@",  [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]);
218 }

-(void)dealloc

{

    [[SKPaymentQueue defaultQueue] removeTransactionObserver:self];//解除监听

 }

代码我就不一一解释了。接下来我就给你们看运行后的结果。

 


  




 

最后给你们补充点东西,在与服务器作较验的时候,考虑到网络异常状况,服务器的验证应该是一个可恢复的队列,若是失败了,应该进行重试。

与苹果的验证接口文档在https://developer.apple.com/library/ios/#documentation/NetworkingInternet/Conceptual/StoreKitGuide/VerifyingStoreReceipts/VerifyingStoreReceipts.html#//apple_ref/doc/uid/TP4008267-CH104-SW3 。简单来讲就是将购买凭证用Base64编码,而后Post给苹果的验证服务器,苹果将验证结果以JSON形式返回。

苹果AppStore线上的购买凭证地址是:https://buy.itunes.apple.com/verifyReceipt , 测试地址是:https://sandbox.itunes.apple.com/verifyReceipt

注意事项:

苹果在审核应用时,只会在沙盒(sandbox)环境购买,其产生的购买凭证,也只能链接苹果的测试验证服务器。可是审核的应用又是链接的线上服务器,那应该判断苹果正式验证服务器的返回状态码,若是 是21007,则再一次链接测试服务器进行验证便可。https://developer.apple.com/library/ios/releasenotes/General/ValidateAppStoreReceipt/Introduction.html  上有对返回的状态码的详细说明。

相关文章
相关标签/搜索