首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 移动开发 > Android >

Android支付接入(7):Google In-app-Billing

2013-10-16 
Android支付接入(七):Google In-app-Billing注意:类型根据VPN而定,我用的是L2TP/IPSecPSK,选择此类型时,编

Android支付接入(七):Google In-app-Billing
Android支付接入(7):Google In-app-BillingAndroid支付接入(7):Google In-app-BillingAndroid支付接入(7):Google In-app-BillingAndroid支付接入(7):Google In-app-BillingAndroid支付接入(7):Google In-app-Billing
Android支付接入(7):Google In-app-BillingAndroid支付接入(7):Google In-app-BillingAndroid支付接入(7):Google In-app-BillingAndroid支付接入(7):Google In-app-BillingAndroid支付接入(7):Google In-app-BillingAndroid支付接入(7):Google In-app-BillingAndroid支付接入(7):Google In-app-Billing
注意:类型根据VPN而定,我用的是L2TP/IPSecPSK,选择此类型时,编辑只需填写名称,服务器地址和IPSec预共享密钥即可,然后连接的时候填写帐号和密码。当打开Google商店能看到付费软件表名VPN已成功连接,如果显示VPN已连接但还看不到付费软件时,进入应用程序管理器分别清除GooglePlay服务和Google Play商店数据之后再打开Google商店即可。
文档下载链接为:  http://pan.baidu.com/share/link?shareid=1387554851&uk=473193131源码下载链接为:http://pan.baidu.com/share/link?shareid=1579953623&uk=473193131   注:源码导入工程是不可用的,需将包名、版本号、版本code、签名改为你上传至Google控制台测试应用的包名、版本号、版本code、签名,且将MainActivity.java中的Stringbase64EncodedPublicKey ="";填写上你应用程序的签名。PS:签名即Eclipse->AndroidTools->Export Signed Application Package...   网盘分享中的DemoForGoogleBilling.apk文件是可支付的,但支付会将钱打到我们公司账户上,因为我用的是上线app的key。
一:接入流程:   1.申请Google开发者帐号,开发人员控制台左侧选择“设置”填写测试人员帐号。Android支付接入(7):Google In-app-Billing

   2.添加新应用,此处有个“上传APK”,此处上传的apk上传到Bate版或者ALPHA版,但包名、版本code、版本name、签名需跟最终上线的产品保持一致。此处上传测试版本的目的是当你支付接入完毕后测试时用。Android支付接入(7):Google In-app-Billing
    3.集成Google Billing。     (1).Purchasing Items,购买商品时的通信过程Android支付接入(7):Google In-app-Billing
Android支付接入(7):Google In-app-Billing
      (2).Consuming In-app Products,消耗产品时的通信过程Android支付接入(7):Google In-app-Billing

    4.测试支付。
      (1).测试支付官方文档链接http://developer.android.com/google/play/billing/billing_testing.html
      (2).Testing with staticresponses,静态测试,即当支付状态为一下四种情况时游戏逻辑是否正确。官方给出的4种如下:There are four reserved product IDs for testing static In-appBilling responses:android.test.purchasedWhen you make an In-app Billing request with this product ID,Google Play responds as though you successfully purchased an item.The response includes a JSON string, which contains fake purchaseinformation (for example, a fake order ID). In some cases, the JSONstring is signed and the response includes the signature so you cantest your signature verification implementation using theseresponses.android.test.canceledWhen you make an In-app Billing request with this product IDGoogle Play responds as though the purchase was canceled. This canoccur when an error is encountered in the order process, such as aninvalid credit card, or when you cancel a user's order before it ischarged.android.test.refundedWhen you make an In-app Billing request with this product ID,Google Play responds as though the purchase was refunded. Refundscannot be initiated through Google Play's in-app billing service.Refunds must be initiated by you (the merchant). After you processa refund request through your Google Wallet merchant account, arefund message is sent to your application by Google Play. Thisoccurs only when Google Play gets notification from Google Walletthat a refund has been made. For more information about refunds,see Handling IN_APP_NOTIFY messages and In-app BillingPricing.android.test.item_unavailableWhen you make an In-app Billing request with this product ID,Google Play responds as though the item being purchased was notlisted in your application's product list.      例:当配置为android.test.purchased时:

Android支付接入(7):Google In-app-BillingAndroid支付接入(7):Google In-app-BillingAndroid支付接入(7):Google In-app-Billing
      (3).当游戏逻辑测试通过后,进行支付测试。测试时手机设备上绑定的Google帐号必须是在开发者控制台中配置的测试帐号,绑定非大陆的信用卡,支付后会在开发者控制台看到支付的订单,由于是测试订单,可以将测试产生的费用返还给绑定的信用卡。     测试效果图如下(由于本人没有非大陆的信用卡,所以只能看到这个界面,上线项目“蘑菇帮”测试ok)Android支付接入(7):Google In-app-Billing
Android支付接入(7):Google In-app-Billing支付接入过程中涉及到的接口及名词:
一:受管理商品和不受管理商品   1.受管理商品即不可重复购买的,例如:解锁关卡,激活游戏等。   2.不受管理商品即可重复购买的,例如:购买金币,购买药水,等消耗品。   3.订阅商品,由于项目中没有涉及到,如有需要的可以翻阅一下Google Billing文档。Google in-app BillingV3将所有商品默认为受管理的,如果有不受管理商品则需要调用consumeAsync去消耗调,(或者你可以通俗的理解为,当你成功购买一个道具,Google后台会将此道具加上标记,当你调用consumeAsync将订单消耗掉时,该订单标记被取消)。二:三个回调

  1.IabHelper.OnIabPurchaseFinishedListener 支付完成的回调,如果是受管理的商品在此回调中直接可以将道具给用户

 

  2.IabHelper.OnConsumeFinishedListene消耗完成的回调,当不受管理的商品被成功消耗进入此回调,此时将不受管理的商品给用户

 

    3.IabHelper.QueryInventoryFinishedListener 查询完成的回调,RestoreOrder的时候用,当有订单成功付款但由于种种原因(突然断网、断电等)没收到Google支付成功的回调时,在这里可以查询到此订单,此时需要对订单进行处理(给用户道具等)。

四:测试用的app一定要跟上传到Google的测试版的包名、版本code、name、签名一致,否则无法进行支付测试。

    1.当签名不一致或者版本code、版本name不一致时错误界面如下:

Android支付接入(7):Google In-app-Billing

Android支付接入(7):Google In-app-Billing

      2.当包名不一致时错误界面如下:

Android支付接入(7):Google In-app-Billing

Android支付接入(7):Google In-app-Billing

接下来跟大家一起看一下代码具体实现:
1.下载in-app-billing-v03,下载地址:http://pan.baidu.com/share/link?shareid=1387554851&uk=473193131将下载后的压缩包解压:Android支付接入(7):Google In-app-Billing

将src目录下两个包及包中的java文件引入工程,例如:
Android支付接入(7):Google In-app-Billing
2.添加权限:
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 object   IabHelper mHelper; // Debugtag, for logging   static final String TAG = "TrivialDrive"; //Current amount of gas in tank, in units   int 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;   @Overrideprotected voidonCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);Stringbase64EncodedPublicKey = "";//此处填写自己的appid       mHelper =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() { @Overridepublic void onClick(Viewv) {// TODO Auto-generatedmethod stubiapHandler.sendEmptyMessage(1);}});      //购买100猫币(不受管理商品)      findViewById(R.id.button2).setOnClickListener(newView.OnClickListener() { @Overridepublic void onClick(Viewv) {// TODO Auto-generatedmethod stubiapHandler.sendEmptyMessage(2);}});       //RestoreOrder      findViewById(R.id.button3).setOnClickListener(newView.OnClickListener() { @Overridepublic void onClick(Viewv) {// TODO Auto-generatedmethod stubif (iap_is_ok) {mHelper.queryInventoryAsync(mGotInventoryListener);}else {showMessage("提示", "GooglePlay初始化失败,当前无法进行支付,请确定您所在地区支持Google Play支付或重启游戏再试!");} }});       //获取价格      findViewById(R.id.button4).setOnClickListener(newView.OnClickListener() { @Overridepublic void onClick(Viewv) {// TODO Auto-generatedmethod stubsku_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(){ @Overridepublic void run() {// TODO Auto-generatedmethod stubgetPrice();}}).start();}});       //测试订单      findViewById(R.id.button5).setOnClickListener(newView.OnClickListener() { @Overridepublic void onClick(Viewv) {// TODO Auto-generatedmethod stubiapHandler.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 blocke.printStackTrace();}               }}} catch (RemoteExceptione) {// TODO Auto-generatedcatch blocke.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 finished   IabHelper.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 complete   IabHelper.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 bit          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 finishquerying the items we own   IabHelper.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金币需要恢复" );}       }   };   @Overrideprotected voidonActivityResult(int requestCode, int resultCode, Intent data){// TODO Auto-generatedmethod stubLog.d(TAG,"onActivityResult(" + requestCode + "," + resultCode + "," +data);       // Pass onthe activity result to the helper for handling       if(!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.");       }}   @Overrideprotected void onDestroy(){// TODO Auto-generatedmethod stubsuper.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接入过程,接下来会跟大家一起走一遍亚马逊支付,如有疑问请留言。


  

2楼anquangan198917分钟前
博客是从新浪博客中搬家过来的,图片显示可能有问题,图片我重新上传了一次,我这是可以看到图片的,可以尝试刷新一下,如果还不行的话,请留言,我再重新上传一遍。
1楼lfdfhl昨天 17:36
图片看不见 楼主

热点排行