ios 內購 伺服器二次驗證元寶處理
阿新 • • 發佈:2019-01-23
以前都是在本地處理內購 也沒有做驗證。這次手機網遊 為了避免作弊 網路遊戲都是在伺服器端實現元寶的加減。
內購程式碼 還是以前寫的 直接用了 。這次主要做了伺服器二次驗證。
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,
));
}
?>