这是第二篇


Cocos 2d-X Lua 游戏添加苹果内购(一) 图文详解准备流程

这是前面的第一篇,详细的说明了怎样添加内购项目以及填写银行信息提交以及沙盒测试员的添加使用以及需要我们注意的东西,结果,被移除首页了!前面第一篇的内容是这篇的基础,前面那些不弄好,下面的商品信息你是请求不到的,这点需要大家特别注意...有需要前面提到的内容的孩子可以点击链接进去自己看看!!

这篇就具体的总结我们Lua和OC交互的内容以及内购具体的代码以及结果的测试说明:

内购部分OC的代码实现


先自己总结一下整个支付的流程,下面的代码部分我们也就按照这个支付流程来解读:

最开始你首先要做的就是给你的项目添加: StoreKit.framework 框架

以及在你需要写支付的类中导入: #import <StoreKit/StoreKit.h>

并且你还得遵守 <SKPaymentTransactionObserver,SKProductsRequestDelegate > 两个协议,后面会实现他们相应的代理方法。

接下来你初始化了你支付类需要你初始化的东西之后,就开始判断用户有没有禁止了苹果支付,代码如下:

// 在这里先判断是否可以调用支付
-(void)isPay{// 判断用户是否禁止了苹果支付if ([SKPaymentQueue canMakePayments]) {// 1.获取产品信息列表[self requestProductData:PRODUCTID];}else{self.alertTitle   = @"充值失败";self.alertMessage = @"您禁止了支付权限!";#if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_8_0// 不能进行支付进行提示[self.viewController presentViewController:self.alertController animated:YES completion:nil];
#else[self.viewController.view addSubview:self.alertView];
#endif}
}

按照我们最开始时候的流程,接下来就需要我们去创建 SKProductsRequest 向苹果服务器请求商品的信息,具体的代码如下:

- (void)requestProductData:(NSString *)productId{NSArray * productArray = [[NSArray alloc]initWithObjects:productId, nil];NSSet   * productSet = [NSSet setWithArray:productArray];// 创建支付请求SKProductsRequest * productRequest = [[SKProductsRequest alloc]initWithProductIdentifiers:productSet];productRequest.delegate = self;[productRequest start];
}

注意: 上面代码中的 productId 就是我们刚开始在开发者后台创建新的内购产品时候的产品ID,要是不理解的强烈建议先看第一篇文章,得知道什么是产品ID。

#pragma mark -- SKRequestDelegate
// 下面的方法会接收苹果服务器返回的商品的产品信息
// Sent immediately before -requestDidFinish:
- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response {// 接收商品的信息NSArray * productInfo = response.products;if (productInfo.count ==0) {NSLog(@"接收到的商品的信息为空!");return;}else{// 打印出商品信息  以下的信息全都是在你开发者账号下面添加了内购项目中填写for (SKProduct *pro in productInfo) {NSLog(@"显示名称:%@", [pro localizedTitle]);NSLog(@"描述:%@", [pro localizedDescription]);NSLog(@"你设置的价格单位:%@", [pro price]);              // 注意这里的单位,是用你在内购项目里面设置的定价NSLog(@"单位:%@", [pro.priceLocale objectForKey:NSLocaleCurrencySymbol]);NSLog(@"CNY:%@", [pro.priceLocale objectForKey:NSLocaleCurrencyCode]);NSLog(@"测试商品ID:%@", [pro productIdentifier]);}}// SKProduct对象包含了在App Store上注册的商品的本地化信息。SKProduct *storeProduct = nil;for (SKProduct * pro in productInfo) {if ([pro.productIdentifier isEqualToString:PRODUCTID]) {storeProduct = pro;}}//创建一个支付对象,并放到队列中self.skMutablePayment = [SKMutablePayment paymentWithProduct:storeProduct];//设置购买的数量 具体的交易金额就是这里的  数量 * 开发者账号定价if (self.payParments != 0) {//开始调用支付    self.skMutablePayment.quantity = self.payParments;[[SKPaymentQueue defaultQueue] addPayment:self.skMutablePayment];// 开始一个内购监听[self startObserver];}else{NSLog(@"没有设置购买的数量!!");}
}

这一步就走到我们接收到了商品的信息,接下来要做的事按照前面给的流程图,就需要我们开启一个内购的监听。再给大家看到你请求到的商品的基本信息,如下:

具体的上面的内容是什么,大家可以对比上面的输出的时候循环里面我加了它们各自的信息。

可以看到我们现在是添加了一个监控,开始监控和结束监控的代码如下:

- (void)startObserver {if (!self.isObserver) {[[SKPaymentQueue defaultQueue] addTransactionObserver:self];NSLog(@"开始监听 ------ 内购");self.isObserver = YES;}
}- (void)stopObserver {if (self.isObserver) {[[SKPaymentQueue defaultQueue] removeTransactionObserver:self];NSLog(@"移除监听 ------ 内购");self.isObserver = NO;}
}

上面我们就开启了监听,也开始了支付,中间的怎样使用沙盒测试账号进行购买的测试,以及过程中需要注意的事项我们已经总结过了,可以看前面的文章。

等支付完成之后,我们就可以收到来自苹果支付结果的回调了,具体的回调处理下面的代码中有详细的注释:

#pragma mark -- SKPaymentTransactionObserver
//<SKPaymentTransactionObserver>千万不要忘记绑定,代码如下:
//监听购买结果
//[[SKPaymentQueue defaultQueue] addTransactionObserver:self];
- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray<SKPaymentTransaction *> *)transactions
{SKPaymentTransaction *transaction = transactions.lastObject;switch (transaction.transactionState) {// 购买成功case SKPaymentTransactionStatePurchased: {NSData *data = [NSData dataWithContentsOfFile:[[[NSBundle mainBundle] appStoreReceiptURL] path]];// 刚才交易的内购的清单NSString *receipt = [data base64EncodedStringWithOptions:0];NSLog(@"刚才交易的内购的清单:%@",receipt);// 对交易结果进行二次验证[self verifyPruchase];}break;// 交易失败case SKPaymentTransactionStateFailed: {NSLog(@"交易失败");// 交易失败也要回调服务端// 将交易从交易队列中删除[[SKPaymentQueue defaultQueue] finishTransaction:transaction];}break;case SKPaymentTransactionStateRestored: {NSLog(@"这是你已经购买过该商品!");[[SKPaymentQueue defaultQueue] finishTransaction:transaction];}break;case SKPaymentTransactionStatePurchasing: {NSLog(@"商品添加进列表");}break;default: {NSLog(@"这是什么情况啊?");}break;}
}

接下来在按照流程走的话就到二次验证支付结果的,其实我觉得这个过程放在移动端问题也不大,整个过程走Https,也没有什么关键的数据怕数问题,不像支付宝和微信支付签名的过程一样那么重要,不过需要注意的是验证这个结果得地址是分开的,也就是在开发测试阶段和上线阶段的地址是不同的,发送网络POST请求,对购买凭据进行验证:

测试验证地址:https://sandbox.itunes.apple.com/verifyReceipt

正式验证地址:https://buy.itunes.apple.com/verifyReceipt

下面是具体的支付结果的验证代码:

#pragma mark 验证购买凭据
- (void)verifyPruchase {// 验证凭据,获取到苹果返回的交易凭据// appStoreReceiptURL iOS7.0增加的,购买交易完成后,会将凭据存放在该地址NSURL *receiptURL = [[NSBundle mainBundle] appStoreReceiptURL];// 从沙盒中获取到购买凭据NSData *receiptData = [NSData dataWithContentsOfURL:receiptURL];// 发送网络POST请求,对购买凭据进行验证//测试验证地址:https://sandbox.itunes.apple.com/verifyReceipt//正式验证地址:https://buy.itunes.apple.com/verifyReceiptNSURL *url = [NSURL URLWithString:@"https://sandbox.itunes.apple.com/verifyReceipt"];NSMutableURLRequest *urlRequest =[NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:10.0f];urlRequest.HTTPMethod = @"POST";NSString *encodeStr   = [receiptData base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithLineFeed];NSString *payload     = [NSString stringWithFormat:@"{\"receipt-data\" : \"%@\"}", encodeStr];NSData   *payloadData = [payload dataUsingEncoding:NSUTF8StringEncoding];urlRequest.HTTPBody   = payloadData;// 提交验证请求,并获得官方的验证JSON结果 iOS9后更改了另外的一个方法NSData *result = [NSURLConnection sendSynchronousRequest:urlRequest returningResponse:nil error:nil];// 官方验证结果为空if (result == nil) {NSLog(@"交易验证失败");return;}// 二次验证返回,在这里给服务端返回验证结果NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:result options:NSJSONReadingAllowFragments error:nil];if (dict != nil) {// 比对字典中以下信息基本上可以保证数据安全// bundle_id , application_version , product_id , transaction_idNSLog(@"验证成功!购买的商品的信息是:%@", dict);// 在这里回调Lua文件支付的结果NSDictionary * receipt = dict[@"receipt"];// 在连续的交易中,会有多笔交易产生NSArray * in_app  = receipt[@"in_app"];if (in_app.count !=0) {for (NSDictionary * dic in in_app) {// 订单号回调LuaNSString * transaction_id = dic[@"transaction_id"];[self toLuaFunc:self.handlerID backMsg:[transaction_id UTF8String]];}       }}else{// 交易不成功,回调LuaNSString * transaction_id = @" ";[self toLuaFunc:self.handlerID backMsg:[transaction_id UTF8String]];}
}

这样整个支付其实已经算是完成了的,看的仔细的朋友应该看到请求到回调结果之后我们OC回调Lua了,在这里成功之后我们是回调了Lua,在Lua俩面利用Socket向服务器去发送一个支付的确定的结果,下面我们说说Lua和OC的相互调用。

Lua 调用 OC


下面是自己在做的一个Lua文件和OC交互的一个大概的示意图,如下:

通过上面的一个示意图,在对比下面的代码,我们一句句的分析一下整个流程:

首先是第一步: Lua 文件调用 Bridge_ios  着重看一下下面几句代码:

-- 点击跳转到苹果支付界面
function Bridge_ios.presentApplePayWithParams(payParam, callback)--quantity 价格   callback回调local params = {quantity = payParam, scriptHandler = callback}local ok,ret = luaoc.callStaticMethod(BRIDGE_CLASS,"presentApplePayController",params)if not ok then-- 返回值print("luaj error:"..ret)   end
end

其实直接调用OC的就是  luaoc.callStaticMethod 这个方法,这个方法解释一下:

1、luaoc    local luaoc = require "cocos.cocos2d.luaoc"   这个Lua引入就像OC 的#import 一样!

2、BRIDGE_CLASS  这个表示你和OC的那个类进行交互。

3、"presentApplePayController" 接下来的这个参数,就是你OC类里面写的类方法!

4、params 顾名思义就是参数的意思,Lua 这里传过去的是以 表 的形式,相信懂Lua 的你也清楚,什么是表!

再说说这个参数:看这一句    local params = {quantity = payParam, scriptHandler = callback}

我们把参数写成了表的形式,用OC理解牛把它当成一个字典!quantity 是键  payParam 就是你要传的值  , scriptHandler 是键,callback是值,只不过它是函数,OC需要回调的函数,具体的用法我们下面说回调的时候再说。

在上面的调用中:BRIDGE_CLASS 就是 AppController。

OC 回调 Lua


前面说完了Lua 调用OC,下面接着说说 OC是怎样回调Lua 的,具体的根据下面的代码解释:

// Lua 回调函数
- (void) toLuaFunc: (int)funC backMsg:(std::string)msg{
#if CC_ENABLE_SCRIPT_BINDINGint handler = funC;if (-1 != handler){auto sc = cocos2d::Director::getInstance()->getScheduler();sc->performFunctionInCocosThread([handler, msg](){cocos2d::LuaBridge::pushLuaFunctionById(handler);cocos2d::LuaStack *stack = cocos2d::LuaBridge::getStack();stack->pushString(msg.c_str());stack->executeFunction(1);cocos2d::LuaBridge::releaseLuaFunctionById(handler);});}
#endif
}

最后我们一句一句的解释一下上面这个OC回调Lua的过程:

LuaBridge::pushLuaFunctionById(handlerID); //压入需要调用的方法id(假设方法为XG)

LuaStack *stack = LuaBridge::getStack(); //获取lua栈

stack->pushString("oc call lua method..."); //将需要通过方法XG传递给lua的参数压入lua栈,这里也就是设置OC回调给Lua的参数

stack->executeFunction(1); //根据压入的方法id调用方法XG,并把XG方法参数传递给lua代码

LuaBridge::releaseLuaFunctionById(handlerID); //最后记得释放一下function

上面的这整个过程,再结合我们第一篇文章写得苹果内购的图文详解流程,基本上一个完整的游戏添加内购的过程就算是结束了,要是有什么问题可以在我的主页找我的QQ或者下面留言给我!!

Cocos 2d-X Lua 游戏添加苹果内购(一) 图文详解准备流程

转载于:https://www.cnblogs.com/zhangxiaoxu/p/7729693.html

Cocos 2d-X Lua 游戏添加苹果内购(二) OC和Lua交互代码详解相关推荐

  1. Cocos 2d-X Lua 游戏添加苹果内购(一) 图文详解准备流程

    事前准备 最近给游戏添加了苹果的内购,这一块的东西也是刚刚做完,总结一下,其实这里不管是游戏还是我们普通的App添加内购这一块的东西都是差不多的,多出来的部分就是我们Lua和OC的交互的部分,以前刚开 ...

  2. iOS开发系列--通讯录、蓝牙、内购、GameCenter、iCloud、Passbook详解

    代码改变世界 Posts - 69, Articles - 0, Comments - 812 Cnblogs Dashboard Login Home Contact Gallery RSS Ken ...

  3. iOS开发 IAP苹果内购

    为什么80%的码农都做不了架构师?>>>    1.概念介绍 <1>苹果内购: App内购买是指在苹果的 App Store 中购买应用程序的方式. 在玩一些游戏类应用软 ...

  4. Unity接入苹果内购(IAP)

    Unity接入苹果内购(IAP) 前言 苹果支付流程 配置App 配置商品 协议.税务和银行业务 沙盒测试账号 Unity(IAP) 测试 前言 第一次发帖,有点激动嘿嘿!话不多说直接奔主题,项目中需 ...

  5. 苹果内购噩梦条款3.1.1,知道这些小细节才不会被拒审

    说到苹果审核被拒条款的C位,3.1.1必须有姓名. 3.1.1作为常年呆在被拒前三位的条款,已经让一大批互联网民工脱了发. 3.1.1让人头疼的点都有哪些? • 审核周期长一直卡包: • 根本没办法隐 ...

  6. 真正手把手教你用unity接入苹果内购(IAP)

    原帖:真正手把手教你用unity接入苹果内购(IAP) http://www.manew.com/thread-100403-1-1.html (出处: -[游戏蛮牛]-ar增强现实,虚拟现实,uni ...

  7. iOS_苹果内购详细步骤

    iOS苹果内购详细步骤 iOS开发支付的两种方式 1 Apple Pay + 调取外部支付,例如支付宝.微信.银联等 2 苹果内购IAP(In-App Purchase) 1 IAP规则详解 1.1 ...

  8. 【iOS】苹果内购调研

    参考文章 官方文档 iOS开发内购全套图文教程 App Store上架指导 苹果不允许 iOS 应用内置购买(IAP)使用第三方支付方式,那么跨平台的电子书阅读器怎么解决这个问题? 应用内购(In-A ...

  9. 苹果内购和 Apple Pay

    作者:CC老师_MissCC 链接:http://www.jianshu.com/p/e3bc47e81785 來源:简书 苹果内购 1.什么是内购? 如果你购买的商品,是在本app中使用和消耗的,就 ...

最新文章

  1. ibatis源码浅析- 初探
  2. 再生希尔伯特空间_向量、函数向量、再生核希尔伯特空间、核技巧
  3. 调用百度 Echarts 显示重庆市地图
  4. CSS3 移动端开发技巧
  5. Redis分布式锁的实现原理看这篇就够了~
  6. [C++] Pure Virtual Function and Abstract Class
  7. set列表对象去重_Redis中hash、set、zset有多牛?从底层告诉你数据结构原理
  8. MiniProfiler工具介绍
  9. python 抓取网页工具
  10. 第二章:WINDOWS的一些技巧
  11. idea导入项目的问题:nothing found
  12. linux realtek声卡驱动下载,一步一步安装Realtek ALC888、ALC1200 声卡(附Realtek ALC888 ALC1200驱动)...
  13. 缅柬泰之色---彩图大串联 一 (缅甸篇)
  14. (1)ROS安装时Rosdep 报错解决教程
  15. Tagtraum.Industries.beaTunes.v3.5.7.Incl.Keygen-NOY
  16. 数字音乐各种高保真音乐格式
  17. Android第三方库收藏汇总
  18. 设置短域名跳转目标网址,长链接缩短的方法
  19. 【超详细】使用Oracle VM VirtualBox 搭建一个Linux虚拟机
  20. python产品质量分析_产品评论 使用Python分析Amazon Smart产品评论

热门文章

  1. MySQL----ERROR 1071 (42000): Specified key was too long; max key length is 767 bytes
  2. MySQL 慢查询日志工具之pt-query-digest
  3. location和location.href跳转url的区别
  4. 用js改变embed标签的src值
  5. Camtasia Studio 7 试用笔记
  6. mysql unsupported data type._数据查询Unsupported command错误
  7. CloudStack相关技术-主存储和二级存储
  8. 华为首款搭载鸿蒙os 荣耀智慧屏,全球首款搭载鸿蒙OS终端! 荣耀智慧屏将在今天拉开面纱...
  9. leetcode算法题--一周中的第几天
  10. 《剑指Offer》题一~题十