android google play接入一样的操作借用了网上别人博客的部分 改正的一些错误,主要介绍 cocos2d-x google play 接入不一样的部分
如果没有GooglePlay此处附上安装Google Play的一键安装器的链接(需要Root权限):http://www.muzhiwan.com/com.muzhiwan.gsfinstaller-86095.html
- mHelper.launchPurchaseFlow(MainActivity.this,“android.test.purchased”,RC_REQUEST,mPurchaseFinishedListener);
mHelper.launchPurchaseFlow(MainActivity.this,“android.test.purchased”,RC_REQUEST,mPurchaseFinishedListener);
四:测试用的app一定要跟上传到Google的测试版的包名、版本code、name、签名一致,否则无法进行支付测试。
接下来跟大家一起看一下代码具体实现:
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控制台添加新应用程序后的appid
mHelper =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.");
}
});
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);
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 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金币需要恢复");
}
}
};
@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 handling
if(!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.");
}
}
- @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"