以前都是在本地处理内购 也没有做验证。这次手机网游 为了避免作弊 网络游戏都是在服务器端实现元宝的加减。
内购代码 还是以前写的 直接用了 。这次主要做了服务器二次验证。
NSString *roleId = [[NSString alloc] initWithUTF8String:name]; [[PlatformHandler sharedHandler]doBuyByRoleId:roleId money:money]; //内部函数 -(void)doBuyByRoleId:(NSString *)paramRoleId money:(int)money { NSURL* url = [NSURL URLWithString:@"cydia://package/com.example.package"]; //是否越狱 if ([[UIApplication sharedApplication] canOpenURL:url]) { NSString *sMes = NSLocalizedString(@"SHOP_ERROR_STOREBUY_INFO", nil); UIAlertView *alertV = [[UIAlertView alloc]initWithTitle:nil message:sMes delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil]; [alertV show]; [alertV release]; return; } CGSize mWinSize= [UIScreen mainScreen].bounds.size; if ([[[UIDevice currentDevice] systemVersion] floatValue] < 8.0) { std::swap(mWinSize.width, mWinSize.height); } LoadingView *lv = [[LoadingView alloc] initWithFrame:CGRectMake(0, 0, mWinSize.width, mWinSize.height)]; lv.tag = TAG_VIEW_LOADING; [[EAGLView sharedEGLView] addSubview:lv]; [lv release]; if ([SKPaymentQueue canMakePayments]) { NSLog(@"addObserver:receiveAppStoreInfo"); [[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(receiveAppStoreInfo:) name:NOTIFICATION_APPSTORE_BUY_FOLDER object:nil]; [[CBiOSStoreManager sharedInstance] initialStore]; [[CBiOSStoreManager sharedInstance] buy:[NSString stringWithFormat:@"%@%d",BUY_ID,index] paramRoleId:paramRoleId]; } else { UIAlertView *alert = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"STR_BUY_ERROR", nil) message:NSLocalizedString(@"STR_BUY_ERROR_INFO", nil) delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil]; [alert show]; [alert release]; if([[EAGLView sharedEGLView] viewWithTag:TAG_VIEW_LOADING]) [[[EAGLView sharedEGLView] viewWithTag:TAG_VIEW_LOADING] removeFromSuperview]; } } //购买成功函数回调 -(void)receiveAppStoreInfo:(id)sender { NSLog(@"receive info"); if([[EAGLView sharedEGLView] viewWithTag:TAG_VIEW_LOADING]) { [[[EAGLView sharedEGLView] viewWithTag:TAG_VIEW_LOADING] removeFromSuperview]; } NSNotification *notification = (NSNotification *)sender; NSString *action = [notification object]; if ([action isEqualToString:MSG_ACTION_FINISH]) { NSLog(@"------------MSG_ACTION_FINISH==============购买成功"); } [[NSNotificationCenter defaultCenter] removeObserver:self name:NOTIFICATION_APPSTORE_BUY_FOLDER object:nil]; }
/* * CBiOSStoreManager.mm * CloudBox Cross-Platform Framework Project * * Created by xxhh on 2012/10/30. * */ #import "CBiOSStoreManager.h" #define SERVER_DOMAIN @"http://192.168.0.177" #define TEST_SANDBOX 1 @implementation CBiOSStoreManager //自身实例 static CBiOSStoreManager* _sharedInstance = nil; //付费单例获取 +(CBiOSStoreManager*)sharedInstance { @synchronized([CBiOSStoreManager class]) { if (!_sharedInstance) [[self alloc] init]; return _sharedInstance; } return nil; } // +(id)alloc { @synchronized([CBiOSStoreManager class]) { NSAssert(_sharedInstance == nil, @"Attempted to allocate a second instance of a singleton.\n"); _sharedInstance = [super alloc]; return _sharedInstance; } return nil; } -(id)init { self = [super init]; if (self != nil) { } return self; } -(void)initialStore { [[SKPaymentQueue defaultQueue] addTransactionObserver:self]; } -(void)releaseStore { [[SKPaymentQueue defaultQueue] removeTransactionObserver:self]; } -(void)buy:(NSString*)buyProductIDTag paramRoleId:(NSString *)paramRoleId { _paramRoleId=paramRoleId; [self requestProductData:buyProductIDTag]; } //查找付费列表。 -(bool)CanMakePay { NSLog(@"----------CanMakePay--------------\n"); return [SKPaymentQueue canMakePayments]; } -(void)requestProductData:(NSString*)buyProductIDTag { NSLog(@"----------Request--------------\n"); _buyProductIDTag = [buyProductIDTag retain]; NSArray *product = [[NSArray alloc] initWithObjects:buyProductIDTag,nil]; NSSet *nsset = [NSSet setWithArray:product]; SKProductsRequest *request=[[SKProductsRequest alloc] initWithProductIdentifiers: nsset]; request.delegate=self; [request start]; [product release]; } - (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response{ NSLog(@"----------didReceiveResponse--------------\n"); SKPayment *payment = nil; if (response == NULL || response.products == NULL || response.products.count == 0) { [[NSNotificationCenter defaultCenter] postNotificationName:NOTIFICATION_APPSTORE_BUY_FOLDER object:MSG_ACTION_ERROR]; [request autorelease]; return; } payment = [SKPayment paymentWithProduct:[response.products objectAtIndex:0]]; [[SKPaymentQueue defaultQueue] addPayment:payment]; [request autorelease]; } - (void)requestProUpgradeProductData:(NSString*)buyProductIDTag { NSLog(@"----------requestProUpgradeProductData--------------\n"); NSSet *productIdentifiers = [NSSet setWithObject:buyProductIDTag]; SKProductsRequest* productsRequest = [[SKProductsRequest alloc] initWithProductIdentifiers:productIdentifiers]; productsRequest.delegate = self; [productsRequest start]; } - (void)request:(SKRequest *)request didFailWithError:(NSError *)error { NSLog(@"----------Request Failed--------------\n"); [[NSNotificationCenter defaultCenter] postNotificationName:NOTIFICATION_APPSTORE_BUY_FOLDER object:MSG_ACTION_ERROR]; } -(void) requestDidFinish:(SKRequest *)request { NSLog(@"----------Request finished--------------\n"); } -(void) purchasedTransaction: (SKPaymentTransaction *)transaction { NSLog(@"-----Purchased Transaction----\n"); NSArray *transactions =[[NSArray alloc] initWithObjects:transaction, nil]; [self paymentQueue:[SKPaymentQueue defaultQueue] updatedTransactions:transactions]; [transactions release]; } - (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions { NSLog(@"----------updatedTransactions--------------\n"); for (SKPaymentTransaction *transaction in transactions) { switch (transaction.transactionState) { case SKPaymentTransactionStatePurchased: NSLog(@"-----Transaction--购买完成-----\n"); [self completeTransaction:transaction]; break; case SKPaymentTransactionStateFailed:{ [self failedTransaction:transaction]; NSLog(@"-----Transaction Failed--购买失败-----\n"); break; } case SKPaymentTransactionStateRestored: [self restoreTransaction:transaction]; NSLog(@"----- Already buy this product---已经购买-----\n"); case SKPaymentTransactionStatePurchasing: NSLog(@"-----Transcation puchasing---正在购买-----\n"); break; default: break; } } } - (void) completeTransaction: (SKPaymentTransaction *)transaction { // 验证购买凭据 [self verifyReceipt:transaction]; NSString *sBuyID = transaction.payment.productIdentifier; NSLog(@"completeTransaction: BuyID: %@", sBuyID); [[NSNotificationCenter defaultCenter] postNotificationName:NOTIFICATION_APPSTORE_BUY_FOLDER object:MSG_ACTION_FINISH]; // 将交易从交易队列中删除 [[SKPaymentQueue defaultQueue] finishTransaction: transaction]; } #pragma mark 本地验证购买凭据 - (void)verifyPruchase:(SKPaymentTransaction *)transaction { // transaction.transactionReceipt // 验证凭据,获取到苹果返回的交易凭据 // appStoreReceiptURL iOS7.0增加的,购买交易完成后,会将凭据存放在该地址 // NSURL *receiptURL = [[NSBundle mainBundle] appStoreReceiptURL]; // 从沙盒中获取到购买凭据 // NSData *receiptData = [NSData dataWithContentsOfURL:receiptURL]; // 发送网络POST请求,对购买凭据进行验证 // NSURL *url = [NSURL URLWithString:@"https://sandbox.itunes.apple.com/verifyReceipt"]; // 国内访问苹果服务器比较慢,timeoutInterval需要长一点 // NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:10.0f]; // request.HTTPMethod = @"POST"; // 在网络中传输数据,大多情况下是传输的字符串而不是二进制数据 // 传输的是BASE64编码的字符串 /** BASE64 常用的编码方案,通常用于数据传输,以及加密算法的基础算法,传输过程中能够保证数据传输的稳定性 BASE64是可以编码和解码的 */ // NSString *encodeStr = [receiptData base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithLineFeed]; // NSString *encodeStr = [transaction.transactionReceipt base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithLineFeed]; // NSString *payload = [NSString stringWithFormat:@"{\"receipt-data\" : \"%@\"}", encodeStr]; // NSData *payloadData = [payload dataUsingEncoding:NSUTF8StringEncoding]; // request.HTTPBody = payloadData; // 提交验证请求,并获得官方的验证JSON结果 // NSData *result = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil]; // 官方验证结果为空 // if (result == nil) { // NSLog(@"验证失败"); // } // NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:result options:NSJSONReadingAllowFragments error:nil]; // NSLog(@"%@", dict); // if (dict != nil) { // 比对字典中以下信息基本上可以保证数据安全 // bundle_id&application_version&product_id&transaction_id // NSLog(@"验证成功"); // } } #pragma mark 服务器验证购买凭据 - (void) verifyReceipt:(SKPaymentTransaction *)transaction { NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"%@/verify.php", SERVER_DOMAIN]]; NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:10.0f]; request.HTTPMethod = @"POST"; NSString *encodeStr = [transaction.transactionReceipt base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithLineFeed]; int isSandBox =0; #ifdef TEST_SANDBOX isSandBox=1; #endif NSString *payload = [NSString stringWithFormat:@"{\"receipt-data\" : \"%@\",\"sandbox\":%d,\"paramRoleId\":\"%@\"}", encodeStr,isSandBox,_paramRoleId]; //把bodyString转换为NSData数据 NSData *bodyData = [payload dataUsingEncoding:NSUTF8StringEncoding allowLossyConversion:YES];//把bodyString转换为NSData数据 [request setHTTPBody:bodyData]; // 提交验证请求,并获得官方的验证JSON结果 NSData *result = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil]; // 官方验证结果为空 if (result == nil) { NSLog(@"验证失败"); } else { NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:result options:NSJSONReadingAllowFragments error:nil]; if (dict != nil && [[dict objectForKey:@"status"]integerValue] ==1 && [[dict objectForKey:@"success"]integerValue] ==1) { // 比对字典中以下信息基本上可以保证数据安全 NSLog(@"验证成功"); }else { NSLog(@"验证失败"); } } } -(void)recordTransaction:(NSString *)product { NSLog(@"-----Record transcation--------\n"); } -(void)provideContent:(NSString *)product { NSLog(@"-----Download product content--------\n"); } - (void) failedTransaction: (SKPaymentTransaction *)transaction { NSLog(@"-----failedTransaction--------\n"); NSNotification *notification= [NSNotification notificationWithName:NOTIFICATION_APPSTORE_BUY_FOLDER object:MSG_ACTION_ERROR]; NSNotificationCenter *center = [NSNotificationCenter defaultCenter]; if (center == nil && notification == nil) { NSLog(@"null"); } [center postNotification:notification]; [[NSNotificationCenter defaultCenter] postNotificationName:NOTIFICATION_APPSTORE_BUY_FOLDER object:MSG_ACTION_ERROR]; if (transaction.error.code != SKErrorPaymentCancelled) { if(transaction.error.code == SKErrorUnknown) { NSLog(@"Unknown Error (%d), product: %@", (int)transaction.error.code, transaction.payment.productIdentifier); UIAlertView *failureAlert = [[UIAlertView alloc] initWithTitle :@"In-App-Purchase Error:" message: @"There was an error purchasing this item please try again." delegate : self cancelButtonTitle:@"OK"otherButtonTitles:nil]; [failureAlert show]; [failureAlert release]; } if(transaction.error.code == SKErrorClientInvalid) { NSLog(@"Client invalid (%d), product: %@", (int)transaction.error.code, transaction.payment.productIdentifier); UIAlertView *failureAlert = [[UIAlertView alloc] initWithTitle :@"In-App-Purchase Error:" message: @"There was an error purchasing this item please try again." delegate : self cancelButtonTitle:@"OK"otherButtonTitles:nil]; [failureAlert show]; [failureAlert release]; } if(transaction.error.code == SKErrorPaymentInvalid) { NSLog(@"Payment invalid (%d), product: %@", (int)transaction.error.code, transaction.payment.productIdentifier); UIAlertView *failureAlert = [[UIAlertView alloc] initWithTitle :@"In-App-Purchase Error:" message: @"There was an error purchasing this item please try again." delegate : self cancelButtonTitle:@"OK"otherButtonTitles:nil]; [failureAlert show]; [failureAlert release]; } if(transaction.error.code == SKErrorPaymentNotAllowed) { NSLog(@"Payment not allowed (%d), product: %@", (int)transaction.error.code, transaction.payment.productIdentifier); UIAlertView *failureAlert = [[UIAlertView alloc] initWithTitle :@"In-App-Purchase Error:" message: @"There was an error purchasing this item please try again." delegate : self cancelButtonTitle:@"OK"otherButtonTitles:nil]; [failureAlert show]; [failureAlert release]; } } [[SKPaymentQueue defaultQueue] finishTransaction: transaction]; } -(void) paymentQueueRestoreCompletedTransactionsFinished: (SKPaymentTransaction *)transaction { NSLog(@"-----paymentQueueRestoreCompletedTransactionsFinished-------\n"); } - (void) restoreTransaction: (SKPaymentTransaction *)transaction { NSLog(@"-----Restore transaction--------\n"); } -(void) paymentQueue:(SKPaymentQueue *) paymentQueue restoreCompletedTransactionsFailedWithError:(NSError *)error { NSLog(@"-------Payment Queue----\n"); } -(void)dealloc { [super dealloc]; } @end
/* * CBiOSStoreManager.h * CloudBox Cross-Platform Framework Project * * Created by xxhh on 2012/10/30. * */ #import #import #define NOTIFICATION_APPSTORE_BUY_FOLDER @"buy_folder" #define MSG_ACTION_ERROR @"msg_action_error" #define MSG_ACTION_FINISH @"msg_action_finish" #define MSG_ACTION_RESTORE @"msg_action_restore" @interface CBiOSStoreManager : NSObject { int buyType; NSString* _buyProductIDTag; NSString* _paramRoleId; } + (CBiOSStoreManager*) sharedInstance; - (void) buy:(NSString*)buyProductIDTag paramRoleId:(NSString *)paramRoleId; - (bool) CanMakePay; - (void) initialStore; - (void) releaseStore; - (void) requestProductData:(NSString*)buyProductIDTag; - (void) provideContent:(NSString *)product; - (void) recordTransaction:(NSString *)product; - (void) requestProUpgradeProductData:(NSString*)buyProductIDTag; - (void) paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions; - (void) purchasedTransaction: (SKPaymentTransaction *)transaction; - (void) completeTransaction: (SKPaymentTransaction *)transaction; - (void) failedTransaction: (SKPaymentTransaction *)transaction; - (void) paymentQueueRestoreCompletedTransactionsFinished: (SKPaymentTransaction *)transaction; - (void) paymentQueue:(SKPaymentQueue *) paymentQueue restoreCompletedTransactionsFailedWithError:(NSError *)error; - (void) restoreTransaction: (SKPaymentTransaction *)transaction; @end
// // LoadingView.m // pDownloader // // Created by xxhh on 10/5/09. // Copyright 2009 __MyCompanyName__. All rights reserved. // #import "LoadingView.h" #import @implementation LoadingView - (id)initWithFrame:(CGRect)frame { if ((self = [super initWithFrame:frame])) { // Initialization code self.backgroundColor = [UIColor colorWithRed:0 green:0 blue:0 alpha:0.0]; UIActivityIndicatorView *loadingview = [[UIActivityIndicatorView alloc]initWithFrame:CGRectMake(0 , 0, 36, 36)]; loadingview.center=CGPointMake(frame.size.width/2, frame.size.height/2-20); [loadingview startAnimating]; UIImageView *image = [[UIImageView alloc]initWithImage:[UIImage imageNamed:@"bg_black.png"]]; image.frame = CGRectMake(0, 0, 210, 150); image.center=CGPointMake(frame.size.width/2, frame.size.height/2); [self addSubview:image]; UILabel *labLoading = [[UILabel alloc]initWithFrame:CGRectMake(0, 0, 210, 200)]; labLoading.center=CGPointMake(frame.size.width/2, frame.size.height/2+20); labLoading.textAlignment = UITextAlignmentCenter; [labLoading setText:@"Loading..."]; [labLoading setBackgroundColor:[UIColor clearColor]]; [labLoading setTextColor:[UIColor whiteColor]]; [self addSubview:labLoading]; [self addSubview:loadingview]; UIButton *btn = [[UIButton alloc]initWithFrame:CGRectMake(0, 0, frame.size.width, frame.size.height)]; [self addSubview:btn]; [btn release]; [labLoading release]; [loadingview release]; [image release]; } return self; } - (void)drawRect:(CGRect)rect { // Drawing code } - (void)dealloc { [super dealloc]; } @end
// // LoadingView.h // pDownloader // // Created by leefj on 10/5/09. // Copyright 2009 __MyCompanyName__. All rights reserved. // #import #define TAG_VIEW_LOADING 1234 @interface LoadingView : UIView { } @end
服务器端代码
$receipt) ); $ch = curl_init($endpoint); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_POSTFIELDS, $postData); $response = curl_exec($ch); $errno = curl_errno($ch); $errmsg = curl_error($ch); curl_close($ch); if ($errno != 0) { throw new Exception($errmsg, $errno); } $data = json_decode($response); if (!is_object($data)) { throw new Exception('Invalid response data'); } if (!isset($data->status) || $data->status != 0) { throw new Exception('Invalid receipt'); } return array( 'quantity' => $data->receipt->quantity, 'product_id' => $data->receipt->product_id, //产品id 'transaction_id' => $data->receipt->transaction_id, 'purchase_date' => $data->receipt->purchase_date, 'app_item_id' => $data->receipt->app_item_id, 'bid' => $data->receipt->bid, 'bvrs' => $data->receipt->bvrs ); } $content=file_get_contents("php://input"); $data = json_decode($content,true); $receipt = $data["receipt-data"]; $isSandbox = (bool) $data["sandbox"]; $paramRoleId = $data["paramRoleId"]; $hostIp = $data["hostIp"]; try { $info = getReceiptData($receipt, $isSandbox); $infoJson=json_encode($info); //进行相关充值处理 // 日志记录 $fh = fopen("lshudong.txt", "a+"); fwrite($fh, "userId:".$paramRoleId."==hostIp:".$hostIp."==时间:".date("Y-m-d H:i:s") ." ==验证成功\n\r"); fclose($fh); // 发送回传消息 echo json_encode(array( 'status' => 1, 'success' => 1, )); } catch (Exception $ex) { echo $ex; //日志记录 $fh = fopen("lshudong.txt", "a+"); fwrite($fh, "userId:".$paramRoleId."hostIp:".$hostIp."时间:".date("Y-m-d H:i:s") ." 验证失败\n\r"); fclose($fh); //发送回传消息 echo json_encode(array( 'status' => 1, 'success' => 0, )); } ?>