IAP实现之一服务器模式 — cocos2dx
来源:互联网 发布:java编程工具哪个好 编辑:程序博客网 时间:2024/05/22 20:58
cocos2dx中的IAP实现:二
C.服务器模式代码实现:添加StoreKit.framework,走完正常的内购前半流程
completeTransaction中处理receipt-data发送至server验证
1.发送数据有几点要注意的:
a.不建议使用AFN方式,虽然封装的比较好,但用不好各种闪退
b.原生OC NSURLSession 也不建议使用,发送请求另起线程会影响cocos2dx的渲染线程,遇到过回来部分UI画不出来的情况
c.使用cocos2dx的curl库就可以了
2.具体代码实现:
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;@property bool startContentService; /* 接收验证控制变量 */- (void)initProductId:(NSString*) productIdStr;- (void)purchaseFunc;- (void)iapDealReceiptFun:(SKPaymentTransaction *)transaction;@end
/* author: chiu project: BYGame date: 2016/08/22 */#import "PaymentController.h"#import "CCHelp.h"@interface PaymentController ()@end@implementation PaymentControllerstatic bool hasAddObersver = NO;- (id)initWithPayConstructor:(NSString *) productIdStr{ self = [super init]; if (self) { // Custom initialization [self initProductId:productIdStr]; self.startContentService = true; if (!hasAddObersver) { hasAddObersver = YES; // 监听购买结果 [[SKPaymentQueue defaultQueue] addTransactionObserver:self]; } } return self;}- (void)initProductId:(NSString*) productIdStr{ self.productID = productIdStr; self.startContentService = true;}- (void)purchaseFunc{ NSString *product = self.productID; if([SKPaymentQueue canMakePayments]){ [self requestProductData:product]; NSLog(@"允许程序内付费"); }else{ NSLog(@"不允许程序内付费"); }}- (void)iapDealReceiptFun:(SKPaymentTransaction *)transaction{ NSData *receipt; receipt = transaction.transactionReceipt; if (!receipt) { /* No local receipt -- handle the error. */ } //因为此处可能会多次调用原因不明所以加判断只调用一次 else if (receipt && self.startContentService) { /** 服务器要做的事情: 接收ios端发过来的购买凭证。 判断凭证是否已经存在或验证过,然后存储该凭证。 将该凭证发送到苹果的服务器验证,并将验证结果返回给客户端。 如果需要,修改用户相应的会员权限 */ NSString *recepitNStr = [receipt base64EncodedStringWithOptions:0]; CCHelp* cppHelper = GetCCHelp(); cppHelper->purchaseRecepit([recepitNStr UTF8String]); }}//请求商品- (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]; self.startContentService = true; [[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]; //self.startContentService = false; [[SKPaymentQueue defaultQueue] finishTransaction:tran]; } break; default: { [[SKPaymentQueue defaultQueue] finishTransaction:tran]; } break; } }}//交易结束- (void)completeTransaction:(SKPaymentTransaction *)transaction{ NSLog(@"交易结束"); //交易结束向服务器发送验证receipt [self iapDealReceiptFun:transaction]; //这个千万别忘了 ,要不你就会犯第一条问题(配置消耗型物品重复购买却显示此项目免费恢复) // 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{ NSLog(@"connectionDidFinishLoading......");}- (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
使用NSURLSession方式发送:
//发送数据字典 后面转Json格式 NSDictionary *dic = @{@"receipt-data": [receipt base64EncodedStringWithOptions:0], @"order_id":[NSString stringWithFormat:@"%s",PayInstance::GetPayInstance()->getCurOrderIdStr().c_str()], @"user_id":[NSString stringWithFormat:@"%ld",GetUserInstance()->GetMeUserItem()->GetUserID()]}; /* 此处是当前订单号拼接生成验证地址 */ NSString* ocCurOrderIdUrlStr = [NSString stringWithFormat:@"http://xxx.xxxx.com:8003/xxxx.aspx?order_id=%s", PayInstance::GetPayInstance()->getCurOrderIdStr().c_str()]; /* 发送receipt至服务器验证 */ //1,创建会话对象 NSURLSession *session = [NSURLSession sharedSession]; //2,根据会话创建task NSURL *url = [NSURL URLWithString:ocCurOrderIdUrlStr]; //3,创建可变的请求对象 NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url]; //4,请求方法改为post request.HTTPMethod = @"POST"; //5,设置请求体-Json格式 NSData *postData = [NSJSONSerialization dataWithJSONObject:dic options:NSJSONWritingPrettyPrinted error:nil]; [request setHTTPBody:postData]; //6根据会话创建一个task(发送请求) NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) { /* 解析Http回调数据 */ NSDictionary * callBackDicData = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:nil]; NSLog(@"post dic = %@",dic); NSString *returnCodeNStr = [callBackDicData objectForKey:@"return_code"]; int returnCodeInt = [returnCodeNStr intValue]; if(returnCodeInt == 200 ){ /* 服务器验证收据成功 并确定支付成功后返回 */ CCHelp* cppHelper = GetCCHelp(); cppHelper->purchaseResult(1,1); } else{ CCHelp* cppHelper = GetCCHelp(); cppHelper->purchaseResult(1,-1); } }]; [dataTask resume];
使用cocos2dx方式发送:
void CCHelp::purchaseRecepit(const char* recepitDataStr){ if (recepitDataStr == nullptr) { return; } /* 此处是当前订单号拼接生成验证地址 */ CHttpRequest* pRequest = new CHttpRequest; YYDefineChar(url, 256, "%s","http://xxx.xxx.com:8003/xxx.aspx"); pRequest->setUrl(url); pRequest->setRequestType(CHttpRequest::Type::POST); YYDefineChar(szPostData,512*20,"receipt-data=%s&order_id=%s&user_id=%ld",recepitDataStr,PayInstance::GetPayInstance()->getCurOrderIdStr().c_str(),GetUserInstance()->GetMeUserItem()->GetUserID()); pRequest->setRequestData(szPostData,strlen(szPostData)); pRequest->setResponseCallback(CC_CALLBACK_2(CCHelp::onRecepitDataCallback, GetCCHelp())); CHttpClient::getInstance()->send(pRequest); pRequest->release();}
onRecepitDataCallback处理服务器验证收据回调
另外注意问题:
1.比第一个文档就多了个接收receipt-data过程处理,支付成功后由服务器加钻石金币处理,不再由客户端通知网站
2.整个服务器验证过程也有掉单的情况,像程序收到receipt-data后网络掉线,程序闪退,重复点击等等,方案是缓存recepit-data,由客户端判断订单状态,未完成的二次发送至服务器验证。后续补充.....
阅读全文
0 0
- IAP实现之一服务器模式 — cocos2dx
- IAP实现之一内建模式 — cocos2dx
- IAP实现之一掉单优化处理 — cocos2dx
- cocos2dx几种设计模式之一
- STR912--自编TFTP(服务器模式)IAP下载
- IAP 实现
- [cocos2dx 3.0 + iap]中文文档
- cocos2dx 代理模式实现方法
- 通过跳线方式实现STM32 的IAP模式
- Java实现Http服务器之一
- java服务器IAP验证
- cocos2dx 设计模式 观察者模式 实现
- STM32存储器 — <3> STM32实现IAP(上位机和IAP程序设计)
- 一个简单观察者模式的实现 cocos2dx
- Cocos2dx-lua实现单例设计模式
- 【IAP支付之二】In app purchase 本地购买和服务器购买两种购买模式
- 【IAP支付之二】In app purchase 本地购买和服务器购买两种购买模式
- STM32的IAP实现
- 欢迎使用CSDN-markdown编辑器
- tomcat启动报错java.net.MalformedURLException: Local host name unknown
- C++经典类库(C++开发必看)
- dp转换px
- mysql常用语法
- IAP实现之一服务器模式 — cocos2dx
- Git 分支
- 【Java基础总结】-异常与泛型
- node.js在本地启动https服务
- poi读取Excel时日期为数字 的解决方法
- TCP协议--TCP连接的建立和关闭
- 蚁族程序员自述:冬天盼暖气,面朝西二旗
- Qtablewidget设置某一列不可编辑
- javascript编写规范