Android支付接入(7):Google In-app-Billing
今天跟大家一起看下Google的in-app Billing V3支付。
注意:类型根据VPN而定,我用的是L2TP/IPSecPSK,选择此类型时,编辑只需填写名称,服务器地址和IPSec预共享密钥即可,然后连接的时候填写帐号和密码。当打开Google商店能看到付费软件表名VPN已成功连接,如果显示VPN已连接但还看不到付费软件时,进入应用程序管理器分别清除GooglePlay服务和Google Play商店数据之后再打开Google商店即可。
3.集成Google Billing。
(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);
一:受管理商品和不受管理商品
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-permissionandroid:name="com.android.vending.BILLING"/>
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.");}});
调用支付接口:
if(iap_is_ok){
mHelper.launchPurchaseFlow(MainActivity.this,skus[1],RC_REQUEST, mPurchaseFinishedListener);
}else {
showMessage("提示", "GooglePlay初始化失败,当前无法进行支付,请确定您所在地区支持Google Play支付或重启游戏再试!");
}
调用查询接口:
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();
}
三个回调:
// 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
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;
}
最后附上MainActivity.java完整文件,源码下载地址:http://pan.baidu.com/share/link?shareid=1579953623&uk=473193131:
packagecn.catcap.together;importjava.util.ArrayList;
importorg.json.JSONException;
importcom.android.vending.billing.IInAppBillingService;
importcom.example.android.trivialdrivesample.util.IabHelper;
importcom.example.android.trivialdrivesample.util.IabResult;
importcom.example.android.trivialdrivesample.util.Inventory;
importcom.example.android.trivialdrivesample.util.Purchase;
importcom.example.android.trivialdrivesample.util.SkuDetails;
importandroid.os.Bundle;
importandroid.os.Handler;
importandroid.os.RemoteException;
importandroid.app.Activity;
importandroid.app.AlertDialog;
importandroid.content.Intent;
importandroid.util.Log;
importandroid.view.View;
importandroid.widget.TextView;public class MainActivityextends Activity {// The helper objectIabHelper mHelper;// Debugtag, for loggingstatic final String TAG = "TrivialDrive";//Current amount of gas in tank, in unitsint mTank;//(arbitrary) request code for the purchase flow请求码static final int RC_REQUEST = 10001;private boolean iap_is_ok = false;//double_income为受管理商品,coins_100为不受管理商品private String[] skus ={"android.test.purchased","double_income","coins_100"};privateArrayList<String> sku_list;privateArrayList<String> price_list;private IInAppBillingService billingservice;private TextView tv;@Override
protected voidonCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Stringbase64EncodedPublicKey = "";//此处填写自己的appidmHelper =new IabHelper(this, base64EncodedPublicKey);// enabledebug logging (for a production application, you should set this tofalse).mHelper.enableDebugLogging(false);// Start setup. This isasynchronous and the specified listener// will becalled once setup completes.Log.d(TAG,"Starting setup.");mHelper.startSetup(new IabHelper.OnIabSetupFinishedListener() {public voidonIabSetupFinished(IabResult result) {Log.d(TAG, "Setup finished.");if (!result.isSuccess()) {// Ohnoes, there was a problem.complain("Problem setting up in-app billing: " + result);return;}iap_is_ok = true;// Hooray, IAB is fully set up. Now, let's getan inventory of stuff we own.Log.d(TAG, "Setup successful. Queryinginventory.");}});//购买双倍金币(受管理商品)findViewById(R.id.button1).setOnClickListener(newView.OnClickListener() {@Override
public void onClick(Viewv) {
// TODO Auto-generatedmethod stub
iapHandler.sendEmptyMessage(1);
}
});//购买100猫币(不受管理商品)findViewById(R.id.button2).setOnClickListener(newView.OnClickListener() {@Override
public void onClick(Viewv) {
// TODO Auto-generatedmethod stub
iapHandler.sendEmptyMessage(2);
}
});//RestoreOrderfindViewById(R.id.button3).setOnClickListener(newView.OnClickListener() {@Override
public void onClick(Viewv) {
// TODO Auto-generatedmethod stub
if (iap_is_ok) {
mHelper.queryInventoryAsync(mGotInventoryListener);
}else {
showMessage("提示", "GooglePlay初始化失败,当前无法进行支付,请确定您所在地区支持Google Play支付或重启游戏再试!");
}}
});//获取价格findViewById(R.id.button4).setOnClickListener(newView.OnClickListener() {@Override
public void onClick(Viewv) {
// TODO Auto-generatedmethod stub
sku_list = newArrayList<String>();
price_list = newArrayList<String>();
//添加默认值
sku_list.add("double_income");
price_list.add("HK$40");
sku_list.add("coins_100");
price_list.add("HK$8");
new Thread(new Runnable(){@Override
public void run() {
// TODO Auto-generatedmethod stub
getPrice();
}
}).start();
}
});//测试订单findViewById(R.id.button5).setOnClickListener(newView.OnClickListener() {@Override
public void onClick(Viewv) {
// TODO Auto-generatedmethod stub
iapHandler.sendEmptyMessage(3);
}
});//显示价格tv =(TextView) findViewById(R.id.text);
}
//获取价格
private voidgetPrice(){
ArrayList<String> skus = newArrayList<String>();
skus.add("double_income");
skus.add("coins_100");
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-generatedcatch block
e.printStackTrace();
}}
}
} catch (RemoteExceptione) {
// TODO Auto-generatedcatch block
e.printStackTrace();
}
}Handler iapHandler = newHandler(){
public voidhandleMessage(android.os.Message msg) {
switch(msg.what){
case 0:
tv.setText(price_list.get(0)+"\n"+price_list.get(1));
break;
case 1:
if (iap_is_ok) {
mHelper.launchPurchaseFlow(MainActivity.this, skus[1], RC_REQUEST, mPurchaseFinishedListener);
}else {
showMessage("提示", "GooglePlay初始化失败,当前无法进行支付,请确定您所在地区支持Google Play支付或重启游戏再试!");
}
break;
case 2:
if (iap_is_ok) {
mHelper.launchPurchaseFlow(MainActivity.this, skus[2], RC_REQUEST,mPurchaseFinishedListener);
}else {
showMessage("提示", "GooglePlay初始化失败,当前无法进行支付,请确定您所在地区支持Google Play支付或重启游戏再试!");
}
break;
case 3:
if (iap_is_ok) {
mHelper.launchPurchaseFlow(MainActivity.this, skus[0], RC_REQUEST,mPurchaseFinishedListener);
}else {
showMessage("提示", "GooglePlay初始化失败,当前无法进行支付,请确定您所在地区支持Google Play支付或重启游戏再试!");
}break;
default:
break;
}
};
};// Callback for when apurchase is finishedIabHelper.OnIabPurchaseFinishedListenermPurchaseFinishedListener = newIabHelper.OnIabPurchaseFinishedListener() {publicvoid onIabPurchaseFinished(IabResult result, Purchase purchase){Log.d(TAG, "Purchasefinished: " + result + ", purchase: " + purchase);if (result.isFailure()) {// Oh noes!complain("Error purchasing: " + result);return;}Log.d(TAG, "Purchasesuccessful.");if(purchase.getSku().equals("coins_100")||purchase.getSku().equals("android.test.purchased")){mHelper.consumeAsync(purchase, mConsumeFinishedListener);
}else if(purchase.getSku().equals("double_income")) {
//受管理的商品,开启双倍经验
showMessage("支付成功","成功购买双倍经验");
}}};// Called when consumption is completeIabHelper.OnConsumeFinishedListenermConsumeFinishedListener = newIabHelper.OnConsumeFinishedListener() {publicvoid onConsumeFinished(Purchase purchase, IabResult result) {Log.d(TAG, "Consumptionfinished. Purchase: " + purchase + ", result: " + result);// We know this is the "gas"sku because it's the only one we consume,// so we don't check whichsku was consumed. If you have more than one// sku, you probably shouldcheck...if (result.isSuccess()) {// successfully consumed, so we apply theeffects of the item in our// game world's logic, which in our case meansfilling the gas tank a bitif(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 finishquerying the items we ownIabHelper.QueryInventoryFinishedListenermGotInventoryListener = newIabHelper.QueryInventoryFinishedListener() {publicvoid onQueryInventoryFinished(IabResult result, Inventoryinventory) {Log.d(TAG, "Query inventoryfinished.");if (result.isFailure()) {complain("Failed to query inventory: " +result);return;}Log.d(TAG, "Query inventorywas successful.");if(inventory.hasPurchase("double_income")) {//查询到有受管理的商品支付成功需要将道具给用户
showMessage("成功Restore双倍金币", "查询到有双倍金币需要恢复");
}elseif(inventory.hasPurchase("cions_100")){
//查询到不受管理的商品支付成功需要将道具消耗掉
showMessage("成功Restore100金币","查询到有100金币需要恢复" );
}}};@Override
protected voidonActivityResult(int requestCode, int resultCode, Intent data){
// TODO Auto-generatedmethod stub
Log.d(TAG,"onActivityResult(" + requestCode + "," + resultCode + "," +data);// Pass onthe activity result to the helper for handlingif(!mHelper.handleActivityResult(requestCode, resultCode, data)){// not handled, so handle itourselves (here's where you'd// perform any handling ofactivity results not related to in-app// billing...super.onActivityResult(requestCode, resultCode, data);}else {Log.d(TAG, "onActivityResulthandled by IABUtil.");}
}@Override
protected void onDestroy(){
// TODO Auto-generatedmethod stub
super.onDestroy();
if (mHelper != null)mHelper.dispose();mHelper =null;
}
void complain(Stringmessage) {Log.e(TAG,"**** TrivialDrive Error: " + message);alert("Error: " + message);}
void alert(String message){AlertDialog.Builder bld = new AlertDialog.Builder(this);bld.setMessage(message);bld.setNeutralButton("OK", null);Log.d(TAG,"Showing alert dialog: " + message);bld.create().show();}
private voidshowMessage(String title,String message){
newAlertDialog.Builder(MainActivity.this).setTitle(title).setMessage(message).setPositiveButton("确定",null).show();
}
}
以上就是完整的Google in-appBilling接入过程,接下来会跟大家一起走一遍亚马逊支付,如有疑问请留言。
Android支付接入(7):Google In-app-Billing相关推荐
- Android支付接入之Google In-app-Billing
原文链接:http://www.mobile-open.com/2016/966337.html 因为公司需要接入Google的应用内支付(即Google的in-app Billing V3),接入过 ...
- Android支付接入:Google In-app-Billing
http://blog.csdn.net/michael_liu_89/article/details/12704461 今天跟大家一起看下Google的in-app Billing V3支付. ...
- Google in app billing 应用内支付
一 简介 Google in app billing 是google play 商店的应用内支付,他是一种应用内的虚拟的道具支付服务,支持应用内支付(inapp)和订阅(subs)两种模式; 在中国, ...
- Android支付接入(七):Googlenbsp;In-app-Billing
http://qing.blog.sina.com.cn/tj/634ac835330048cu.html 原文地址:Android支付接入(七):Google In-app-Billing作者:屌丝 ...
- Android支付接入(七):Google In-app-Billing
转载 http://blog.csdn.net/michael_liu_89/article/details/12704461 今天跟大家一起看下Google的in-app Billing V3支付. ...
- Android支付接入(七):Google In-app-Billing
今天跟大家一起看下Google的in-app Billing V3支付. 如果没有GooglePlay此处附上安装Google Play的一键安装器的链接(需要Root权限):http://www ...
- Android支付接入
转载自:http://blog.sina.com.cn/s/blog_9498c8b60101d7x5.html 今天跟大家一起看下Google的in-app Billing V3支付. 如果没有 ...
- Android支付接入(五):机锋网
前边已经陆续跟大家走了一遍运营商和支付宝付费接入,今天跟大家一起看看机锋网的支付接入.事实上付费接入本身并没有太多须要注意的地方,做的多了以后你会发现套路都是大同小异的.而须要注意的地方在于怎么跟游戏 ...
- GooglePlay内购接入错误Google Play In-app Billing API version is less than 3
接入谷歌内购时,代码部分接入好了,于是打算开始测试,但是打开应用后初始化时一直提示错误:Google Play In-app Billing API version is less than 3.看名 ...
最新文章
- html动态报警图片,报警记录.html
- Text模式和PDU模式短信的区别
- 《windows程序设计》第二章学习心得
- [转]使用DBX分析AIX 下的 CoreDump
- python 中self
- PHP技术的优缺点(转载)
- Windows server 2008设置远程桌面
- 配置visual studio code进行asp.net core rc2的开发(转载jeffreywu)
- 大数据数学基础 python描述下载_正版 大数据数学基础(Python语言描述)Python 大数据 数学 高职-计算机-大数据技术...
- (day 25 - 广度优先搜索 )剑指 Offer 32 - II. 从上到下打印二叉树 II
- Java中的一些术语的解释
- 制作pdf文档书签,自动生成or根据目录生成
- json文件下载--防止chrome直接打开方案
- win7 企业版MAK神key win7企业版激活码
- CISSP考试要涨价了,5月1日起考试费涨为749美元
- Binomial Showdown
- 儿童卡通城堡banner动画
- 小米手机使用FlutterDownloader下载安卓apk文件不能正常安装
- 打印机可以打印不能扫描怎么弄_打印机无法扫描怎么解决 打印机无法扫描相关介绍【解决方法】...
- Linux基本命令(Redhat,CentOS)