cocos2dx中的IAP实现:一
A.苹果内购IAP两种模式流程:
1.内置模式:
app从app store 获取产品信息
用户选择需要购买的产品
app发送支付请求到app store
app store 处理支付请求,并返回transaction信息
app将购买的内容展示给用户
app从app store 获取产品信息
用户选择需要购买的产品
app发送支付请求到app store
app store 处理支付请求,并返回transaction信息
app将购买的内容展示给用户
2.服务器模式的流程:
app从服务器获取产品标识列表
app从app store 获取产品信息
用户选择需要购买的产品
app 发送 支付请求到app store
app store 处理支付请求,返回transaction信息
app 将transaction receipt 发送到服务器
服务器收到收据后发送到app stroe验证收据的有效性
app store 返回收据的验证结果
根据app store 返回的结果决定用户是否购买成功
上述两种模式的不同之处主要在于:交易的收据验证,内建模式没有专门去验证交易收据,而服务器模式会使用独立的服务器去验证交易收据。内建模式简单快捷,但容易被破解。服务器模式流程相对复杂,但相对安全。
B.内置模式代码实现:添加StoreKit.framework
PaymentController.h文件:
/*
* PaymentController.h
*
* Created by chiu on 15-06-16.
* Copyright (c) 2015年 Idlehands. All rights reserved.
*/
#import <UIKit/UIKit.h>
#import <StoreKit/StoreKit.h>
@interface PaymentController : NSObject<SKPaymentTransactionObserver,SKProductsRequestDelegate>
@property NSString *productID;
- (void)initProductId:(NSString*) productIdStr;
- (void)purchaseFunc;
@end
PaymentController.mm文件:
/*
author: chiu
project: BYGame
date: 2016/08/22
*/
#import "PaymentController.h"
#import "CCHelp.h"
@interface PaymentController ()
@end
@implementation PaymentController
static bool hasAddObersver = NO;
- (id)initWithPayConstructor:(NSString *) productIdStr
{
self = [super init];
if (self) {
// Custom initialization
[self initProductId:productIdStr];
if (!hasAddObersver) {
hasAddObersver = YES;
// 监听购买结果
[[SKPaymentQueue defaultQueue] addTransactionObserver:self];
}
}
return self;
}
- (void)initProductId:(NSString*) productIdStr
{
self.productID = productIdStr;
}
- (void)purchaseFunc{
NSString *product = self.productID;
if([SKPaymentQueue canMakePayments]){
[self requestProductData:product];
NSLog(@"允许程序内付费");
}else{
NSLog(@"不允许程序内付费");
}
}
//请求商品
- (void)requestProductData:(NSString *)type{
NSLog(@"-------------请求对应的产品信息----------------");
NSArray *product = [[NSArray alloc] initWithObjects:type, 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(@"--------------收到产品反馈消息---------------------");
NSArray *product = response.products;
if([product count] == 0){
NSLog(@"--------------没有商品------------------");
return;
}
NSLog(@"productID:%@", response.invalidProductIdentifiers);
NSLog(@"产品付费数量:%d",[product count]);
SKProduct *payInfoPorduct = nil;
for (SKProduct *pro in product) {
NSLog(@"%@", [pro description]);
NSLog(@"%@", [pro localizedTitle]);
NSLog(@"%@", [pro localizedDescription]);
NSLog(@"%@", [pro price]);
NSLog(@"%@", [pro productIdentifier]);
if([pro.productIdentifier isEqualToString:self.productID]){
payInfoPorduct = pro;
}
}
if(!payInfoPorduct)
{
return;
}
NSLog(@"发送购买请求");
if (floor(NSFoundationVersionNumber) < NSFoundationVersionNumber_iOS_5_0)
{
NSLog(@"pay_it less 5.0");
SKPayment* payment = [SKPayment paymentWithProductIdentifier:self.productID];
[[SKPaymentQueue defaultQueue] addPayment:payment];
}
else
{
NSLog(@"pay_it 5.0+");
SKMutablePayment* payment = [SKMutablePayment paymentWithProduct:payInfoPorduct];
payment.quantity = [product count];
[[SKPaymentQueue defaultQueue] addPayment:payment];
}
[request autorelease];
}
- (void)requestProUpgradeProductData
{
NSLog(@"------请求升级数据---------");
NSSet *productIdentifiers = [NSSet setWithObject:@"com.productid"];
SKProductsRequest* productsRequest = [[SKProductsRequest alloc] initWithProductIdentifiers:productIdentifiers];
productsRequest.delegate = self;
[productsRequest start];
}
//请求失败
- (void)request:(SKRequest *)request didFailWithError:(NSError *)error{
NSLog(@"------------------错误-----------------:%@", error);
UIAlertView *alerView = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"Alert",NULL) message:[error localizedDescription]
delegate:nil cancelButtonTitle:NSLocalizedString(@"Close",nil) otherButtonTitles:nil];
[alerView show];
[alerView release];
}
- (void)requestDidFinish:(SKRequest *)request{
NSLog(@"------------反馈信息结束-----------------");
}
-(void) PurchasedTransaction: (SKPaymentTransaction *)transaction{
NSLog(@"-----PurchasedTransaction----");
NSArray *transactions =[[NSArray alloc] initWithObjects:transaction, nil];
[self paymentQueue:[SKPaymentQueue defaultQueue] updatedTransactions:transactions];
[transactions release];
}
//监听购买结果
- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transaction{
for(SKPaymentTransaction *tran in transaction){
switch (tran.transactionState) {
case SKPaymentTransactionStatePurchased:
{
NSLog(@"交易完成");
[self completeTransaction:tran];
CCHelp* cppHelper = GetCCHelp();
cppHelper->purchaseResult(1,1);
[[SKPaymentQueue defaultQueue] finishTransaction:tran];
}
break;
case SKPaymentTransactionStatePurchasing:
{
NSLog(@"商品添加进列表");
}
break;
case SKPaymentTransactionStateRestored:
{
NSLog(@"已经购买过商品");
[self restoreTransaction:tran];
[[SKPaymentQueue defaultQueue] finishTransaction:tran];
}
break;
case SKPaymentTransactionStateFailed:
{
NSLog(@"交易失败");
[self failedTransaction:tran];
CCHelp* cppHelper = GetCCHelp();
cppHelper->purchaseResult(1,-1);
[[SKPaymentQueue defaultQueue] finishTransaction:tran];
}
break;
default:
{
CCHelp* cppHelper = GetCCHelp();
cppHelper->purchaseResult(1,-1);
[[SKPaymentQueue defaultQueue] finishTransaction:tran];
}
break;
}
}
}
//交易结束
- (void)completeTransaction:(SKPaymentTransaction *)transaction{
NSLog(@"交易结束");
// Remove the transaction from the payment queue.
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
}
- (void) failedTransaction: (SKPaymentTransaction *)transaction{
if (transaction.error.code != SKErrorPaymentCancelled)
{
}
switch (transaction.error.code) {
case SKErrorUnknown:
NSLog(@"SKErrorUnknown");
break;
case SKErrorClientInvalid:
NSLog(@"SKErrorClientInvalid");
break;
case SKErrorPaymentCancelled:
NSLog(@"SKErrorPaymentCancelled");
break;
case SKErrorPaymentInvalid:
NSLog(@"SKErrorPaymentInvalid");
break;
case SKErrorPaymentNotAllowed:
NSLog(@"SKErrorPaymentNotAllowed");
break;
case SKErrorStoreProductNotAvailable:
NSLog(@"SKErrorStoreProductNotAvailable");
break;
default:
break;
}
[[SKPaymentQueue defaultQueue] finishTransaction: transaction];
}
- (void) restoreTransaction: (SKPaymentTransaction *)transaction
{
}
#pragma mark connection delegate
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
NSLog(@"%@", [[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] autorelease]);
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection{
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response{
switch([(NSHTTPURLResponse *)response statusCode]) {
case 200:
case 206:
break;
case 304:
break;
case 400:
break;
case 404:
break;
case 416:
break;
case 403:
break;
case 401:
case 500:
break;
default:
break;
}
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
NSLog(@"test");
}
- (void)dealloc{
[[SKPaymentQueue defaultQueue] removeTransactionObserver:self];
[super dealloc];
}
@end
调用例子:
/* Ios IAP entrance */
int payPrice = pNotify->GetSubType();
std::string productIdStr;
switch (payPrice)
{
case 1024:
productIdStr = "ttz_yk";
break;
case 1025:
productIdStr = "ttz_6";
break;
default:
break;
}
NSLog(@"----------当前商品ID: %s", productIdStr.c_str());
NSString* ocProductIdStr = [NSString stringWithFormat:@"%s",
productIdStr.c_str()];
PaymentController* pPayController = [[PaymentController alloc] initWithPayConstructor:ocProductIdStr];
[pPayController purchaseFunc];
PS:内置模式并没有做订单凭证后台验证,整个流程看起来都非常简单,所以是很不安全的方式,容易被破解内购产品刷单,下篇blog处理服务器模式