Android支付接入:Google In-app-Billing

http://blog.csdn.net/michael_liu_89/article/details/12704461

今天跟大家一起看下Google的in-app Billing V3支付。

   如果沒有GooglePlay此處附上安裝Google Play的一鍵安裝器的鏈接(需要Root權限):http://www.muzhiwan.com/com.muzhiwan.gsfinstaller-86095.html
   之前用過Google BillingV2,感覺不太爽。V2版支付走的是異步通知,不能即時得到支付結果,支付、查詢接口太過複雜,還有就是沒找到RestoreOrder接口,因此選擇使用V3版,網上大部分都是介紹GoogleBilling的付費機制原理,具體針對某個功能點的很模糊,所以如果大家想了解GoogleBilling付費機制的這篇博文大可不看,網上轉載多的是,我寫這篇博文的目的是想讓大家快速的將Google支付集成到自己項目中。
   集成Google in-appBilling的前提是你已經正確連接上VPN(大陸用戶),基本上每個公司都會有VPN的,這個找項目組長去要。
  也正式由於天朝的封鎖使得在大陸接Google的支付加大了難度。所以要想接in-appBilling首先要有一個穩定的vpn,PS:非大陸的就行,最好是美、日的。
VPN設置:Android支付接入(七):Google <wbr>In-app-BillingAndroid支付接入(七):Google <wbr>In-app-BillingAndroid支付接入(七):Google <wbr>In-app-BillingAndroid支付接入(七):Google <wbr>In-app-BillingAndroid支付接入(七):Google <wbr>In-app-BillingAndroid支付接入(七):Google <wbr>In-app-Billing

注意:類型根據VPN而定,我用的是L2TP/IPSecPSK,選擇此類型時,編輯只需填寫名稱,服務器地址和IPSec預共享密鑰即可,然後連接的時候填寫帳號和密碼。當打開Google商店能看到付費軟件表名VPN已成功連接,如果顯示VPN已連接但還看不到付費軟件時,進入應用程序管理器分別清除GooglePlay服務和Google Play商店數據之後再打開Google商店即可。

   注:源碼導入工程是不可用的,需將包名、版本號、版本code、簽名改爲你上傳至Google控制檯測試應用的包名、版本號、版本code、簽名,且將MainActivity.java中的Stringbase64EncodedPublicKey ="";填寫上你應用程序的簽名。PS:簽名即Eclipse->AndroidTools->Export Signed Application Package...
   網盤分享中的DemoForGoogleBilling.apk文件是可支付的,但支付會將錢打到我們公司賬戶上,因爲我用的是上線app的key。

一:接入流程:
   1.申請Google開發者帳號,開發人員控制檯左側選擇“設置”填寫測試人員帳號。


   2.添加新應用,此處有個“上傳APK”,此處上傳的apk上傳到Bate版或者ALPHA版,但包名、版本code、版本name、簽名需跟最終上線的產品保持一致。此處上傳測試版本的目的是當你支付接入完畢後測試時用。

    3.集成Google Billing。
     (1).Purchasing Items,購買商品時的通信過程

Android支付接入(七):Google <wbr>In-app-Billing
      (2).Consuming In-app Products,消耗產品時的通信過程


    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.purchased
When 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.canceled
When 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.refunded
When 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_unavailable
When 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時
[java] view plaincopy
  1. mHelper.launchPurchaseFlow(MainActivity.this,“android.test.purchased”,RC_REQUEST,mPurchaseFinishedListener);  

Android支付接入(七):Google <wbr>In-app-BillingAndroid支付接入(七):Google <wbr>In-app-Billing
      (3).當遊戲邏輯測試通過後,進行支付測試。測試時手機設備上綁定的Google帳號必須是在開發者控制檯中配置的測試帳號,綁定非大陸的信用卡,支付後會在開發者控制檯看到支付的訂單,由於是測試訂單,可以將測試產生的費用返還給綁定的信用卡。
     測試效果圖如下(由於本人沒有非大陸的信用卡,所以只能看到這個界面,上線項目“蘑菇幫”測試ok)
Android支付接入(七):Google <wbr>In-app-Billing

支付接入過程中涉及到的接口及名詞:

一:受管理商品和不受管理商品
   1.受管理商品即不可重複購買的,例如:解鎖關卡,激活遊戲等。
   2.不受管理商品即可重複購買的,例如:購買金幣,購買藥水,等消耗品。
   3.訂閱商品,由於項目中沒有涉及到,如有需要的可以翻閱一下Google Billing文檔。
Google in-app BillingV3將所有商品默認爲受管理的,如果有不受管理商品則需要調用consumeAsync去消耗調,(或者你可以通俗的理解爲,當你成功購買一個道具,Google後臺會將此道具加上標記,當你調用consumeAsync將訂單消耗掉時,該訂單標記被取消)。
二:三個回調

  1.IabHelper.OnIabPurchaseFinishedListener 支付完成的回調,如果是受管理的商品在此回調中直接可以將道具給用戶

 

  2.IabHelper.OnConsumeFinishedListener 消耗完成的回調,當不受管理的商品被成功消耗進入此回調,此時將不受管理的商品給用戶

 

    3.IabHelper.QueryInventoryFinishedListener 查詢完成的回調,RestoreOrder的時候用,當有訂單成功付款但由於種種原因(突然斷網、斷電等)沒收到Google支付成功的回調時,在這裏可以查詢到此訂單,此時需要對訂單進行處理(給用戶道具等)。

四:測試用的app一定要跟上傳到Google的測試版的包名、版本code、name、簽名一致,否則無法進行支付測試。

    1.當簽名不一致或者版本code、版本name不一致時錯誤界面如下:

Android支付接入(七):Google <wbr>In-app-Billing

      2.當包名不一致時錯誤界面如下:

Android支付接入(七):Google <wbr>In-app-Billing

接下來跟大家一起看一下代碼具體實現:
1.下載in-app-billing-v03,下載地址:http://pan.baidu.com/share/link?shareid=1387554851&uk=473193131將下載後的壓縮包解壓:

將src目錄下兩個包及包中的java文件引入工程,例如:

2.添加權限:
[html] view plaincopy
  1. <uses-permissionandroid:nameuses-permissionandroid:name="com.android.vending.BILLING"/>  

3.添加支付代碼:
    初始化IapHelper:

[java] view plaincopy
  1. String base64EncodedPublicKey ="";此處填寫Google控制檯添加新應用程序後的appid  
  2.       mHelper =new IabHelper(this, base64EncodedPublicKey);  
  3.        // enable debuglogging (for a production application, you should set this tofalse).  
  4.       mHelper.enableDebugLogging(false);  
  5.     // Start setup. This is asynchronous andthe specified listener  
  6.        // will be called oncesetup completes.  
  7.        Log.d(TAG,"Starting setup.");  
  8.       mHelper.startSetup(new IabHelper.OnIabSetupFinishedListener(){  
  9.           publicvoid onIabSetupFinished(IabResult result){  
  10.               Log.d(TAG,"Setupfinished.");  
  11.              if (!result.isSuccess()) {  
  12.                  // Ohnoes, there was a problem.  
  13.                  complain("Problemsetting up in-app billing: " + result);  
  14.                 return;  
  15.               }  
  16.              iap_is_ok = true;  
  17.               //Hooray, IAB is fully set up. Now, let's get an inventory of stuffwe own.  
  18.              Log.d(TAG, "Setup successful. Queryinginventory.");  
  19.            }  
  20.        });  

  調用支付接口:

[java] view plaincopy
  1. if(iap_is_ok){  
  2. mHelper.launchPurchaseFlow(MainActivity.this,skus[1],RC_REQUEST, mPurchaseFinishedListener);  
  3. }else {  
  4. showMessage("提示""GooglePlay初始化失敗,當前無法進行支付,請確定您所在地區支持Google Play支付或重啓遊戲再試!");  
  5. }  

  調用查詢接口:

 

[java] view plaincopy
  1. mHelper.queryInventoryAsync(mGotInventoryListener);  

  調用獲取道具價格接口:(因Google市場是根據不同國家顯示不同貨幣價格,所以顯示到遊戲道具列表中的價格不是定值,而是動態獲取的)

 

[java] view plaincopy
  1. billingservice =mHelper.getService();  
  2. Bundle querySkus = newBundle();  
  3.    querySkus.putStringArrayList("ITEM_ID_LIST", skus);  
  4. try {  
  5. Bundle skuDetails = billingservice.getSkuDetails(3,MainActivity.this.getPackageName(),"inapp", querySkus);  
  6. ArrayList<String> responseList =skuDetails.getStringArrayList("DETAILS_LIST");  
  7. if (null!=responseList) {  
  8. for (String thisResponse :responseList) {  
  9.           try {  
  10. SkuDetails d = newSkuDetails(thisResponse);  
  11.    
  12. for (int i = 0; i <sku_list.size(); i++) {  
  13. if(sku_list.get(i).equals(d.getSku())) {  
  14. price_list.set(i, d.getPrice());  
  15. }  
  16. }  
  17. iapHandler.sendEmptyMessage(0);  
  18.    
  19. }catch (JSONException e) {  
  20. // TODO Auto-generated catchblock  
  21. e.printStackTrace();  
  22. }  
  23.             
  24.        }  
  25. }  
  26. }catch (RemoteException e) {  
  27. // TODO Auto-generated catchblock  
  28. e.printStackTrace();  
  29. }  

  三個回調:

 

[java] view plaincopy
  1. // Callback for when a purchase is finished  
  2. IabHelper.OnIabPurchaseFinishedListener mPurchaseFinishedListener =newIabHelper.OnIabPurchaseFinishedListener() {  
  3.       publicvoidonIabPurchaseFinished(IabResult result, Purchase purchase) {  
  4.            Log.d(TAG,"Purchase finished: " + result+", purchase: " +purchase);  
  5.           if (result.isFailure()) {  
  6.              // Oh noes!  
  7.               complain("Error purchasing: " + result);  
  8.              return;  
  9.            }  
  10.   
  11.            Log.d(TAG,"Purchase successful.");  
  12.           if(purchase.getSku().equals("coins_100")||purchase.getSku().equals("android.test.purchased")){  
  13.           mHelper.consumeAsync(purchase, mConsumeFinishedListener);  
  14. }elseif (purchase.getSku().equals("double_income")) {  
  15. //受管理的商品,開啓雙倍經驗  
  16. showMessage("支付成功","成功購買雙倍經驗");  
  17. }  
  18.        }  
  19.     };  
  20. // Called when consumption is complete  
  21. IabHelper.OnConsumeFinishedListener mConsumeFinishedListener =newIabHelper.OnConsumeFinishedListener() {  
  22.       publicvoid onConsumeFinished(Purchasepurchase, IabResult result) {  
  23.           Log.d(TAG,"Consumption finished. Purchase: "+purchase + ", result: " +result);  
  24.   
  25.           // We know this is the "gas"sku because it's the only onewe consume,  
  26.           // so we don't check whichsku was consumed. If you havemore than one  
  27.           //sku, you probably shouldcheck...  
  28.           if (result.isSuccess()) {  
  29.               //successfully consumed, so we apply the effects of the item inour  
  30.               //game world's logic, which in our case means filling the gas tank abit  
  31.           if(purchase.getSku().equals("coins_100")||purchase.getSku().equals("android.test.purchased")){  
  32.           showMessage("支付成功","成功購買100貓幣");  
  33.     }  
  34.            }  
  35.           else {  
  36.               complain("Error while consuming: " + result);  
  37.            }  
  38.        }  
  39.     };  
  40.       
  41. // Listener that's called when we finish querying the items weown  
  42. IabHelper.QueryInventoryFinishedListener mGotInventoryListener =newIabHelper.QueryInventoryFinishedListener() {  
  43.       publicvoidonQueryInventoryFinished(IabResult result, Inventory inventory){  
  44.           Log.d(TAG,"Query inventory finished.");  
  45.           if (result.isFailure()) {  
  46.               complain("Failed to query inventory: " +result);  
  47.              return;  
  48.            }  
  49.   
  50.           Log.d(TAG,"Query inventory was successful.");  
  51.   
  52.           if(inventory.hasPurchase("double_income")) {  
  53.          //查詢到有受管理的商品支付成功需要將道具給用戶  
  54. showMessage("成功Restore雙倍金幣""查詢到有雙倍金幣需要恢復");  
  55. }elseif(inventory.hasPurchase("cions_100")){  
  56. //查詢到不受管理的商品支付成功需要將道具消耗掉  
  57. showMessage("成功Restore100金幣","查詢到有100金幣需要恢復");  
  58. }  
  59.        }  
  60.     };  

  處理返回Activity後的數據:

[java] view plaincopy
  1. @Override  
  2. protectedvoid onActivityResult(int requestCode,int resultCode, Intent data) {  
  3. // TODO Auto-generated methodstub  
  4. Log.d(TAG, "onActivityResult("+ requestCode + "," +resultCode +"," + data);  
  5.   
  6.        // Pass on theactivity result to the helper for handling  
  7.       if(!mHelper.handleActivityResult(requestCode, resultCode, data)){  
  8.           // not handled, so handle it ourselves(here's where you'd  
  9.           // perform any handling of activityresults not related to in-app  
  10.           // billing...  
  11.           super.onActivityResult(requestCode,resultCode, data);  
  12.        }  
  13.       else {  
  14.           Log.d(TAG,"onActivityResult handled by IABUtil.");  
  15.        }  
  16. }  

  退出遊戲後銷燬IabHelper:

 

[java] view plaincopy
  1. @Override  
  2. protectedvoid onDestroy() {  
  3. // TODO Auto-generated methodstub  
  4. super.onDestroy();  
  5. if (mHelper !=null) mHelper.dispose();  
  6.       mHelper =null;  
  7. }  

  最後附上MainActivity.java完整文件,源碼下載地址:http://pan.baidu.com/share/link?shareid=1579953623&uk=473193131

[java] view plaincopy
  1. packagecn.catcap.together;  
  2.   
  3. importjava.util.ArrayList;  
  4. importorg.json.JSONException;  
  5. importcom.android.vending.billing.IInAppBillingService;  
  6. importcom.example.android.trivialdrivesample.util.IabHelper;  
  7. importcom.example.android.trivialdrivesample.util.IabResult;  
  8. importcom.example.android.trivialdrivesample.util.Inventory;  
  9. importcom.example.android.trivialdrivesample.util.Purchase;  
  10. importcom.example.android.trivialdrivesample.util.SkuDetails;  
  11. importandroid.os.Bundle;  
  12. importandroid.os.Handler;  
  13. importandroid.os.RemoteException;  
  14. importandroid.app.Activity;  
  15. importandroid.app.AlertDialog;  
  16. importandroid.content.Intent;  
  17. importandroid.util.Log;  
  18. importandroid.view.View;  
  19. importandroid.widget.TextView;  
  20.   
  21. public class MainActivityextends Activity {  
  22.    
  23. // The helper object  
  24.    IabHelper mHelper;  
  25.  // Debugtag, for logging  
  26.    static final String TAG = "TrivialDrive";  
  27.  //Current amount of gas in tank, in units  
  28.    int mTank;  
  29.  //(arbitrary) request code for the purchase flow請求碼  
  30.    static final int RC_REQUEST = 10001;  
  31.    private boolean iap_is_ok = false;  
  32.    //double_income爲受管理商品,coins_100爲不受管理商品  
  33.    private String[] skus ={"android.test.purchased","double_income","coins_100"};  
  34.      
  35.    privateArrayList<String> sku_list;  
  36.    privateArrayList<String> price_list;  
  37.      
  38.    private IInAppBillingService billingservice;  
  39.    private TextView tv;  
  40.      
  41.   
  42. @Override  
  43. protected voidonCreate(Bundle savedInstanceState) {  
  44. super.onCreate(savedInstanceState);  
  45. setContentView(R.layout.activity_main);  
  46. Stringbase64EncodedPublicKey = "";//此處填寫自己的appid  
  47.        mHelper =new IabHelper(this, base64EncodedPublicKey);  
  48.        // enabledebug logging (for a production application, you should set this tofalse).  
  49.       mHelper.enableDebugLogging(false);  
  50.     // Start setup. This isasynchronous and the specified listener  
  51.        // will becalled once setup completes.  
  52.        Log.d(TAG,"Starting setup.");  
  53.       mHelper.startSetup(new IabHelper.OnIabSetupFinishedListener() {  
  54.           public voidonIabSetupFinished(IabResult result) {  
  55.              Log.d(TAG, "Setup finished.");  
  56.              if (!result.isSuccess()) {  
  57.                  // Ohnoes, there was a problem.  
  58.                 complain("Problem setting up in-app billing: " + result);  
  59.                 return;  
  60.              }  
  61.              iap_is_ok = true;  
  62.              // Hooray, IAB is fully set up. Now, let's getan inventory of stuff we own.  
  63.              Log.d(TAG, "Setup successful. Queryinginventory.");  
  64.           }  
  65.        });  
  66.       //購買雙倍金幣(受管理商品)  
  67.       findViewById(R.id.button1).setOnClickListener(newView.OnClickListener() {  
  68.    
  69. @Override  
  70. public void onClick(Viewv) {  
  71. // TODO Auto-generatedmethod stub  
  72. iapHandler.sendEmptyMessage(1);  
  73. }  
  74. });  
  75.       //購買100貓幣(不受管理商品)  
  76.       findViewById(R.id.button2).setOnClickListener(newView.OnClickListener() {  
  77.    
  78. @Override  
  79. public void onClick(Viewv) {  
  80. // TODO Auto-generatedmethod stub  
  81. iapHandler.sendEmptyMessage(2);  
  82. }  
  83. });  
  84.        //RestoreOrder  
  85.       findViewById(R.id.button3).setOnClickListener(newView.OnClickListener() {  
  86.    
  87. @Override  
  88. public void onClick(Viewv) {  
  89. // TODO Auto-generatedmethod stub  
  90. if (iap_is_ok) {  
  91. mHelper.queryInventoryAsync(mGotInventoryListener);  
  92. }else {  
  93. showMessage("提示""GooglePlay初始化失敗,當前無法進行支付,請確定您所在地區支持Google Play支付或重啓遊戲再試!");  
  94. }  
  95.    
  96. }  
  97. });  
  98.        //獲取價格  
  99.       findViewById(R.id.button4).setOnClickListener(newView.OnClickListener() {  
  100.    
  101. @Override  
  102. public void onClick(Viewv) {  
  103. // TODO Auto-generatedmethod stub  
  104. sku_list = newArrayList<String>();  
  105. price_list = newArrayList<String>();  
  106. //添加默認值  
  107. sku_list.add("double_income");  
  108. price_list.add("HK$40");  
  109. sku_list.add("coins_100");  
  110. price_list.add("HK$8");  
  111. new Thread(new Runnable(){  
  112.    
  113. @Override  
  114. public void run() {  
  115. // TODO Auto-generatedmethod stub  
  116. getPrice();  
  117. }  
  118. }).start();  
  119. }  
  120. });  
  121.        //測試訂單  
  122.       findViewById(R.id.button5).setOnClickListener(newView.OnClickListener() {  
  123.    
  124. @Override  
  125. public void onClick(Viewv) {  
  126. // TODO Auto-generatedmethod stub  
  127. iapHandler.sendEmptyMessage(3);  
  128. }  
  129. });  
  130.        //顯示價格  
  131.        tv =(TextView) findViewById(R.id.text);  
  132. }  
  133. //獲取價格  
  134. private voidgetPrice(){  
  135. ArrayList<String> skus = newArrayList<String>();  
  136. skus.add("double_income");  
  137. skus.add("coins_100");  
  138. billingservice =mHelper.getService();  
  139. Bundle querySkus = newBundle();  
  140.   querySkus.putStringArrayList("ITEM_ID_LIST",skus);  
  141. try {  
  142. Bundle skuDetails =billingservice.getSkuDetails(3,MainActivity.this.getPackageName(),"inapp", querySkus);  
  143. ArrayList<String> responseList =skuDetails.getStringArrayList("DETAILS_LIST");  
  144. if (null!=responseList){  
  145. for (String thisResponse :responseList) {  
  146.          try {  
  147. SkuDetails d = newSkuDetails(thisResponse);  
  148.    
  149. for (int i = 0; i< sku_list.size(); i++) {  
  150. if(sku_list.get(i).equals(d.getSku())) {  
  151. price_list.set(i,d.getPrice());  
  152. }  
  153. }  
  154. iapHandler.sendEmptyMessage(0);  
  155.    
  156. catch (JSONException e){  
  157. // TODO Auto-generatedcatch block  
  158. e.printStackTrace();  
  159. }  
  160.            
  161.       }  
  162. }  
  163. catch (RemoteExceptione) {  
  164. // TODO Auto-generatedcatch block  
  165. e.printStackTrace();  
  166. }  
  167. }  
  168.    
  169. Handler iapHandler = newHandler(){  
  170. public voidhandleMessage(android.os.Message msg) {  
  171. switch(msg.what){  
  172. case 0:  
  173. tv.setText(price_list.get(0)+"\n"+price_list.get(1));  
  174. break;  
  175. case 1:  
  176. if (iap_is_ok) {  
  177. mHelper.launchPurchaseFlow(MainActivity.this, skus[1], RC_REQUEST,        mPurchaseFinishedListener);  
  178. }else {  
  179. showMessage("提示""GooglePlay初始化失敗,當前無法進行支付,請確定您所在地區支持Google Play支付或重啓遊戲再試!");  
  180. }  
  181. break;  
  182. case 2:  
  183. if (iap_is_ok) {  
  184. mHelper.launchPurchaseFlow(MainActivity.this, skus[2], RC_REQUEST,mPurchaseFinishedListener);  
  185. }else {  
  186. showMessage("提示""GooglePlay初始化失敗,當前無法進行支付,請確定您所在地區支持Google Play支付或重啓遊戲再試!");  
  187. }  
  188. break;  
  189. case 3:  
  190. if (iap_is_ok) {  
  191. mHelper.launchPurchaseFlow(MainActivity.this, skus[0], RC_REQUEST,mPurchaseFinishedListener);  
  192. }else {  
  193. showMessage("提示""GooglePlay初始化失敗,當前無法進行支付,請確定您所在地區支持Google Play支付或重啓遊戲再試!");  
  194. }  
  195.    
  196. break;  
  197. default:  
  198. break;  
  199. }  
  200. };  
  201. };  
  202.    
  203. // Callback for when apurchase is finished  
  204.    IabHelper.OnIabPurchaseFinishedListenermPurchaseFinishedListener = newIabHelper.OnIabPurchaseFinishedListener() {  
  205.        publicvoid onIabPurchaseFinished(IabResult result, Purchase purchase){  
  206.           Log.d(TAG, "Purchasefinished: " + result + ", purchase: " + purchase);  
  207.           if (result.isFailure()) {  
  208.              // Oh noes!  
  209.              complain("Error purchasing: " + result);  
  210.              return;  
  211.           }  
  212.   
  213.           Log.d(TAG, "Purchasesuccessful.");  
  214.           if(purchase.getSku().equals("coins_100")||purchase.getSku().equals("android.test.purchased")){  
  215.          mHelper.consumeAsync(purchase, mConsumeFinishedListener);  
  216. }else if(purchase.getSku().equals("double_income")) {  
  217. //受管理的商品,開啓雙倍經驗  
  218. showMessage("支付成功","成功購買雙倍經驗");  
  219. }  
  220.        }  
  221.    };  
  222.    // Called when consumption is complete  
  223.    IabHelper.OnConsumeFinishedListenermConsumeFinishedListener = newIabHelper.OnConsumeFinishedListener() {  
  224.        publicvoid onConsumeFinished(Purchase purchase, IabResult result) {  
  225.           Log.d(TAG, "Consumptionfinished. Purchase: " + purchase + ", result: " + result);  
  226.   
  227.           // We know this is the "gas"sku because it's the only one we consume,  
  228.           // so we don't check whichsku was consumed. If you have more than one  
  229.           // sku, you probably shouldcheck...  
  230.           if (result.isSuccess()) {  
  231.              // successfully consumed, so we apply theeffects of the item in our  
  232.              // game world's logic, which in our case meansfilling the gas tank a bit  
  233.           if(purchase.getSku().equals("coins_100")||purchase.getSku().equals("android.test.purchased")){  
  234.           showMessage("支付成功","成功購買100貓幣");  
  235.    }  
  236.           }  
  237.           else {  
  238.              complain("Error while consuming: " +result);  
  239.           }  
  240.        }  
  241.    };  
  242.      
  243.    // Listener that's called when we finishquerying the items we own  
  244.    IabHelper.QueryInventoryFinishedListenermGotInventoryListener = newIabHelper.QueryInventoryFinishedListener() {  
  245.        publicvoid onQueryInventoryFinished(IabResult result, Inventoryinventory) {  
  246.           Log.d(TAG, "Query inventoryfinished.");  
  247.           if (result.isFailure()) {  
  248.              complain("Failed to query inventory: " +result);  
  249.              return;  
  250.           }  
  251.   
  252.           Log.d(TAG, "Query inventorywas successful.");  
  253.   
  254.           if(inventory.hasPurchase("double_income")) {  
  255.           //查詢到有受管理的商品支付成功需要將道具給用戶  
  256. showMessage("成功Restore雙倍金幣""查詢到有雙倍金幣需要恢復");  
  257. }elseif(inventory.hasPurchase("cions_100")){  
  258. //查詢到不受管理的商品支付成功需要將道具消耗掉  
  259. showMessage("成功Restore100金幣","查詢到有100金幣需要恢復" );  
  260. }  
  261.        }  
  262.    };  
  263.    @Override  
  264. protected voidonActivityResult(int requestCode, int resultCode, Intent data){  
  265. // TODO Auto-generatedmethod stub  
  266. Log.d(TAG,"onActivityResult(" + requestCode + "," + resultCode + "," +data);  
  267.   
  268.        // Pass onthe activity result to the helper for handling  
  269.        if(!mHelper.handleActivityResult(requestCode, resultCode, data)){  
  270.           // not handled, so handle itourselves (here's where you'd  
  271.           // perform any handling ofactivity results not related to in-app  
  272.           // billing...  
  273.          super.onActivityResult(requestCode, resultCode, data);  
  274.        }  
  275.        else {  
  276.           Log.d(TAG, "onActivityResulthandled by IABUtil.");  
  277.        }  
  278. }  
  279.    @Override  
  280. protected void onDestroy(){  
  281. // TODO Auto-generatedmethod stub  
  282. super.onDestroy();  
  283. if (mHelper != null)mHelper.dispose();  
  284.        mHelper =null;  
  285. }  
  286. void complain(Stringmessage) {  
  287.        Log.e(TAG,"**** TrivialDrive Error: " + message);  
  288.       alert("Error: " + message);  
  289.    }  
  290. void alert(String message){  
  291.       AlertDialog.Builder bld = new AlertDialog.Builder(this);  
  292.       bld.setMessage(message);  
  293.       bld.setNeutralButton("OK"null);  
  294.        Log.d(TAG,"Showing alert dialog: " + message);  
  295.       bld.create().show();  
  296.    }  
  297. private voidshowMessage(String title,String message){  
  298. newAlertDialog.Builder(MainActivity.this).setTitle(title).setMessage(message).setPositiveButton("確定",null).show();  
  299. }  
  300. }  

以上就是完整的Google in-appBilling接入過程

發佈了62 篇原創文章 · 獲贊 72 · 訪問量 128萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章