iOS游戏IAP数据服务器验证

来源:互联网 发布:阿里云 vps 编辑:程序博客网 时间:2024/06/13 02:48

我上一篇博客《为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

运行就可以得到结果了:

这里写图片描述

查看打印数据:

这里写图片描述

0 0
原创粉丝点击