2015-07-06 3 views
0

Некоторые из моих пользователей жалуются, что приобретенная им «премиальная версия» не восстанавливается.Как правильно восстановить покупку в приложении?

Я связался с одним из этих пользователей, и я отправил APK с дополнительными сообщениями. Вот что происходит:

  1. Когда пользователь попытается снова купить товар, он получает сообщение Unable to buy item (response: 7: Item already owned). Это ожидаемое сообщение, поскольку он уже купил его.
  2. Но когда пользователь пытается восстановить покупки с помощью того же SKU, он возвращает null/false.

Это обратный вызов от покупки:

@Override 
public void onIabPurchaseFinished(IabResult result, Purchase purchase) { 
    if (result.isFailure()) { 
     Log.d("debug", "failed - " + result.mMessage); 
     return; 
    } 

    Log.d("debug", "success"); 

    // continue with the purchase validation... 
} 

Это обратный вызов от восстановления покупок:

@Override 
public void onQueryInventoryFinished(IabResult result, Inventory inventory) { 
    if (result.isFailure()) { 
     Log.d("debug", "inventory: failed (" + result.mMessage + ")"); 
     return; 
    } 

    if (inventory.hasPurchase(SKU_PREMIUM)) { 
     Log.d("debug", "success - purchase restored"); 
    } 
    else { 
     Log.d("debug", "failure - no purchase found for this user"); 
    } 
} 

Пожалуйста, обратите внимание, что это происходит только с небольшим количеством пользователей, я тестировал несколько раз и по моим тестам я получаю сообщение success - purchase restored после запроса инвентаря.

Просто, чтобы быть ясным, я использую API v3, и этот SKU является управляемым элементом. Мне нужно проверить, покупал ли пользователь его или нет (я не хочу его потреблять).

+0

Вы имеете в виду 'inventory.hasPurchase (SKU_PREMIUM)' возвращает false? – xizzhu

+0

Точно, только на некоторых устройствах пользователя. Когда я тестирую свои устройства, он возвращает true. – thiagolr

ответ

0

К сожалению, это была моя ошибка.

Пострадавшие пользователи купили продукт в приложении на очень старой версии, которая имела различные полезные данные разработчика для того же SKU, в зависимости от того, где в приложении была совершена покупка.

Эти различные полезные данные разработчика были удалены из последних версий и, очевидно, нарушили предыдущие покупки.

0

Если вы используете версию v3 для покупки приложения, то API версии 3 поддерживает управляемые продукты in-app и подписки.

Управляемые в приложении продукты - это элементы, которые имеют информацию о собственности, отслеживаемые и управляемые Google Play. Когда пользователь приобретает управляемый элемент в приложении, Google Play сохраняет информацию о покупке для каждого элемента для каждого пользователя. Это позволяет в любой момент позже запросить Google Play, чтобы восстановить состояние предметов, приобретенных конкретным пользователем. Эта информация сохраняется на серверах Google Play, даже если пользователь удаляет приложение или меняет устройства.

Если вы используете API версии 3, вы также можете использовать , используя элементов в вашем приложении. Обычно вы будете использовать потребление предметов, которые можно приобрести несколько раз (например, в игре, валюте, магии или магических заклинаниях). После покупки управляемый элемент не может быть приобретен снова, пока вы не будете потреблять товар, отправив запрос на потребление в Google Play.

Употреблять элемент см ниже способом:

IabHelper.OnIabPurchaseFinishedListener mPurchaseFinishedListener = new IabHelper.OnIabPurchaseFinishedListener() { 
     public void onIabPurchaseFinished(IabResult result, Purchase purchase) { 
      Log.d(TAG, "Purchase finished: " + result + ", purchase: " + purchase); 

      // if we were disposed of in the meantime, quit. 
      if (mHelper == null) return; 

      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_PREMIUM)) { 
       //consumeItem(); 
       Constant.showProgressDialog(getActivity()); 
       mHelper.consumeAsync(purchase, mConsumeFinishedListener); 
      } 


     } 
    }; 

добавить Также этот метод для вашей деятельности

IabHelper.OnConsumeFinishedListener mConsumeFinishedListener = new IabHelper.OnConsumeFinishedListener() { 
     public void onConsumeFinished(Purchase purchase, IabResult result) { 
      Log.d(TAG, "Consumption finished. Purchase: " + purchase + ", result: " + result); 

      // if we were disposed of in the meantime, quit. 
      if (mHelper == null) return; 

      // We know this is the "gas" sku because it's the only one we consume, 
      // so we don't check which sku was consumed. If you have more than one 
      // sku, you probably should check... 
      if (result.isSuccess()) { 
       // successfully consumed, so we apply the effects of the item in our 
       // game world's logic, which in our case means filling the gas tank a bit 
       Log.d(TAG, "Consumption successful. Provisioning."); 

      } 
      else { 
       complain("Error while consuming: " + result); 
      } 

      Log.d(TAG, "End consumption flow."); 
     } 
    }; 

В классе IabHelper.java есть ниже метод:

int queryPurchases(Inventory inv, String itemType) throws JSONException, RemoteException { 
     // Query purchases 
     logDebug("Querying owned items, item type: " + itemType); 
     logDebug("Package name: " + mContext.getPackageName()); 
     boolean verificationFailed = false; 
     String continueToken = null; 

     do { 
      logDebug("Calling getPurchases with continuation token: " + continueToken); 
      Bundle ownedItems = mService.getPurchases(3, mContext.getPackageName(), 
        itemType, continueToken); 

      int response = getResponseCodeFromBundle(ownedItems); 
      logDebug("Owned items response: " + String.valueOf(response)); 
      if (response != BILLING_RESPONSE_RESULT_OK) { 
       logDebug("getPurchases() failed: " + getResponseDesc(response)); 
       return response; 
      } 
      if (!ownedItems.containsKey(RESPONSE_INAPP_ITEM_LIST) 
        || !ownedItems.containsKey(RESPONSE_INAPP_PURCHASE_DATA_LIST) 
        || !ownedItems.containsKey(RESPONSE_INAPP_SIGNATURE_LIST)) { 
       logError("Bundle returned from getPurchases() doesn't contain required fields."); 
       return IABHELPER_BAD_RESPONSE; 
      } 

      ArrayList<String> ownedSkus = ownedItems.getStringArrayList(
         RESPONSE_INAPP_ITEM_LIST); 
      ArrayList<String> purchaseDataList = ownedItems.getStringArrayList(
         RESPONSE_INAPP_PURCHASE_DATA_LIST); 
      ArrayList<String> signatureList = ownedItems.getStringArrayList(
         RESPONSE_INAPP_SIGNATURE_LIST); 

      for (int i = 0; i < purchaseDataList.size(); ++i) { 
       String purchaseData = purchaseDataList.get(i); 
       String signature = signatureList.get(i); 
       String sku = ownedSkus.get(i); 
       if (Security.verifyPurchase(mSignatureBase64, purchaseData, signature)) { 
        logDebug("Sku is owned: " + sku); 
        Purchase purchase = new Purchase(itemType, purchaseData, signature); 

        if (TextUtils.isEmpty(purchase.getToken())) { 
         logWarn("BUG: empty/null token!"); 
         logDebug("Purchase data: " + purchaseData); 
        } 

        // Record ownership and token 
        inv.addPurchase(purchase); 
       } 
       else { 
        logWarn("Purchase signature verification **FAILED**. Not adding item."); 
        logDebug(" Purchase data: " + purchaseData); 
        logDebug(" Signature: " + signature); 
        verificationFailed = true; 
       } 
      } 

      continueToken = ownedItems.getString(INAPP_CONTINUATION_TOKEN); 
      logDebug("Continuation token: " + continueToken); 
     } while (!TextUtils.isEmpty(continueToken)); 

     return verificationFailed ? IABHELPER_VERIFICATION_FAILED : BILLING_RESPONSE_RESULT_OK; 
    } 

В Это вы получите список принадлежащих ему товаров

+0

Спасибо за ваш ответ! Я использую API v3, и этот SKU является управляемым элементом. Мне нужно проверить, покупал ли пользователь его или нет (я не хочу его потреблять). – thiagolr

+0

вы также можете получить список принадлежащих ему предметов, связанных с вашим идентификатором на игровом автомате –

+0

Разве это не ответ onQueryInventoryFinished? – thiagolr

Смежные вопросы