最近应用审核被拒绝了,缘由是由于使用了第三方支付,苹果说须要使用到应用内购买。可是查了下相关资料,太杂且不详细,好吧,因此如今本身来写博客咯,把我所知道的一一列出来,可能内容有点乱,你们就将就着些吧html
首先进入苹果的ItunesConnection(https://itunesconnect.apple.com)点击左上角的加号新建一个App应用,点击后该网站会弹出一个信息编辑框,你们只要将上面的信息填充完毕点击save便可在苹果的app平台上拥有一个属于本身的App。ios
在套装ID的上,须要提早为该App申请一个AppID以及BundleID,只要是申请成功了就会在选择列表中显示出来。若是有人有疑问如何申请,请看我以前那一篇推送的博客,里面有详细的步骤。附上连接点击打开连接。服务器
这里顺便多说一句这个ItunesConnect是用来干吗的,它是苹果公司给我的或企业提供管理本身App的一个平台。在这个平台上开发者能够新建,删除和管理本身的App应用,开发者能够根据需求对App应用进行上架与下架,编辑App信息,生成测试app所需的信息。具体操做我就不细说了。网络
咱们打开ItunesConnect,进入协议、税务和银行业务,配置相关信息。数据结构
填写相关信息,由于我是已经申请成功了,因此看到了就是下图app
进入协议、税务和银行业务页面后,会有3种合同类型,若是你以前没有主动申请过去合同,那么通常你如今激活的合同只有iOS Free Application一种。ide
页面内容分为两块:测试
合同类型分为3种:网站
若是你没有添加过联系人,你须要经过Add New Contact按钮来添加一个新的联系人。而后指定联系人的职务,职务以下:ui
若是你是独立开发者,能够所有填你本身一我的。
咱们点击Bank Info下方的Set Up按钮能够进入联系方式填写页面,以下图:
选择你的银行帐户,若是你没有,点击旁边的Add Bank Account添加一个帐户。下面是添加一个帐户的流程。
2-二、填写银行CNAPS Code
若是你不知道CNAPS Code是多少,能够点击Look up Transit Number来查询,查询时会根据3个关键信息来查询,以下:
2-三、确认银行信息
2-四、填写银行帐号信息
2-五、确认全部信息
三、填写税务信息
税务信息这一块了解不是不少,不过由于是国内开发者,能够不用太费心,税务信息分3种:
我选择的是U.S Tax Forms,选择后会问你两个问题,第一个问题以下:询问你是不是美国居民,有没有美国伙伴关系或者美国公司,若是没有直接选择No。
接下来第二个问题以下:询问你有没有在美国的商业性活动,没有也直接选No。
而后填写你的税务信息,包括如下几点:
填写完这些信息后就能够提交了
四、等待审核
当你填写完全部资料后,合同状态就会变成Processing, 大概24小时内就会有结果。
进入ItunesConnect,点击你的App,选择上面“功能”中的"App内购买项目",就能够看到右边有一个+号,以下图(最近由于被IPV6的问题给拒绝了)
单击+号,选择你须要建立的购买类型
在上图所示的编辑框中输入,商品名称,产品ID以及价格等级,在这边说明一下:
1.商品名称根据你的消费道具的实际意义来讲明,好比“100颗宝石”,“100金币”等。
2.产品ID是比较重要的,由项目自定义,只要惟一便可,像我通常都是用App的bundleID加一个后缀来表示,这样既跟项目关联又具备惟一性。
3.价格等级的话“查看价格表”中有对应的说明,能够对照着表中每一个国家的货币价格与等级来选择。
建立购买项目成功后,回到App内购买项目,就能够看到咱们刚刚建立的购买项目了。
咱们打开ItunesConnect,选择“用户和职能”选项, 咱们能够看到有一个“沙箱技术测试员”,咱们单击“+”号,添加咱们的测试账号,以下图:
而后咱们的相关信息,我就不一一列举了,以下图:
单击“存储”,咱们的测试账号就建立成功了。下面开始撸代码了
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 上有对返回的状态码的详细说明。