您的位置:首页 > 移动开发 > IOS开发

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充值数据校验流程如图:



而以下代码就是要实现上图数据校验流程的:

//
//  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


运行就可以得到结果了:



查看打印数据:

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: