2012-03-19 11 views
7

मैं ऐप-ऐप बिलिंग का उपयोग करके "भुगतान" संस्करण में एक निःशुल्क ऐप अपग्रेड करने का प्रयास कर रहा हूं। मैंने बिलिंग को संभालने के लिए this tutorial से कोड का उपयोग किया क्योंकि आधिकारिक डेवलपर साइट पर एक बहुत ही जटिल और मेरे जैसे साधारण प्रवाह के लिए गन्दा है।एंड्रॉइड इन-ऐप बिलिंग - पुनर्स्थापना ट्रांज़ेक्शन सूचना

अपग्रेड करने के लिए मेरा कोड ठीक काम करता है।

समस्या तब आती है जब मैं यह देखने के लिए कुछ जोड़ने का प्रयास करता हूं कि उपयोगकर्ता पहले से ही खरीदा है या नहीं, लेकिन डेटा को साफ़ करने या साफ़ करने के द्वारा या तो मेरा खरीद डेटा खो गया है (मुझे परवाह नहीं है)।

ऐप स्टार्टअप पर मैं पहले ध्वज के बाद सेट किए गए ध्वज की जांच करता हूं। यदि वह ध्वज नहीं है, तो उपयोगकर्ता को एक संवाद दिखाया गया है कि ऐप पिछली खरीदारियों की जांच करेगा, और जब वे ठीक क्लिक करेंगे, तो पुनर्स्थापनाकरण जानकारी विधि कहा जाता है। इसके बाद एप्लिकेशन को मजबूर होना पड़ता है।

क्योंकि डिबगिंग या एमुलेटर पर इन-ऐप बिलिंग काम नहीं करती है, इसलिए मुझे प्रत्येक बार कोड को आजमाने के लिए ऐप का एक हस्ताक्षरित संस्करण प्रकाशित करना होगा। मुझे यह जानने का कोई तरीका नहीं है कि जब मैं पुनर्स्थापनाकरण अनुरोध अनुरोध करने का प्रयास करता हूं तो एप्लिकेशन क्यों निकलता है। क्या किसी के पास कोई सुराग है कि मैं इसका निदान कैसे कर सकता हूं, या मेरे ऐप को मरने के कारण क्या हो सकता है? या restoreTransactionInformation विधि का उपयोग करने का एक उदाहरण उदाहरण है?

संपादित करें: तो ऐसा लगता है कि RESTORE_TRANSACTIONS अनुरोध सही प्रतिक्रिया प्राप्त कर रहा है, और मेरी परीक्षण खरीद के विवरण लौटा रहा है। दुर्भाग्य से इससे पहले कि यह कुछ भी कर सके, ऐप को मजबूर कर दिया गया है।

I/BillingService(6484): confirmTransaction() 
D/Finsky (1884): [7] MarketBillingService.getPreferredAccount: com.hippypkg: Account from first account. 
I/BillingService(6484): current request is:********** 
I/BillingService(6484): RESTORE_TRANSACTIONS Sync Response code: RESULT_OK 
D/WindowManagerImpl(6484): finishRemoveViewLocked, mViews[0]: [email protected]********** 
W/InputManagerService(1381): [unbindCurrentClientLocked] Disable input method client. 
W/InputManagerService(1381): [startInputLocked] Enable input method client. 
D/NativeCrypto(1884): returned from sslSelect() with result 1, error code 2 
D/Finsky (1884): [1] MarketBillingService.sendResponseCode: Sending response RESULT_OK for request ********** to com.hippypkg. 
I/BillingService(6484): Received action: com.android.vending.billing.PURCHASE_STATE_CHANGED 
I/BillingService(6484): purchaseStateChanged got signedData: {"nonce":**********,"orders":[{"orderId":"**********","packageName":"com.hippypkg","productId":"hippy_upgrade_free_to_full","purchaseTime":1331476540000,"purchaseState":0}]} 
I/BillingService(6484): purchaseStateChanged got signature: **********== 
I/BillingService(6484): signedData: {"nonce":**********,"orders":[{"orderId":"**********","packageName":"com.hippypkg","productId":"hippy_upgrade_free_to_full","purchaseTime":1331476540000,"purchaseState":0}]} 
I/BillingService(6484): signature: **********== 
I/BillingService(6484): confirmTransaction() 
I/BillingService(6484): makerequestbundle success 
I/BillingService(6484): putstringarray success 
D/Finsky (1884): [24] MarketBillingService.getPreferredAccount: com.hippypkg: Account from first account. 
D/AndroidRuntime(6484): Shutting down VM 
W/dalvikvm(6484): threadid=1: thread exiting with uncaught exception (group=0x4001d5a0) 
E/AndroidRuntime(6484): FATAL EXCEPTION: main 
E/AndroidRuntime(6484): java.lang.RuntimeException: Unable to start receiver com.hippypkg.BillingReceiver: java.lang.NullPointerException 
E/AndroidRuntime(6484): at android.app.ActivityThread.handleReceiver(ActivityThread.java:2144) 
E/AndroidRuntime(6484): at android.app.ActivityThread.access$2400(ActivityThread.java:135) 
E/AndroidRuntime(6484): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1114) 
E/AndroidRuntime(6484): at android.os.Handler.dispatchMessage(Handler.java:99) 
E/AndroidRuntime(6484): at android.os.Looper.loop(Looper.java:150) 
E/AndroidRuntime(6484): at android.app.ActivityThread.main(ActivityThread.java:4385) 
E/AndroidRuntime(6484): at java.lang.reflect.Method.invokeNative(Native Method) 
E/AndroidRuntime(6484): at java.lang.reflect.Method.invoke(Method.java:507) 
E/AndroidRuntime(6484): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:849) 
E/AndroidRuntime(6484): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:607) 
E/AndroidRuntime(6484): at dalvik.system.NativeStart.main(Native Method) 
E/AndroidRuntime(6484): Caused by: java.lang.NullPointerException 
E/AndroidRuntime(6484): at android.os.Parcel.readException(Parcel.java:1328) 
E/AndroidRuntime(6484): at android.os.Parcel.readException(Parcel.java:1276) 
E/AndroidRuntime(6484): at com.android.vending.billing.IMarketBillingService$Stub$Proxy.sendBillingRequest(IMarketBillingService.java:100) 
E/AndroidRuntime(6484): at com.hippypkg.BillingHelper.confirmTransaction(BillingHelper.java:152) 
E/AndroidRuntime(6484): at com.hippypkg.BillingHelper.verifyPurchase(BillingHelper.java:250) 
E/AndroidRuntime(6484): at com.hippypkg.BillingReceiver.purchaseStateChanged(BillingReceiver.java:41) 
E/AndroidRuntime(6484): at com.hippypkg.BillingReceiver.onReceive(BillingReceiver.java:23) 
E/AndroidRuntime(6484): at android.app.ActivityThread.handleReceiver(ActivityThread.java:2103) 
E/AndroidRuntime(6484): ... 10 more 
W/ActivityManager(1381): Force finishing activity com.hippypkg/.Hippy 
+0

अरे वहाँ; क्या आपको अभी तक कोई समाधान मिला है? मैं बस इस मुद्दे पर आया और मैं आपके जैसा ही स्थान पर अटक गया हूं। – Sid

+0

अभी तक नहीं - दुर्भाग्य से मैं किसी और चीज़ पर काम करने के लिए चले गए और उन्हें देखने का मौका नहीं मिला। अब तक के सबसे अच्छे परिणाम के लिए निकोले द्वारा प्रतिक्रिया पर धागे का पालन करें। अगर आपको कहीं भी मिलता है तो मुझे बताएं! – Hippyjim

+0

इसे हल किया, बाद में 4 घंटे और 5 कॉफी) :) जवाब देखें। – Sid

उत्तर

4

तो आखिरकार मैं इसे समझने में कामयाब रहा।

आप अनुप्रयोग में बिलिंग अवलोकन के लिए गूगल डॉक्स को देखें, तो यह कहा गया है कि:

RESTORE_TRANSACTIONS अनुरोध प्रकार भी चलाता है एक PURCHASE_STATE_CHANGED प्रसारण आशय है, जो लेन-देन के बारे में जानकारी के एक ही प्रकार एक के दौरान भेजा गया है शामिल खरीद अनुरोध, हालांकि आपको CONFIRM_NOTIFICATIONS संदेश के साथ इस इरादे का जवाब देने की आवश्यकता नहीं है।

सामान्य खरीद-पुष्टिकरण ट्रांज़ेक्शन चक्र में, जब आप ऐप बिलिंग उत्पाद खरीदने का अनुरोध करते हैं, तो Google फ़ील्ड के समूह के साथ एक JSON वापस भेजता है। इनमें से एक फ़ील्ड 'inform_id' है। जब Google एक PURCHASE_STATE_CHANGED इरादा भेजता है, तो यह ऐप से CONFIRM_NOTIFICATIONS प्रतिक्रिया की अपेक्षा करता है, जिसमें एक बंडल होता है जिसमें अधिसूचना_आईडी शामिल है। सब ठीक है और यहाँ अच्छा है।

समस्या तब शुरू होती है जब आप ऐप से RESTORE_TRANSACTIONS अनुरोध के लिए Google से PURCHASE_STATE_CHANGED प्राप्त करते हैं। इस JSON में notificaion_id फ़ील्ड नहीं हैं। लाइब्रेरी अभी भी CONFIRM_NOTIFICATIONS के साथ प्रतिक्रिया देती है, बंडल में अधिसूचना_आईडी सरणी जोड़ती है, जो इस मामले में शून्य है। यही कारण है कि NullPointerException का कारण बनता है।

समाधान: मैं ट्रैक करने के लिए जब उपयोगकर्ता एक सामान्य खरीदारी करता है एक बूलियन जोड़कर BillingHelper.java वर्ग संशोधित, और जब वह restoreTransactions करना चाहता है। यदि यह पुनर्स्थापना अनुरोध है, तो मैं हैंडलर को एक संदेश वापस भेजता हूं और पुष्टिकरण चरण छोड़ देता हूं।

संपादित करें: ऊपर फिक्स के लिए कोड BillingHelper.java में है मैं ट्रैक करने के लिए उपयोगकर्ता एक RESTORE_TRANSACTIONS कॉल (isRestoreTransactions) बनाया है कि क्या एक बूलियन ध्वज का उपयोग कर रहा हूँ।

BillingHelper.java की 'verifyPurchase' विधि में, मैं कोड इस प्रकार बदल दिया है:

protected static void verifyPurchase(String signedData, String signature) { 
     ArrayList<VerifiedPurchase> purchases = BillingSecurity.verifyPurchase(signedData, signature); 

     if(isRestoreTransaction) 
     { 
      /* 
      * 
      *Add some logic to retrieve the restored purchase product ID's from the 'purchases' array 
      * 
      */ 

      //Set the boolean to false 
      isRestoreTranscation = false; 

      //Send a message to the handler, informing it that purchases were restored 
      if(mCompletedHandler != null){ 
       mCompletedHandler.sendEmptyMessage(0); 
      } else { 
       Log.e(TAG, "verifyPurchase error. Handler not instantiated. Have you called setCompletedHandler()?"); 
      } 
     } 
     else 
     { 
      /* 
      *...... 
      *...... 
      *...... 
      *Original method body here 
      *...... 
      *...... 
      *...... 
      */ 
     } 
    } 
+0

सिड, बहुत बहुत धन्यवाद - यह इसे तोड़ दिया। चूंकि बूलियन आदि के साथ गड़बड़ की बजाय, मेरे ऐप से केवल 1 खरीद संभव है, मैं बस जांचता हूं कि नवीनतम खरीद। नोटिफिकेशन आईडी शून्य था या नहीं। यदि ऐसा है, तो यह पुष्टि भेजने की कोशिश नहीं करता है (यदि यह शून्य है तो यह काम नहीं करेगा)। यदि आपका समाधान थोड़ा अधिक व्यापक है, तो भविष्य के आगंतुकों के लिए यह अच्छा हो सकता है यदि आप यहां कोड परिवर्तन पोस्ट कर सकते हैं, या शायद ट्यूटोरियल में हमें यह मिला है। एक बार फिर धन्यवाद! – Hippyjim

+0

क्या आप मुझे वह परिवर्तन दे सकते हैं जो आपने RESTORE_TRANSACTIONS के लिए किए हैं ...? मैं कुछ दिनों के लिए उस समस्या से भी अटक गया हूं। कृपया आपके द्वारा किए गए परिवर्तन प्रदान करके मेरी सहायता करें। –

+1

रशभ, – Sid

4

आप वास्तव में 'फिर से स्थापित करने' और 'को मंजूरी दे दी एप्लिकेशन डेटा' के बीच एक अंतर नहीं कर सकते: यहाँ क्या होता है बाजार सही होने के बाद RESTORE_TRANSACTIONS अनुरोध का जवाब की एक logcat (अस्पष्ट कोड के बिना) है। वे अनिवार्य रूप से वही हैं: साझा प्राथमिकताएं खाली हैं। आपको भी इसकी आवश्यकता नहीं है।

इस मुद्दे का निदान करने के लिए, 'लेनदेन बहाल करें' बटन डालें और इसे विभिन्न राज्यों (बस स्थापित, ध्वज सेट) आदि पर क्लिक करें। फिर लॉगकैट देखें।

बीटीडब्लू, पहले मूल कोड के साथ रहना बेहतर हो सकता है, आपको इस तरह से और सहायता मिलेगी। Google Code पर कुछ प्रोजेक्ट भी हैं जो आईएबी कोड को लपेटने के लिए इसे थोड़ा आसान बनाने के लिए लपेटते हैं।

+0

धन्यवाद, मैंने सवाल स्पष्ट कर दिया है क्योंकि मुझे सच में परवाह नहीं है कि उन्होंने अपना डेटा कैसे खो दिया - मुझे पता है कि एक के बीच का अंतर बताना संभव नहीं है नया इंस्टॉल और एक जिसने डेटा मिटा दिया था। जैसा कि मैंने उल्लेख किया है, प्रबंधित इन-ऐप खरीदारियों की जांच के लिए बिलिंग का उपयोग करने में सक्षम होने के लिए, आपको एक हस्ताक्षरित ऐप का उपयोग डीबग मोड में नहीं करना चाहिए, इसलिए इसे वास्तविक डिवाइस पर चलाना होगा। इसका मतलब है कि मेरे पास कोई लॉगकट नहीं है - जब तक कि मुझे कुछ याद नहीं आ रहा है? विशाल Google उदाहरण का उपयोग करने के लिए, यह बहुत जटिल है और मैं इस बात का काम नहीं कर सकता कि इसमें मेरा सरल खरीदारी कैसे किया जाए, इसलिए मैंने जिस रैपर का उल्लेख किया है उसका उपयोग करना। – Hippyjim

+0

आपको कुछ याद आ रहा है :) आपके पास लॉगकैट है, यदि आप मैनिफेस्ट में डिबग करने योग्य ध्वज सेट करते हैं तो आप ऐप को डीबग भी कर सकते हैं। 'विशाल' उदाहरण का उपयोग करने का लाभ यह है कि आपको वास्तव में यह समझने की आवश्यकता होगी कि यह आंतरिक रूप से कैसे काम करता है, और यह टूटने पर आपको ठीक करने में मदद करेगा। आपको कम से कम परीक्षण पर भाग पढ़ना चाहिए: http://developer.android.com/guide/market/billing/billing_testing.html –

+0

धन्यवाद, दुर्भाग्य से मैंने उस पृष्ठ को पढ़ लिया है और यह बहुत मदद नहीं है। यह केवल वास्तविक खरीद के बारे में बात करता है, जिसे मैंने बिना किसी समस्या के किया था। मौजूदा खरीदारियों को देखने का प्रयास करते समय (एक RESTORE_TRANSACTIONS अनुरोध करना), यदि ऐप डीबग मोड में है तो मुझे प्रत्येक अनुरोध के लिए RESULT_DEVELOPER_ERROR मिलता है। उसी गाइड के मुताबिक आपने मुझे अभी संदर्भित किया है, यह अपेक्षित व्यवहार है।तो परीक्षण करने का एकमात्र तरीका, एक हस्ताक्षरित आवेदन के साथ है - बिना डीबग के। क्या लाइव डिवाइस पर लॉगकैट देखने का कोई तरीका है? – Hippyjim

0

मैं भी एक नि: शुल्क एप्लिकेशन अपग्रेड किया जा सकता विकासशील हूँ, लेकिन मैं, ब्लंडेल के ट्यूटोरियल के बजाय Oficial उदाहरण का इस्तेमाल किया क्योंकि कि ट्यूटोरियल जानकारी और does not आइटम उपयोग प्रबंधित नहीं सहेजता है

बस restoreDatabase पर एक बार देख ले() डंगऑन नमूने में विधि, यह वही करता है जो आप चाहते हैं, साझा करते हैं, साझा किए गए संदर्भों का उपयोग करते हुए, यदि यह पहला रन है और यदि यह पुनर्स्थापना प्रक्रिया विधि को कॉल करता है।

डीबग करने के लिए, बस अपने डिवाइस को ग्रहण करने के लिए कनेक्ट करें और लॉगकैट की जांच करें, बस निरंतर डीबग (Consts.java में) को सत्य में सेट करना न भूलें और मैनिफेस्ट में डिबग करने योग्य टैग को भी सही पर सेट करें।

नमूना कोड को बेहतर ढंग से समझने के लिए मैंने अभी बहुत अधिक डीबग जोड़ा और अब यह काम कर रहा है।

संबंधित मुद्दे