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-提交审核的时候不需要提供沙盒技术测试账号的,苹果有自己的测试账号。

原文地址:https://www.cnblogs.com/somethingWithiOS/p/6688042.html