coco2d-x游戏开发google play Google In-app-Billing 支付接入
android google play接入一样的操作借用了网上别人博客的部分 改正的一些错误,主要介绍 cocos2d-x google play 接入不一样的部分
如果没有GooglePlay此处附上安装Google Play的一键安装器的链接(需要Root权限):http://www.muzhiwan.com/com.muzhiwan.gsfinstaller-86095.html
注意:类型根据VPN而定,我用的是L2TP/IPSecPSK,选择此类型时,编辑只需填写名称,服务器地址和IPSec预共享密钥即可,然后连接的时候填写帐号和密码。当打开Google商店能看到付费软件表名VPN已成功连接,如果显示VPN已连接但还看不到付费软件时,进入应用程序管理器分别清除GooglePlay服务和Google Play商店数据之后再打开Google商店即可。
(2).Consuming In-app Products,消耗产品时的通信过程
(1).测试支付官方文档链接http://developer.android.com/google/play/billing/billing_testing.html
(2).Testing with staticresponses,静态测试,即当支付状态为一下四种情况时游戏逻辑是否正确。
- mHelper.launchPurchaseFlow(MainActivity.this,“android.test.purchased”,RC_REQUEST,mPurchaseFinishedListener);
mHelper.launchPurchaseFlow(MainActivity.this,“android.test.purchased”,RC_REQUEST,mPurchaseFinishedListener);
一:受管理商品和不受管理商品
1.IabHelper.OnIabPurchaseFinishedListener支付完成的回调,如果是受管理的商品在此回调中直接可以将道具给用户
2.IabHelper.OnConsumeFinishedListener消耗完成的回调,当不受管理的商品被成功消耗进入此回调,此时将不受管理的商品给用户
3.IabHelper.QueryInventoryFinishedListener查询完成的回调,RestoreOrder的时候用,当有订单成功付款但由于种种原因(突然断网、断电等)没收到Google支付成功的回调时,在这里可以查询到此订单,此时需要对订单进行处理(给用户道具等)。
四:测试用的app一定要跟上传到Google的测试版的包名、版本code、name、签名一致,否则无法进行支付测试。
1.当签名不一致或者版本code、版本name不一致时错误界面如下:
2.当包名不一致时错误界面如下:
接下来跟大家一起看一下代码具体实现:
1.下载in-app-billing-v03,下载地址:http://pan.baidu.com/share/link?shareid=1387554851&uk=473193131将下载后的压缩包解压:
将src目录下两个包及包中的java文件引入工程,例如:
2.添加权限:
- <uses-permission android:name="com.android.vending.BILLING" />
<uses-permissionandroid:name="com.android.vending.BILLING"/>
- String base64EncodedPublicKey ="";此处填写Google控制台添加新应用程序后的appid
- mHelper = new IabHelper(this, base64PublicKey);
- mHelper.enableDebugLogging(true);
- Log.d(TAG, "Starting setup.");
- System.out.println("#######################################");
- mHelper.startSetup(new OnIabSetupFinishedListener() {
- @Override
- public void onIabSetupFinished(IabResult result) {
- // TODO Auto-generated method stub
- Log.d(TAG,"setupfinish.");
- if(!result.isSuccess()){
- System.out.println("连接遇到问题"+result);
- return;
- }
- System.out.println("连接成功");
- iap_is_ok = true;
- mHelper.queryInventoryAsync(mGotInventoryListener);//回调未处理的订单
- }
- });
String base64EncodedPublicKey ="";此处填写Google控制台添加新应用程序后的appidmHelper =new IabHelper(this, base64EncodedPublicKey);// enable debuglogging (for a production application, you should set this tofalse).mHelper.enableDebugLogging(false);// Start setup. This is asynchronous andthe specified listener// will be called oncesetup completes.Log.d(TAG,"Starting setup.");mHelper.startSetup(new IabHelper.OnIabSetupFinishedListener(){publicvoid onIabSetupFinished(IabResult result){Log.d(TAG,"Setupfinished.");if (!result.isSuccess()) {// Ohnoes, there was a problem.complain("Problemsetting up in-app billing: " + result);return;}iap_is_ok = true;//Hooray, IAB is fully set up. Now, let's get an inventory of stuffwe own.Log.d(TAG, "Setup successful. Queryinginventory.");}});
调用支付接口:
System.out.println("@@@@@@@@@@@@@@@@@@@@@@@@@"+str);
mHelper.launchPurchaseFlow(this,这里是商品的id, 这里定义的请求id常量, mPurchaseFinishedListener);
}else{
System.out.println("连接失败");
jniHelper.SendErro();//我在这里是回调cocos2d-x中的c++代码
}
if(iap_is_ok){
mHelper.launchPurchaseFlow(MainActivity.this,skus[1],RC_REQUEST, mPurchaseFinishedListener);
}else {
showMessage("提示", "GooglePlay初始化失败,当前无法进行支付,请确定您所在地区支持Google Play支付或重启游戏再试!");
}
在jiniHeler类中代码
public static native int SendErro();
c++中的实现代码处理这个错误
extern"C"
{
void Java_org_cocos2dx_lua_jniHelper_SendErro(JNIEnv *env, jobject thiz)
{
CCLOG("CHENGONG");
getErroToLua();
}
};
调用查询接口:
- mHelper.queryInventoryAsync(mGotInventoryListener);
mHelper.queryInventoryAsync(mGotInventoryListener);
调用获取道具价格接口:(因Google市场是根据不同国家显示不同货币价格,所以显示到游戏道具列表中的价格不是定值,而是动态获取的)
billingservice =mHelper.getService();
Bundle querySkus = newBundle();querySkus.putStringArrayList("ITEM_ID_LIST", skus);
try {
Bundle skuDetails = billingservice.getSkuDetails(3,MainActivity.this.getPackageName(),"inapp", querySkus);
ArrayList<String> responseList =skuDetails.getStringArrayList("DETAILS_LIST");
if (null!=responseList) {
for (String thisResponse :responseList) {try {
SkuDetails d = newSkuDetails(thisResponse);for (int i = 0; i <sku_list.size(); i++) {
if(sku_list.get(i).equals(d.getSku())) {
price_list.set(i, d.getPrice());
}
}
iapHandler.sendEmptyMessage(0);}catch (JSONException e) {
// TODO Auto-generated catchblock
e.printStackTrace();
}}
}
}catch (RemoteException e) {
// TODO Auto-generated catchblock
e.printStackTrace();
}
public void infoPrice(){
new Thread(new Runnable() {//写一个线程防止阻塞主线程
@Override
public void run() {
// TODO Auto-generated method stub
ArrayList<String> skus = new ArrayList<String>();
skus.add(DIAMOND_80);//这里的常量是我定义的商品id
skus.add(DIAMOND_400);
skus.add(DIAMOND_800);
skus.add(DIAMOND_1600);
skus.add(DIAMOND_4000);
skus.add(DIAMOND_8000);
billingservice = mHelper.getService();
if (billingservice != null){//这里做空判断防止客户设备没有安装google play 导致空错误
Bundle querySkus = new Bundle();
querySkus.putStringArrayList("ITEM_ID_LIST", skus);
System.out.println("##############"+querySkus.toString());
try {
Bundle skuDetails = billingservice.getSkuDetails(3, AppActivity.this.getPackageName(),"inapp", querySkus);
ArrayList<String> responseList = skuDetails.getStringArrayList("DETAILS_LIST");
if (null!=responseList) {
pstr="";
for (String thisResponse : responseList) {
try {
SkuDetails d = new SkuDetails(thisResponse);
pstr = pstr + d.getPrice()+",";//将价格连接成一个字符创传进cocos2d-x中的c++中
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}).start();
mpstr = pstr ;//这里 mpstr是一个全局的静态变量 pstr是一个 全局变量 这样的赋值为了 后面再静态方法中返回这个价格的组合字符创到c++中
}
public static String getPrice(){
return mpstr;//返回这个字符串
}
c++部分代码实现
注意:加上平台预编译
std::string OSHelper::getAPrice()
{
std::string str = "nil";
JniMethodInfo minfo;//定义Jni函数信息结构体
//getStaticMethodInfo 次函数返回一个bool值表示是否找到此函数
bool isHave = JniHelper::getStaticMethodInfo(minfo,
"org/cocos2dx/lua/AppActivity", //类的路径
"rtnActivity", //方法名
"()Ljava/lang/Object;"); //括号里的是参数,后面的是返回值。
jobject activityObj;
if (isHave) {
activityObj = minfo.env->CallStaticObjectMethod(minfo.classID, minfo.methodID);
}
CCLog("正确获取到 jobj");
//CCLog(jobj);
JniMethodInfo methodInfo;
isHave = JniHelper::getMethodInfo(methodInfo,
"org/cocos2dx/lua/AppActivity", //类的路径
"infoPrice", //方法名
"()V"); //括号里的是参数,后面的是返回值。
if (isHave) {
CCLog("jni-javadddddd函数执行完毕");
methodInfo.env->CallVoidMethod(activityObj, methodInfo.methodID);
//CCLOG(str);
}
CCLog("jni-java函数执行完毕");
JniMethodInfo minfop;
isHave = JniHelper::getStaticMethodInfo(minfop,
"org/cocos2dx/lua/AppActivity", //类的路径
"getPrice", //方法名
"()Ljava/lang/String;"); //括号里的是参数,后面的是返回值。
if (isHave) {
jstring jstr = (jstring)minfop.env->CallStaticObjectMethod(minfop.classID, minfop.methodID);
str = JniHelper::jstring2string(jstr);
}
return str;
}
三个回调:
- // Callback for when a purchase is finished
- IabHelper.OnIabPurchaseFinishedListener mPurchaseFinishedListener =newIabHelper.OnIabPurchaseFinishedListener() {
- publicvoidonIabPurchaseFinished(IabResult result, Purchase purchase) {
- Log.d(TAG,"Purchase finished: " + result+", purchase: " +purchase);
- if (result.isFailure()) {
- // Oh noes!
- complain("Error purchasing: " + result);
- return;
- }
- Log.d(TAG,"Purchase successful.");
- if(purchase.getSku().equals("coins_100")||purchase.getSku().equals("android.test.purchased")){
- mHelper.consumeAsync(purchase, mConsumeFinishedListener);
- }elseif (purchase.getSku().equals("double_income")) {
- //受管理的商品,开启双倍经验
- showMessage("支付成功","成功购买双倍经验");
- }
- }
- };
- // Called when consumption is complete
- IabHelper.OnConsumeFinishedListener mConsumeFinishedListener =newIabHelper.OnConsumeFinishedListener() {
- publicvoid onConsumeFinished(Purchasepurchase, IabResult result) {
- Log.d(TAG,"Consumption finished. Purchase: "+purchase +", result: " +result);
- // We know this is the "gas"sku because it's the only onewe consume,
- // so we don't check whichsku was consumed. If you havemore than one
- //sku, you probably shouldcheck...
- if (result.isSuccess()) {
- //successfully consumed, so we apply the effects of the item inour
- //game world's logic, which in our case means filling the gas tank abit
- if(purchase.getSku().equals("coins_100")||purchase.getSku().equals("android.test.purchased")){
- showMessage("支付成功","成功购买100猫币");
- }
- }
- else {
- complain("Error while consuming: " + result);
- }
- }
- };
- // Listener that's called when we finish querying the items weown
- IabHelper.QueryInventoryFinishedListener mGotInventoryListener =newIabHelper.QueryInventoryFinishedListener() {
- publicvoidonQueryInventoryFinished(IabResult result, Inventory inventory){
- Log.d(TAG,"Query inventory finished.");
- if (result.isFailure()) {
- complain("Failed to query inventory: " +result);
- return;
- }
- Log.d(TAG,"Query inventory was successful.");
- if(inventory.hasPurchase("double_income")) {
- //查询到有受管理的商品支付成功需要将道具给用户
- showMessage("成功Restore双倍金币", "查询到有双倍金币需要恢复");
- }elseif(inventory.hasPurchase("cions_100")){
- //查询到不受管理的商品支付成功需要将道具消耗掉
- showMessage("成功Restore100金币","查询到有100金币需要恢复");
- }
- }
- };
// Callback for when a purchase is finished
IabHelper.OnIabPurchaseFinishedListener mPurchaseFinishedListener =newIabHelper.OnIabPurchaseFinishedListener() {publicvoidonIabPurchaseFinished(IabResult result, Purchase purchase) {Log.d(TAG,"Purchase finished: " + result+", purchase: " +purchase);if (result.isFailure()) {// Oh noes!complain("Error purchasing: " + result);return;}Log.d(TAG,"Purchase successful.");if(purchase.getSku().equals("coins_100")||purchase.getSku().equals("android.test.purchased")){mHelper.consumeAsync(purchase, mConsumeFinishedListener);
}elseif (purchase.getSku().equals("double_income")) {
//受管理的商品,开启双倍经验
showMessage("支付成功","成功购买双倍经验");
}}};
// Called when consumption is complete
IabHelper.OnConsumeFinishedListener mConsumeFinishedListener =newIabHelper.OnConsumeFinishedListener() {publicvoid onConsumeFinished(Purchasepurchase, IabResult result) {Log.d(TAG,"Consumption finished. Purchase: "+purchase + ", result: " +result);// We know this is the "gas"sku because it's the only onewe consume,// so we don't check whichsku was consumed. If you havemore than one//sku, you probably shouldcheck...if (result.isSuccess()) {//successfully consumed, so we apply the effects of the item inour//game world's logic, which in our case means filling the gas tank abitif(purchase.getSku().equals("coins_100")||purchase.getSku().equals("android.test.purchased")){showMessage("支付成功","成功购买100猫币");}}else {complain("Error while consuming: " + result);}}};// Listener that's called when we finish querying the items weown
IabHelper.QueryInventoryFinishedListener mGotInventoryListener =newIabHelper.QueryInventoryFinishedListener() {publicvoidonQueryInventoryFinished(IabResult result, Inventory inventory){Log.d(TAG,"Query inventory finished.");if (result.isFailure()) {complain("Failed to query inventory: " +result);return;}Log.d(TAG,"Query inventory was successful.");if(inventory.hasPurchase("double_income")) {//查询到有受管理的商品支付成功需要将道具给用户
showMessage("成功Restore双倍金币", "查询到有双倍金币需要恢复");
}elseif(inventory.hasPurchase("cions_100")){
//查询到不受管理的商品支付成功需要将道具消耗掉
showMessage("成功Restore100金币","查询到有100金币需要恢复");
}}};
处理返回Activity后的数据:
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
System.out.println(TAG+ "onActivityResult(" + requestCode + "," + resultCode + "," + data);
if (requestCode == RC_REQUEST) {
if(resultCode != 0){//这里取得购买结果到google验证 这里的判断处理一定要有 要不然购买中途退出会出错
purchaseData = data.getStringExtra("INAPP_PURCHASE_DATA");
dataSignature = data.getStringExtra("INAPP_DATA_SIGNATURE");
System.out.println("############"+purchaseData.toString()+"@@@"+dataSignature.toString());
jniHelper.SendInfo(purchaseData.toString()+"*"+dataSignature.toString());//这里调用到c++的部分与上面的实现方法一样就不说了
}
}
if (!mHelper.handleActivityResult(requestCode, resultCode, data)) {
// not handled, so handle it ourselves (here's where you'd
// perform any handling of activity results not related to in-app
// billing...
super.onActivityResult(requestCode, resultCode, data);
}
else {
Log.d(TAG, "onActivityResult handled by IABUtil.");
}
}
@Override
protectedvoid onActivityResult(int requestCode,int resultCode, Intent data) {
// TODO Auto-generated methodstub
Log.d(TAG, "onActivityResult("+ requestCode + "," +resultCode +"," + data);// Pass on theactivity result to the helper for handlingif(!mHelper.handleActivityResult(requestCode, resultCode, data)){// not handled, so handle it ourselves(here's where you'd// perform any handling of activityresults not related to in-app// billing...super.onActivityResult(requestCode,resultCode, data);}else {Log.d(TAG,"onActivityResult handled by IABUtil.");}
}
退出游戏后销毁IabHelper:
- @Override
- protectedvoid onDestroy() {
- // TODO Auto-generated methodstub
- super.onDestroy();
- if (mHelper !=null) mHelper.dispose();
- mHelper =null;
- }
@Override
protectedvoid onDestroy() {
// TODO Auto-generated methodstub
super.onDestroy();
if (mHelper !=null) mHelper.dispose();mHelper =null;
}
注意:以上代码c++中用到jni java-c++中代码的互相调用需要加上头文件的包含
需要加上平台预编译
#include <jni.h>
#include <android/log.h>
#include "platform/android/jni/JniHelper.h"
coco2d-x游戏开发google play Google In-app-Billing 支付接入相关推荐
- C#开发微信门户及应用(32)--微信支付接入和API封装使用
C#开发微信门户及应用(32)--微信支付接入和API封装使用 在微信的应用上,微信支付是一个比较有用的部分,但也是比较复杂的技术要点,在微商大行其道的年代,自己的商店没有增加微信支付好像也说不过去, ...
- 微信小游戏开发实战教程12-广告的开通和接入
微信小游戏开发实战系列的第12篇, 本节内容主要包括:如何尽快的开通广告功能,以及如何将广告接入到微信小游戏中. 如果你没有任何的游戏开发经验,欢迎阅读我的"人人都能做游戏"系列教 ...
- 游戏党福音,Google play游戏明年登录Windows
整理:.左耳 出品:CSDN 如果你是一名游戏爱好者,你有没有想过有一天能在Windows系统上玩Google play的游戏.虽然这很难以置信,但是它确实发生了.近日,Google Play在202 ...
- Notes from Google Play | Google Play 持续助力您的应用和游戏
作者 / Sarah Karam, Google Play 全球应用合作伙伴关系总监 Google Play 应用合作伙伴关系负责人 -- Sarah Karam,曾与多家公司的开发者会面,倾听他们关 ...
- unity 谷歌广告介入_Unity为开发人员发布Google广告
unity 谷歌广告介入 Everyone loves something new. New ad formats, new advertisers, and new content means mo ...
- 【小5聊】发布开发好的google浏览器插件到谷歌应用商店
将自己开发好的google浏览器插件发布到谷歌应用商店 温馨提示:前提你的网络要能够上国外的网站哦,俗称翻墙 1. 注册为 Chrome 网上应用店开发者 开发者控制台,点击跳转 一步一步填写,就是注 ...
- 详述Google针对Android平板App发布的十大开发准则
2019独角兽企业重金招聘Python工程师标准>>> 在Nexus 7出来之前,Android平板市场的低迷一直让开发者对设计好Android平板上的App兴趣缺缺.为了给自己的平 ...
- (转载)如何学好iphone游戏开发
转自:http://www.cnblogs.com/zilongshanren/archive/2011/09/19/2181558.html 自从发布<如何学习iphone游戏开发>到 ...
- 14 岁发现 Bug 兼职游戏开发、拒绝过乔布斯,Dropbox 创始人成为科技创业者的偶像...
作者 | 年素清 责编 | 王晓曼 出品 | 程序人生 (ID:coder _life) Drew Houston(安德鲁·豪斯顿)是著名的互联网企业家和云存储行业Dropbox公司的创始人和首 ...
最新文章
- 给网站添加icon图标
- DivCo: Diverse Conditional Image Synthesis via Contrastive Generative Adversarial Network
- Spring整合Struts的几种最常见方式
- Facebook批量优化360照片
- SAP UI5是如何从浏览器读取语言设置并按照优先级排序的
- 整合ssh model $$_javassist_13 cannot be cast to javassist.util.proxy.Proxy
- VC/MFC中的CComboBox控件使用详解
- c#开发Mongo笔记第五篇
- 从properties配置文件中获取到的中文乱码
- 下载win7原版ios系统文件
- 老旧小区智慧用电改造方案
- LQR、LQR-MPC、GP-MPC控制倒立摆
- 游怎么用模拟器多开挂机不封号
- 计算机和小学科课题,《小学信息技术课堂有效教学的探索》课题研究方案
- mysql数据库初始化 error Found option without preceding group in config file
- obs噪音抑制调多少合适_(3)阿里国际站OBS申请设置使用教程,OBS音频没有声音怎么办?国际站直播回放如何下载?...
- AutoJs学习-录制手指动作
- 基于流式输入输出 使用Java借助GSON库 实现对大型asc文件的读入解析 并输出为JSON文件
- The package javax.swing is not accessible(java GUI 编程时引用swing包和awt包时会报错怎么办)
- java基础-head first java
热门文章
- 三伏天如何祛除“月子病”?
- Webrtc 多人视频会议系统 服务器 Licode 介绍
- 基于微信小程序的电影院购票平台
- maven打包--同时将仓库依赖和本地依赖的jar包也打进去
- iOS客户端React-Native增量更新实践
- 计算机程序设计艺术读后感,计算机程序设计艺术(第1卷)读后感1000字
- c语言编程曹冲称象,《曹冲称象》教学设计
- 嵩天老师-Python语言程序设计-Python123配套练习测验题目汇总整理
- Windows Azure案例:迈阿密市政府使用“云”平台改善服务方案,降低运营成本
- Android开发技术网站推荐