以前都是在本地处理内购 也没有做验证。这次手机网游 为了避免作弊 网络游戏都是在服务器端实现元宝的加减。
内购代码 还是以前写的 直接用了 。这次主要做了服务器二次验证。
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
php 时间函数衔接
服务器端代码
$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,
));
}
?>