Андроид: Биллинг Inapp: Ответ на ошибку: 7: Элемент уже принадлежит
Я научился внедрять биллинг в приложении для своего приложения, чтобы люди могли, например, пожертвовать $, когда нажимают кнопку пожертвования.
Пользователь может пожертвовать более одного раза, то есть покупка является расходной.
Ниже приведены коды из примера TrivalDrive и некоторых учебных пособий из Интернета:
код:
IabHelper mHelper;
static final String ITEM_SKU = "android.test.purchased";
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_in_app_billing);
buy10Button = (Button) findViewById(R.id.buy10Button);
buy15Button = (Button) findViewById(R.id.buy15Button);
buy20Button = (Button) findViewById(R.id.buy20Button);
String base64EncodedPublicKey = "keykeykey";
mHelper = new IabHelper(this, base64EncodedPublicKey);
mHelper.startSetup(new IabHelper.OnIabSetupFinishedListener()
{
public void onIabSetupFinished(IabResult result)
{
if (!result.isSuccess())
{
Log.d(TAG, "In-app Billing setup failed: " + result);
return;
}
if (mHelper == null)
{
return;
}
Log.d(TAG, "In-app Billing is set up OK");
}
});
}
public void buy10Click(View view)
{
mHelper.launchPurchaseFlow(this, ITEM_SKU, 10001, mPurchaseFinishedListener, "");
}
public void buy15Click(View view)
{
}
public void buy20Click(View view)
{
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data)
{
if (mHelper == null) return;
if (!mHelper.handleActivityResult(requestCode, resultCode, data))
{
super.onActivityResult(requestCode, resultCode, data);
}
}
IabHelper.OnIabPurchaseFinishedListener mPurchaseFinishedListener = new IabHelper.OnIabPurchaseFinishedListener()
{
public void onIabPurchaseFinished(IabResult result, Purchase purchase)
{
if (mHelper == null) return;
if (result.isFailure())
{
// Handle error
return;
}
else if ((purchase.getSku().equals(ITEM_SKU)))
{
consumeItem();
}
}
};
public void consumeItem()
{
mHelper.queryInventoryAsync(mReceivedInventoryListener);
}
IabHelper.QueryInventoryFinishedListener mReceivedInventoryListener = new IabHelper.QueryInventoryFinishedListener()
{
public void onQueryInventoryFinished(IabResult result, Inventory inventory)
{
if (mHelper == null) return;
if (result.isFailure())
{
// Handle failure
}
else
{
mHelper.consumeAsync(inventory.getPurchase(ITEM_SKU), mConsumeFinishedListener);
}
}
};
IabHelper.OnConsumeFinishedListener mConsumeFinishedListener = new IabHelper.OnConsumeFinishedListener()
{
public void onConsumeFinished(Purchase purchase, IabResult result)
{
if (mHelper == null) return;
if (result.isSuccess())
{
Toast.makeText(InAppBillingActivity.this, "Thank you for your donation!!", Toast.LENGTH_LONG).show();
}
else
{
// handle error
}
}
};
Вопрос:
Однако я продолжаю получать ошибку E/IabHelper(13392): In-app billing error: Unable to buy item, Error response: 7:Item Already Owned
и что диалоговое окно оплаты в Google Play просто не появляется.
Я исследовал и обнаружил много подобных ситуаций, некоторые предложили подождать несколько минут, а затем покупка будет reset сама по себе, но я ждал почти час, но все равно сосет.
Я также обнаружил, что кто-то предлагает изменить IabResult public boolean isSuccess() { return mResponse == IabHelper.BILLING_RESPONSE_RESULT_OK; }
, чтобы вернуть также BILLING_RESPONSE_RESULT_ITEM_ALREADY_OWNED
as isSuccess = true, но я не знаю, как это изменить...
Как можно устранить проблему? Спасибо!!
Ответы
Ответ 1
Проверьте мой ниже код здесь:
Я не понимаю в вашем коде, почему вы использовали инвентаризацию запросов в слушателе завершения покупки. Метод ConsumeAsync() должен быть вызван, пока вы получаете sku так же, как запрошенный sku.
// Callback for when a purchase is finished
IabHelper.OnIabPurchaseFinishedListener mPurchaseFinishedListener = new IabHelper.OnIabPurchaseFinishedListener() {
public void onIabPurchaseFinished(IabResult result, Purchase purchase) {
Log.d(TAG, "Purchase finished: " + result + ", purchase: "
+ purchase);
if (result.isFailure()) {
complain("Error purchasing: " + result);
return;
}
if (!verifyDeveloperPayload(purchase)) {
complain("Error purchasing. Authenticity verification failed.");
return;
}
Log.d(TAG, "Purchase successful.");
if (purchase.getSku().equals(SKU_GAS)) {
// remove query inventory method from here and put consumeAsync() directly
mHelper.consumeAsync(purchase, mConsumeFinishedListener);
}
}
};
метод startSetup
//вы забыли вызвать метод инвентаризации запросов в методе startSetup.
mHelper.startSetup(new IabHelper.OnIabSetupFinishedListener() {
public void onIabSetupFinished(IabResult result) {
Log.d(TAG, "Setup finished.");
if (!result.isSuccess()) {
// Oh noes, there was a problem.
complain("Problem setting up in-app billing: " + result);
return;
}
// Hooray, IAB is fully set up. Now, let get an inventory of
// stuff we own.
Log.d(TAG, "Setup successful. Querying inventory.");
mHelper.queryInventoryAsync(mGotInventoryListener);
}
});
QueryInventoryFinishedListener
А также проверьте, является ли покупка условий той же, что и вы, не равна нулю, а полезная нагрузка разработчика также одинакова в вашем запросе слушатель инвентаря заканчивается.
if (gasPurchase != null && verifyDeveloperPayload(gasPurchase)){
//code
}
// Listener that called when we finish querying the items and
// subscriptions we own
IabHelper.QueryInventoryFinishedListener mGotInventoryListener = new IabHelper.QueryInventoryFinishedListener() {
public void onQueryInventoryFinished(IabResult result,
Inventory inventory) {
Log.d(TAG, "Query inventory finished.");
if (result.isFailure()) {
complain("Failed to query inventory: " + result);
return;
}
Log.d(TAG, "Query inventory was successful.");
/*
* Check for items we own. Notice that for each purchase, we check
* the developer payload to see if it correct! See
* verifyDeveloperPayload().
*/
// // Check for gas delivery -- if we own gas, we should fill up the
// tank immediately
Purchase gasPurchase = inventory.getPurchase(SKU_GAS);
if (gasPurchase != null && verifyDeveloperPayload(gasPurchase)) {
Log.d(TAG, "We have gas. Consuming it.");
mHelper.consumeAsync(inventory.getPurchase(SKU_GAS),
mConsumeFinishedListener);
return;
}
}
};
Объяснение, почему это происходит:
Всякий раз, когда вы покупаете потребительский товар, в Google Play Store управление не будет производиться с помощью приобретенных продуктов и других вещей на консоли Google Play. Поэтому нам нужно вызвать метод consumeAsync(). когда мы приобрели товар, магазин Google Play сохранил запись, и он был куплен за один раз и позволяет вам приобрести второй раз.
Надеюсь, что это решит вашу проблему.
Ответ 2
Вы приобрели "android.test.purchased", но не потребляли его. Однако, если вы забыли немедленно его потреблять, это не так просто. Мы можем ждать 14 дней. Поддельная покупка будет очищена автоматически. Но это неприемлемо.
Я потратил много времени на поиск решения:
Добавьте эту строку, чтобы получить информацию об отладке.
_iabHelper.enableDebugLogging(true, "TAG");
Запустите приложение. В LogCat вы увидите строку json, например
{"packageName":"com.example","orderId":"transactionId.android.test.purchased","productId":"android.test.purchased","developerPayload":"123","purchaseTime":0,"purchaseState":0,"purchaseToken":"inapp:com.example:android.test.purchased"}
Потребляйте его вручную (замените THAT_JSON_STRING на строку json)
Purchase purchase;
try {
purchase = new Purchase("inapp", THAT_JSON_STRING, "");
_iabHelper.consumeAsync(purchase, new OnConsumeFinishedListener() {
@Override
public void onConsumeFinished(Purchase purchase, IabResult result) {
Log.d("TAG", "Result: " + result);
}
});
} catch (JSONException e) {
e.printStackTrace();
}
_iabHelper - mHelper.
Ответ 3
Мне удалось "потреблять покупку", просто перезапустив устройство.
Ответ 4
Вы можете использовать Google Play "ФИНАНСОВЫЕ ОТЧЕТЫ" → "Посетите свою торговую учетную запись для получения более подробной информации" → "Заказы", чтобы просмотреть и отменить любой заказ, чтобы "использовать его".
Затем вам необходимо перезагрузить устройство. =)
Ответ 5
Я использую: реализацию 'com.android.billingclient: billing: 2.0.0', и в процессе покупки произошла та же ошибка.
- Дело в том, что перед запуском покупки мы должны потреблять ожидающие покупки.
см. фрагмент кода ниже:
List<String> skuList = new ArrayList();
skuList.add(THE_IAP_ID);
BillingClient.Builder billingClientBuilder = BillingClient.newBuilder(context).setListener(new PurchasesUpdatedListener() {
@Override
public void onPurchasesUpdated(BillingResult billingResult, @Nullable List<Purchase> purchases) {
// here we have to check the result ...
});
billingClientBuilder.enablePendingPurchases();
billingClient = billingClientBuilder.build();
billingClient.startConnection(new BillingClientStateListener() {
@Override
public void onBillingSetupFinished(BillingResult billingResult) {
if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK) {
// The BillingClient is ready - query purchases.
Purchase.PurchasesResult pr = billingClient.queryPurchases(BillingClient.SkuType.INAPP);
List<Purchase> pList = pr.getPurchasesList();
for (Purchase iitem : pList) {
ConsumeParams consumeParams = ConsumeParams.newBuilder()
.setPurchaseToken(iitem.getPurchaseToken())
.build();
billingClient.consumeAsync(consumeParams, consumeResponseListener);
}
// process the purchase
} else {
// cancelled or s.e.
...
}
}
С наилучшими пожеланиями, Вам весело :)