iOS 关于内购
最近项目的第三方支付导致项目被拒,记录一下关于内购
1 #import <StoreKit/StoreKit.h> 2 3 //沙盒测试环境验证 4 #define SANDBOX @"https://sandbox.itunes.apple.com/verifyReceipt" 5 //正式环境验证 6 #define AppStore @"https://buy.itunes.apple.com/verifyReceipt" 7 8 #define ProductID_GPSTC01 @"xmws_tc1" //xmws_tc1是在itunes上注册的物品,这个要保持一致 9 #define ProductID_GPSTC02 @"xmws_tc2" 10 #define ProductID_GPSTC03 @"xmws_tc3" 11 12 @interface ViewController ()<SKPaymentTransactionObserver> 13 14 - (void)viewDidLoad { 15 [super viewDidLoad]; 16 [self createViews]; 17 // 01监听购买结果 18 [[SKPaymentQueue defaultQueue] addTransactionObserver:self]; 19 } 20 21 - (void)dealloc 22 { 23 [[SKPaymentQueue defaultQueue] removeTransactionObserver:self]; 24 } 25 26 - (void)createViews 27 { 28 NSArray * buttonNames = @[@"GPS套餐01", @"GPS套餐02", @"GPS套餐03"]; 29 __weak typeof(self) weakSelf = self; 30 [buttonNames enumerateObjectsUsingBlock:^(NSString * buttonName, NSUInteger idx, BOOL * stop) { 31 UIButton * button = [UIButton buttonWithType:UIButtonTypeSystem]; 32 [weakSelf.view addSubview:button]; 33 button.frame = CGRectMake(100, 100 + idx * 60, 150, 50); 34 button.titleLabel.font = [UIFont systemFontOfSize:18]; 35 [button setTitle:buttonName forState:UIControlStateNormal]; 36 37 // 设置tag值 38 button.tag = 1000 + idx; 39 [button addTarget:self action:@selector(buyProduct:) forControlEvents:UIControlEventTouchUpInside]; 40 }]; 41 } 42 43 44 - (void)buyProduct:(UIButton *) sender 45 { 46 self.buyType = sender.tag - 1000; 47 if ([SKPaymentQueue canMakePayments]) { 48 // 02判断是否允许程序内付费购买 49 [self requestProductData]; 50 NSLog(@"允许程序内付费购买"); 51 } 52 else 53 { 54 NSLog(@"不允许程序内付费购买"); 55 UIAlertView *alerView = [[UIAlertView alloc] initWithTitle:@"提示" 56 message:@"您的手机没有打开程序内付费购买" 57 delegate:nil cancelButtonTitle:NSLocalizedString(@"关闭",nil) otherButtonTitles:nil]; 58 [alerView show]; 59 60 } 61 } 62 63 64 // 03查询。下面的ProductId应该是事先在itunesConnect中添加好的,已存在的付费项目。否则查询会失败。 65 - (void)requestProductData { 66 NSLog(@"---------请求对应的产品信息------------"); 67 NSArray *product = nil; 68 switch (self.buyType) { 69 case 0: 70 product = [NSArray arrayWithObject:ProductID_GPSTC01]; 71 break; 72 case 1: 73 product = [NSArray arrayWithObject:ProductID_GPSTC02]; 74 break; 75 case 2: 76 product = [NSArray arrayWithObject:ProductID_GPSTC03]; 77 break; 78 } 79 NSSet *nsset = [NSSet setWithArray:product]; 80 SKProductsRequest *request = [[SKProductsRequest alloc] initWithProductIdentifiers: nsset]; 81 request.delegate = self; 82 [request start]; 83 } 84 85 #pragma mark - SKProductsRequestDelegate 86 // 05收到的产品信息回调 87 - (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response{ 88 89 NSArray *myProduct = response.products; 90 NSLog(@"----收到产品反馈信息%@-----",myProduct); 91 if (myProduct.count == 0) { 92 NSLog(@"无法获取产品信息,购买失败。"); 93 return; 94 } 95 NSLog(@"产品Product ID:%@",response.invalidProductIdentifiers); 96 NSLog(@"产品付费数量: %d", (int)[myProduct count]); 97 // populate UI 98 for(SKProduct *product in myProduct){ 99 NSLog(@"product info"); 100 NSLog(@"SKProduct 描述信息%@", [product description]); 101 NSLog(@"产品标题 %@" , product.localizedTitle); 102 NSLog(@"产品描述信息: %@" , product.localizedDescription); 103 NSLog(@"价格: %@" , product.price); 104 NSLog(@"Product id: %@" , product.productIdentifier); 105 } 106 SKPayment * payment = [SKPayment paymentWithProduct:myProduct[0]]; 107 NSLog(@"---------发送购买请求------------"); 108 [[SKPaymentQueue defaultQueue] addPayment:payment]; 109 110 } 111 112 //弹出错误信息 113 - (void)request:(SKRequest *)request didFailWithError:(NSError *)error{ 114 NSLog(@"-------弹出错误信息----------"); 115 UIAlertView *alerView = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"Alert",NULL) message:[error localizedDescription] 116 delegate:nil cancelButtonTitle:NSLocalizedString(@"Close",nil) otherButtonTitles:nil]; 117 [alerView show]; 118 119 } 120 121 -(void) requestDidFinish:(SKRequest *)request 122 { 123 NSLog(@"----------反馈信息结束--------------"); 124 125 } 126 127 #pragma mark - SKPaymentTransactionObserver 128 // 处理交易结果 129 - (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions { 130 for (SKPaymentTransaction *transaction in transactions) 131 { 132 switch (transaction.transactionState) 133 { 134 case SKPaymentTransactionStatePurchased://交易完成 135 NSLog(@"transactionIdentifier = %@", transaction.transactionIdentifier); 136 [self completeTransaction:transaction]; 137 break; 138 case SKPaymentTransactionStateFailed://交易失败 139 [self failedTransaction:transaction]; 140 break; 141 case SKPaymentTransactionStateRestored://已经购买过该商品 142 [self restoreTransaction:transaction]; 143 break; 144 case SKPaymentTransactionStatePurchasing: //商品添加进列表 145 NSLog(@"商品添加进列表"); 146 break; 147 default: 148 break; 149 } 150 } 151 152 } 153 154 // 交易完成 155 - (void)completeTransaction:(SKPaymentTransaction *)transaction { 156 NSString * productIdentifier = transaction.payment.productIdentifier; 157 // NSString * receipt = [transaction.transactionReceipt base64EncodedString]; 158 if ([productIdentifier length] > 0) { 159 // 向自己的服务器验证购买凭证 160 [self verifyPurchaseWithPaymentTransaction]; 161 } 162 163 // Remove the transaction from the payment queue. 164 [[SKPaymentQueue defaultQueue] finishTransaction: transaction]; 165 166 } 167 168 // 交易失败 169 - (void)failedTransaction:(SKPaymentTransaction *)transaction { 170 if(transaction.error.code != SKErrorPaymentCancelled) { 171 NSLog(@"购买失败"); 172 } else { 173 NSLog(@"用户取消交易"); 174 } 175 [[SKPaymentQueue defaultQueue] finishTransaction: transaction]; 176 } 177 178 /** 179 * 验证购买,避免越狱软件模拟苹果请求达到非法购买问题 180 * 181 */ 182 -(void)verifyPurchaseWithPaymentTransaction{ 183 //从沙盒中获取交易凭证并且拼接成请求体数据 184 NSURL *receiptUrl=[[NSBundle mainBundle] appStoreReceiptURL]; 185 NSData *receiptData=[NSData dataWithContentsOfURL:receiptUrl]; 186 187 NSString *receiptString=[receiptData base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithLineFeed];//转化为base64字符串 188 189 NSString *bodyString = [NSString stringWithFormat:@"{\"receipt-data\" : \"%@\"}", receiptString];//拼接请求数据 190 NSData *bodyData = [bodyString dataUsingEncoding:NSUTF8StringEncoding]; 191 192 193 //创建请求到苹果官方进行购买验证 194 NSURL *url=[NSURL URLWithString:SANDBOX]; 195 NSMutableURLRequest *requestM=[NSMutableURLRequest requestWithURL:url]; 196 requestM.HTTPBody=bodyData; 197 requestM.HTTPMethod=@"POST"; 198 //创建连接并发送同步请求 199 NSError *error=nil; 200 NSData *responseData=[NSURLConnection sendSynchronousRequest:requestM returningResponse:nil error:&error]; 201 if (error) { 202 NSLog(@"验证购买过程中发生错误,错误信息:%@",error.localizedDescription); 203 return; 204 } 205 NSDictionary *dic=[NSJSONSerialization JSONObjectWithData:responseData options:NSJSONReadingAllowFragments error:nil]; 206 NSLog(@"苹果返回的购买凭证 == %@",dic); //苹果返回的购买凭证 207 if([dic[@"status"] intValue]==0){ 208 NSLog(@"购买成功!"); 209 NSDictionary *dicReceipt= dic[@"receipt"]; 210 NSDictionary *dicInApp=[dicReceipt[@"in_app"] firstObject]; 211 NSString *productIdentifier= dicInApp[@"product_id"];//读取产品标识 212 //如果是消耗品则记录购买数量,非消耗品则记录是否购买过 213 NSUserDefaults *defaults=[NSUserDefaults standardUserDefaults]; 214 // if ([productIdentifier isEqualToString:ProductID_IAP_XYJ]) { 215 // int purchasedCount = [defaults integerForKey:productIdentifier];//已购买数量 216 // [[NSUserDefaults standardUserDefaults] setInteger:(purchasedCount+1) forKey:productIdentifier]; 217 // }else{ 218 [defaults setBool:YES forKey:productIdentifier]; 219 // } 220 //在此处对购买记录进行存储,可以存储到开发商的服务器端 221 }else{ 222 NSLog(@"购买失败,未通过验证!"); 223 } 224 } 225 226 // 已购商品 227 - (void)restoreTransaction:(SKPaymentTransaction *)transaction { 228 // 对于已购商品,处理恢复购买的逻辑 229 [[SKPaymentQueue defaultQueue] finishTransaction: transaction]; 230 }
补充:01-测试时一定要在真机上测试,并且要先去设置中退出当前的appleID账号
02-沙盒的测试账号是没有金额限制的,可以无数次测试,刚开始的时候还担心会扣我的钱,实测不会的,请放心测试。
03-提交审核的时候不需要提供沙盒技术测试账号的,苹果有自己的测试账号。