iOS游戏IAP数据服务器验证
2015-08-10 12:23
525 查看
我上一篇博客《为iOS应用/游戏内建购买项目(IAP)》对于CP有自己游戏服务器的从安全性来讲并不适用,有自己服务器则需要进一步对数据进行校验。
如果CP具有自己的游戏服务器, Apple建议在服务器端存储产品ID,而不要将其存储在客户端本地。 这样就可以在不升级程序的前提下添加新的产品,这只需要我们向客户端发送哪个产品的ID。
如果要申请商品ID,可参考《为iOS应用/游戏内建购买项目(IAP)》
更多详细流程可参考这篇文章:《Store Kit Guide(In App Purchase)翻译》
IAP充值数据校验流程如图:
而以下代码就是要实现上图数据校验流程的:
运行就可以得到结果了:
查看打印数据:
如果CP具有自己的游戏服务器, Apple建议在服务器端存储产品ID,而不要将其存储在客户端本地。 这样就可以在不升级程序的前提下添加新的产品,这只需要我们向客户端发送哪个产品的ID。
如果要申请商品ID,可参考《为iOS应用/游戏内建购买项目(IAP)》
更多详细流程可参考这篇文章:《Store Kit Guide(In App Purchase)翻译》
IAP充值数据校验流程如图:
而以下代码就是要实现上图数据校验流程的:
// // ViewController.m // // #import "ViewController.h" @interface ViewController () @end @implementation ViewController #pragma mark 数据初始化 - (void)viewDidLoad { [super viewDidLoad]; //1 [self setOnListner]; UIButton * btn = [UIButton buttonWithType:UIButtonTypeRoundedRect]; [btn setFrame:CGRectMake(100, 300, self.view.bounds.size.width/2, 50)]; [btn setTitle:@"buy" forState:UIControlStateNormal]; btn.backgroundColor = [UIColor purpleColor]; [btn addTarget:self action:@selector(click) forControlEvents:UIControlEventTouchDown]; [self.view addSubview:btn]; } //1,对交易进行监听和设置可购买 -(void)setOnListner{ [[SKPaymentQueue defaultQueue] addTransactionObserver:self]; NSString * des; if([SKPaymentQueue canMakePayments]){ des = @"可购买内置项目!"; }else{ des = @"不可购买内置项目!"; } NSLog(@"%@",des); } -(void)click{ [self reqBuyData]; } //2,请求商品信息 -(void)reqBuyData{ // 所注册的商品ID数组 NSArray * arr = [[NSArray alloc] initWithObjects:@"com.xx.gold100",@"com.xx.gold200", nil]; NSSet *set = [NSSet setWithArray:arr]; SKProductsRequest * req = [[SKProductsRequest alloc] initWithProductIdentifiers:set]; req.delegate = self; [req start]; } #pragma mark SKProductsRequestDelegate代理实现 //3, 得到商品信息,并自动购买第一个 -(void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response{ NSArray * myProducts = response.products; //如果是无效的商品将会出现在这里,如AppleID账号没完善银行信息之类也会导致 NSArray * dArr = response.invalidProductIdentifiers; NSLog(@"接受到产品返回信息%lu", (unsigned long)myProducts.count); NSLog(@"接受到无效的产品返回信息%lu", (unsigned long)dArr.count); if(myProducts.count < 1){ NSLog(@"无有效商品信息!"); return; } SKProduct * buyProduct; for (SKProduct * product in myProducts) { NSLog(@"---pay : %@", product.localizedDescription); NSLog(@"product title:%@", product.localizedTitle); NSLog(@"price:%@", product.price); buyProduct = product; } //这里我直接对最后一个商品进行下单购买, // 游戏中应该把商品列表列出来给玩家选择,然后把要买的add到[SKPaymentQueue defaultQueue],到add这里开始发送购买请求 SKPayment * pay = [SKPayment paymentWithProduct:buyProduct]; [[SKPaymentQueue defaultQueue] addPayment:pay]; } //SKProductsRequestDelegate代理实现,请求商品有错log -(void)request:(SKRequest *)request didFailWithError:(NSError *)error{ NSLog(@"---------error log----%@", error.localizedDescription); } //SKProductsRequestDelegate代理实现 -(void)requestDidFinish:(SKRequest *)request{ NSLog(@"信息请求结束"); } #pragma mark SKPaymentTransactionObserver代理实现 //4,SKPaymentTransactionObserver代理实现,也就是购买的结果 -(void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions { NSString * des = @""; for(SKPaymentTransaction * trans in transactions){ switch (trans.transactionState) { case SKPaymentTransactionStatePurchased: des = @"客户端本地购买完成!将向服务器验证数据!"; //购买成功,那么将要向cp游戏服务器发送订单,cp游戏服务器再去通过iap服务器验证数据,再返回结果到客户端 //5, [self completeTransaction:trans]; //pop出用过的交易 [[SKPaymentQueue defaultQueue] finishTransaction:trans]; break; case SKPaymentTransactionStateFailed: des = @"购买失败!"; [self failedTransaction:trans]; //pop出用过的交易 [[SKPaymentQueue defaultQueue] finishTransaction:trans]; break; case SKPaymentTransactionStateRestored: des = @"购买重复!"; //pop出用过的交易 [[SKPaymentQueue defaultQueue] finishTransaction:trans]; break; case SKPaymentTransactionStatePurchasing: //des = @"购买ing!"; break; default: break; } UIAlertView * a = [[UIAlertView alloc] initWithTitle:@"result" message:des delegate:self cancelButtonTitle:@"ok" otherButtonTitles:nil, nil]; if (![des isEqual: @""]) { [a show]; } } } #pragma mark 自定义的函数,由本地购买成功后验证数据和打印信息用 //5,购买成功后调用, -(void)completeTransaction:(SKPaymentTransaction*) transaction{ //模拟向游戏服务器验证数据 [self verifyTransaction:transaction]; } //6, //假设以下函数是游戏服务器的 //这里应该交给游戏服务器去验证,然后把结果返回客户端,直接现在这里模拟游戏服务器吧 -(void)verifyTransaction:(SKPaymentTransaction*) transaction{ //沙盒测试用url NSString * urlStr = @"https://sandbox.itunes.apple.com/verifyReceipt"; NSURL * url = [NSURL URLWithString:urlStr]; NSMutableURLRequest * req = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:5000]; req.HTTPMethod = @"POST"; //要求Base64编码 NSString * transactionReceipt = [transaction.transactionReceipt base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithLineFeed]; NSString * jsonStr = [NSString stringWithFormat:@"{\"receipt-data\":\"%@\"}", transactionReceipt]; NSData * jsonData = [jsonStr dataUsingEncoding:NSUTF8StringEncoding allowLossyConversion:YES]; [req setHTTPBody:jsonData]; NSData * result = [NSURLConnection sendSynchronousRequest:req returningResponse:nil error:nil]; //这个验证函数里应该是服务器的,得到下面结果后返回给本客户端就OK啦 if (result == nil) { NSLog(@"验证到有误数据"); }else{ NSDictionary * dic = [NSJSONSerialization JSONObjectWithData:result options:NSJSONReadingAllowFragments error:nil]; /*应该返回的json receipt = { ....... }; status = 0; */ //status == 0 才算成功 if (dic!= nil && [dic[@"status"] == 0]) { NSLog(@"数据验证成功!购买成功!"); NSLog(@"返回数据:"); NSLog(@"%@",dic); }else{ NSLog(@"验证到有误数据"); if (dic != nil) { NSLog(@"%@", dic); } } } } //给交易失败后调用 -(void)failedTransaction:(SKPaymentTransaction*)transaction{ NSString * errorDes; NSInteger errorCode = transaction.error.code; NSLog(@"payment error ; %@", transaction.error.localizedDescription); switch (errorCode) { case SKErrorUnknown: errorDes = @"unknown"; break; case SKErrorPaymentCancelled: errorDes = @"payment cancel"; break; case SKErrorPaymentInvalid: errorDes = @"payment invalid"; break; case SKErrorPaymentNotAllowed: errorDes = @"not allowed"; break; case SKErrorClientInvalid: errorDes = @"client invalid"; break; default: break; } UIAlertView * alert = [[UIAlertView alloc] initWithTitle:@"title" message:errorDes delegate:self cancelButtonTitle:@"ok" otherButtonTitles:nil, nil]; [alert show]; } @end
运行就可以得到结果了:
查看打印数据:
相关文章推荐
- iOS手势
- 主动退出iOS程序
- 电脑装完win8.1后无法进入BIOS
- iOS Xcode工程目录的 folder 和 group的区别(蓝色和黄色文件夹的区别)
- IOS开发之多线程详解
- IOS获取各种文件目录路径的方法
- iOS 9 适配系列教程
- iOS二级Table的简单实现
- ios 判断空字符串
- ios:点击tablecell中的一个按钮,确定cell所在的行
- iOS 验证手机号
- ios百度地图的使用(普通定位、反地理编码)
- IOS 获取所有图片工具类
- 【原】iOS动态性(三) Method Swizzling以及AOP编程:在运行时进行代码注入
- ios常用的框架(源自知乎上的回答)
- iOS开发~优雅的使用Xcode帮助文档及帮助系统
- [IOS动画]KDProgressView(圆环)
- iOS定位 - 普通定位(没有地图) - 反地理编码(得到具体位置)
- IOS等待时动画效果的实现
- iOS 9应用开发教程之ios9的视图