Im having a bit of trouble testing in app purchases on android using ti.inappbilling and was wondering if someone that has successfully implemented it can help me where Im going wrong. I was able to get apples stoker running and tested in one hour but I've spent days looking through googles cryptic docs with no luck.
Heres the steps I've taken 1) added the module to the project 2) added the app to google play and created 7 consumable in app purchases 3) published and uploaded the app to google play beta 4) copied my rsa public key from the play store and assigned it to the public_key in the app 5) create a google group and assigned it to testers in google play 6) installed the app from titanium onto my device 7) attempted to do the in app purchase and returns 'IAB RESULT UNKNOWN ERROR' 8) Tried to query the product and it returns RESULT_OK which means that it can see it 9) Scratch head and swear at google
Heres how I'm implementing it
var InAppBilling = require('ti.inappbilling'); // Replace this public key with your app's public key. // Follow the "Add Your Application to the Developer Console" instructions: // http://developer.android.com/training/in-app-billing/preparing-iab-app.html#AddToDevConsole var PUBLIC_KEY = 'mybiglongkey'; // Read more about the developer payload in the "Verify the Developer Payload" // section of the documentation. It is not necessary to change this to run the example. var DEVELOPER_PAYLOAD = myusertestid; var toConsume = null; // A place to hold a purchase that can be consumed ///run setup first in order to do any in app purchases runSetup() InAppBilling.addEventListener('setupcomplete', function(e) { logInApp('Setup response: ' + responseString(e.responseCode)); if (e.success) { logInApp('Setup completed successfully!'); } else { logInApp('Setup FAILED.'); } }); InAppBilling.addEventListener('queryinventorycomplete', function(e) { logInApp('Query Inventory response: ' + responseString(e.responseCode)); var inventory = e.inventory; var purchaseIds = ['Fun Pack 01']; var purchase, details; if (e.success) { for (var i = 0, j = purchaseIds.length; i < j; i++) { // Check for details if (inventory.hasDetails(purchaseIds[i])) { logInApp('Check log for Purchase ' + i + ' details'); Ti.API.info('Details: ' + JSON.stringify(inventory.getDetails(purchaseIds[i]))); } // Check for purchase if (inventory.hasPurchase(purchaseIds[i])) { purchase = inventory.getPurchase(purchaseIds[i]); // Print details for each purchase logInApp('Check log for Purchase ' + i + ' properties'); Ti.API.info(purchaseProperties(purchase)); // Queue 'fp01' up to be consumed if it is owned if (purchase.productId === 'fp01' && purchase.purchaseState === InAppBilling.PURCHASE_STATE_PURCHASED) { toConsume = purchase; logInApp('fp01 is queued to be consumed'); } } } } }); InAppBilling.addEventListener('purchasecomplete', function(e) { logInApp('Purchase response: ' + responseString(e.responseCode)); if (e.success && e.purchase) { logInApp(purchaseProperties(e.purchase)); // Prepare the purchase to be consumed if (e.purchase.productId === 'fp01') { toConsume = e.purchase; logInApp('fp01 is queued to be consumed'); } alert('Purchase completed successfully'); } }); InAppBilling.addEventListener('consumecomplete', function(e) { logInApp('Consume response: ' + responseString(e.responseCode)); if (e.success) { alert('Consume completed successfully'); } });...for some reason it wouldn't let me put it in one code block heres the rest
//////////////////////////////////////////////////////// // Utils //////////////////////////////////////////////////////// function runSetup() { logInApp('Running startSetup...'); InAppBilling.startSetup({ publicKey: PUBLIC_KEY }); logInApp('Wait for setup to complete successfully'); } function responseString(responseCode) { switch (responseCode) { case InAppBilling.RESULT_OK: return 'OK'; case InAppBilling.RESULT_USER_CANCELED: return 'USER CANCELED'; case InAppBilling.RESULT_BILLING_UNAVAILABLE: return 'BILLING UNAVAILABLE'; case InAppBilling.RESULT_ITEM_UNAVAILABLE: return 'ITEM UNAVAILABLE'; case InAppBilling.RESULT_DEVELOPER_ERROR: return 'DEVELOPER ERROR'; case InAppBilling.RESULT_ERROR: return 'RESULT ERROR'; case InAppBilling.RESULT_ITEM_ALREADY_OWNED: return 'RESULT ITEM ALREADY OWNED'; case InAppBilling.RESULT_ITEM_NOT_OWNED: return 'RESULT ITEM NOT OWNED'; case InAppBilling.IAB_RESULT_REMOTE_EXCEPTION: return 'IAB RESULT REMOTE EXCEPTION'; case InAppBilling.IAB_RESULT_BAD_RESPONSE: return 'IAB RESULT BAD RESPONSE'; case InAppBilling.IAB_RESULT_VERIFICATION_FAILED: return 'IAB RESULT VERIFICATION FAILED'; case InAppBilling.IAB_RESULT_SEND_INTENT_FAILED: return 'IAB RESULT SEND INTENT FAILED'; case InAppBilling.IAB_RESULT_UNKNOWN_PURCHASE_RESPONSE: return 'IAB RESULT UNKNOWN PURCHASE RESPONSE'; case InAppBilling.IAB_RESULT_MISSING_TOKEN: return 'IAB RESULT MISSING TOKEN'; case InAppBilling.IAB_RESULT_UNKNOWN_ERROR: return 'IAB RESULT UNKNOWN ERROR'; case InAppBilling.IAB_RESULT_SUBSCRIPTIONS_NOT_AVAILABLE: return 'IAB RESULT SUBSCRIPTIONS NOT AVAILABLE'; case InAppBilling.IAB_RESULT_INVALID_CONSUMPTION: return 'IAB RESULT INVALID CONSUMPTION'; } return ''; } function purchaseStateString(state) { switch (state) { case InAppBilling.PURCHASE_STATE_PURCHASED: return 'PURCHASE STATE PURCHASED'; case InAppBilling.PURCHASE_STATE_CANCELED: return 'PURCHASE STATE CANCELED'; case InAppBilling.PURCHASE_STATE_REFUNDED: return 'PURCHASE STATE REFUNDED'; } return ''; } function purchaseTypeString(state) { switch (state) { case InAppBilling.ITEM_TYPE_INAPP: return 'ITEM TYPE INAPP'; case InAppBilling.ITEM_TYPE_SUBSCRIPTION: return 'ITEM TYPE SUBSCRIPTION'; } return ''; } function purchaseProperties(p) { var str = 'type: ' + purchaseTypeString(p.type) + '\norderId: ' + p.orderId + '\npackageName: ' + p.packageName + '\nproductId: ' + p.productId + '\npurchaseTime: ' + new Date(p.purchaseTime) + '\npurchaseState: ' + purchaseStateString(p.purchaseState) + '\ndeveloperPayload: ' + p.developerPayload + '\ntoken: ' + p.token; return str; } btnBuyfp01.addEventListener('click', function(e){ InAppBilling.purchase({ productId: 'fp01', type: InAppBilling.ITEM_TYPE_INAPP, developerPayload: DEVELOPER_PAYLOAD }); });
am I missing a step? Is there something else I need to do?