Я работаю над приложением для Android, разработанным на основе Titanium SDK 3.2.0.GA, и использую Модуль биллинга в приложении от Appcelerator.
Моя реализация модуля выглядит следующим образом (исключая функции, единственной целью которых является отображение информации журнала):
var IdentifierProduct = '';
var InAppBilling = require('ti.inappbilling');
var publicKey = Alloy.Globals.Android.publicKey_1 + Alloy.Globals.Android.publicKey_2 + Alloy.Globals.Android.publicKey_3 + Alloy.Globals.Android.publicKey_4;
InAppBilling.setPublicKey(publicKey);
function initializeBilling()
{
var synchronousResponse = InAppBilling.checkBillingSupported();
displaySynchronousResponseCodes(synchronousResponse);
}
function requestPurchase(identifier, item_type)
{
// Check if billing for current product type is supported before sending purchase request
var checkBillingResponse = InAppBilling.checkBillingSupported(item_type);
if (checkBillingResponse.responseCode == InAppBilling.RESULT_OK)
{
Ti.API.info('Current product type supported, continuing with request');
var tmpArgs = {
productId: identifier,
productType: item_type,
developerPayload: 'devPayload'
};
Ti.API.info('args for product request\n' + JSON.stringify(tmpArgs));
var synchronousResponse = InAppBilling.requestPurchase({
// productId: 'android.test.purchased',
// productId: 'android.test.canceled',
// productId: 'android.test.refunded',
// productId: 'android.test.item_unavailable',
productId: identifier,
productType: item_type,
developerPayload: 'devPayload'
});
displaySynchronousResponseCodes(synchronousResponse);
}
else
{
Ti.API.info('Current product type not supported, aborting request');
displaySynchronousResponseCodes(checkBillingResponse);
}
}
function ON_BIND_EVENT(e)
{
if (e.result == InAppBilling.SUCCESS) {
NotifyMe('Billing Service Bound');
enableInAppPurchases(true);
//Call
} else {
NotifyMe('Billing Service Bind Failed');
enableInAppPurchases(false);
}
}
InAppBilling.addEventListener(InAppBilling.ON_BIND_EVENT, ON_BIND_EVENT);
function ON_CONNECT_EVENT(e)
{
NotifyMe('CONNECT CALLED');
if(Ti.App.Properties.getBool('transactionsRestores') === null)
{
Ti.API.info('fresh install, lets restore the transactions');
try
{
InAppBilling.restoreTransactions();
}
catch(err)
{
Ti.API.info('Error');
Ti.API.info(JSON.stringify(err));
}
}
}
InAppBilling.addEventListener(InAppBilling.ON_CONNECT_EVENT, ON_CONNECT_EVENT);
function RESPONSE_EVENT(e)
{
// Events with (e.sync == true) are deprecated and will be removed. Use the event object that the methods return.
if(!e.sync){
NotifyMe('RESPONSE CALLED ' + e.requestId + ' ' + e.responseCode);
Ti.API.info('RESPONSE CALLED \n' + 'Request Id:\n' + e.requestId + ' ' + '\nResponse Code:' + ResponseString(e.responseCode));
if(e.responseCode === InAppBilling.RESULT_ERROR)
{
// Error in request
Ti.API.info('Response event error');
Ti.API.info(JSON.stringify(e));
}
else if(e.responseCode === InAppBilling.RESULT_ITEM_UNAVAILABLE)
{
// Item unavailable in request
Ti.API.info('Response event item unavailable');
Ti.API.info(JSON.stringify(e));
}
}
}
InAppBilling.addEventListener(InAppBilling.RESPONSE_EVENT, RESPONSE_EVENT);
function PURCHASE_STATE_CHANGED_EVENT(e)
{
Ti.API.info('PURCHASE_STATE_CHANGED_EVENT Parameters:\n' + JSON.stringify(e) );
NotifyMe('PURCHASE STATE CHANGED CALLED ' + e.signedData + ' ' + e.signature+'\n'+ 'SECURITY RESULT ' + e.result);
Ti.API.info('PURCHASE STATE CHANGED CALLED');
Ti.API.info('Signature Verification Result:\n' + VerificationString(e.result));
Ti.API.info('Signed Data:\n' + e.signedData);
if (e.signedData != null) {
var response = JSON.parse(e.signedData);
/*
* We are not guaranteed to have any orders returned so
* we need to make sure that this one exists before using it.
*
* If there is no notificationId then there is no need to confirmNotifications().
* This happens when restoreTransactions() triggers a PURCHASE_STATE_CHANGED_EVENT.
*/
for(var i = 0; i < response.orders.length; i++)
{
if(typeof response.orders[i] !== 'undefined')
{
setPurchaseFlag(response.orders[i].productId);
}
if (response.orders[i] && response.orders[i].notificationId)
{
Ti.API.info('confirming notification for order ' + JSON.stringify(response.orders[i]));
var synchronousResponse = InAppBilling.confirmNotifications({
notificationIds: [response.orders[i].notificationId]
});
displaySynchronousResponseCodes(synchronousResponse);
}
}
}
}
InAppBilling.addEventListener(InAppBilling.PURCHASE_STATE_CHANGED_EVENT, PURCHASE_STATE_CHANGED_EVENT);
function NOTIFY_EVENT(e)
{
Ti.API.info('NOTIFY CALLED \n' + 'Notify Id:\n' + e.notifyId);
var synchronousResponse = InAppBilling.getPurchaseInformation({
notificationIds: [e.notifyId]
});
displaySynchronousResponseCodes(synchronousResponse);
}
InAppBilling.addEventListener(InAppBilling.NOTIFY_EVENT, NOTIFY_EVENT);
InAppBilling.startBillingService();
Ниже приведен список шагов, которые я рассмотрел для поиска ошибок:
- Я проверил, что имя моего пакета совпадает с именем в черновике моего приложения в Play Store.
- Я проверил правильность моего лицензионного ключа
- все мои продукты в приложении находятся в активном состоянии
- запрос, отправленный в Play Store, имеет идентификаторы продуктов, соответствующие моим продуктам в приложении.
- Учетная запись моего устройства зарегистрирована как тестовая, поэтому она должна позволить мне совершить покупку.
Я добавил внутриигровые продукты около двух недель назад, и каждый раз, когда я пытаюсь запросить покупку, все они возвращают ответ «не найдено». Play Store не может так долго активировать их, верно?
И все же получаю в ответ "товар, который вы пытаетесь приобрести, не найден".
Код ответа, который я получаю, равен 2, что, как я думал, означает RESULT_SERVICE_UNAVAILABLE, но в появившемся диалоговом окне четко говорится, что элемент не найден, я неправильно интерпретирую код ответа? Или я должен выяснить, почему служба недоступна?
Я следовал руководству по тестированию встроенных покупок и получение этой ошибки без ясной причины.
ИЗМЕНИТЬ
Я искал и нашел несколько вопросов (здесь и здесь) разработчики получили RESULT_SERVICE_UNAVAILABLE, когда слишком много вызовов restoreTransactions(). Я проверил свой код и увидел, что действительно выполняю вызов restoreTransactions() каждый раз, когда запускаю приложение.
Теперь я добавил проверку на ON_CONNECT_EVENT, чтобы убедиться, что вообще были транзакции для восстановления, в случае, если это не так, я установил флаг, который не позволяет приложению выполнять () вызвать следующий запуск.
Однако проблема все еще остается: могу ли я как-то связаться с Google, чтобы попросить снова включить мои службы в приложении? Как долго мне ждать? Пользователи в этих вопросах упоминают, что это может занять до 3 недель, можем ли мы ускорить этот процесс?
К сожалению, без In-App Purchases мы не можем выпустить наше приложение.