Android Биллинг; как решить "Не удалось найти предмет, который вы пытались приобрести" - PullRequest
0 голосов
/ 08 апреля 2020

Со всеми недавними изменениями в библиотеке биллинга Google и консоли разработчика сложно применить ответы 2014 года, поэтому я снова публикую эту топику c в надежде найти современный ответ.

Я пользуюсь Google Billing Library 2.2.0

Проблема: enter image description here


Я настроил лицензии: subscriptions


Я также настроил Лицензионное тестирование: license testing


Я также опубликовал сборку выпуска для внутренней тестовой дорожки (подписанную с сертификатом выпуска): release build


Пример соответствующего кода:

private final String SKU_TEST_PROD_1YR = "test_prod_id_1_year";
private final String SKU_TEST_PROD_6MN = "test_prod_id_6_month";
private final String SKU_TEST_PROD_1MN = "test_prod_id_1_month";
private BillingClient billingClient;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    List<String> iapProdIdList = Arrays.asList(SKU_TEST_PROD_1YR, SKU_TEST_PROD_6MN, SKU_TEST_PROD_1MN);
    setupBillingClient(this, iapProdIdList);
}

@Override
protected void onDestroy() {
    super.onDestroy();
    billingClient.endConnection();
}

private void setupBillingClient(Context context, List<String> iapProdList) {
    billingClient = BillingClient.newBuilder(context).setListener(this).build();
    billingClient.startConnection(new BillingClientStateListener() {
        @Override
        public void onBillingSetupFinished(BillingResult billingResult) {
            if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK) {
                loadAllSubscriptionProductIdDetails(iapProdList);
            }
        }

        @Override
        public void onBillingServiceDisconnected() { }
    });
}

private void loadAllSubscriptionProductIdDetails(List<String> iapProdList) {
    if (billingClient.isReady()) {
        SkuDetailsParams params = SkuDetailsParams.newBuilder().setSkusList(iapProdList).setType(BillingClient.SkuType.SUBS).build();

        billingClient.querySkuDetailsAsync(params, (billingResult, prodDetailList) -> {
            if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK && !prodDetailList.isEmpty()) {

                for (SkuDetails prodDetail : prodDetailList) {

                    String productSku = prodDetail.getSku();

                    switch(productSku) {
                        case SKU_TEST_PROD_1YR : {
                            final BillingFlowParams billingFlowParams = BillingFlowParams.newBuilder().setSkuDetails(prodDetail).build();
                            buttonIap1Yr.setOnClickListener(v -> {
                                // trigger purchase - Google needs the parent activity to overlay with their UI
                                billingClient.launchBillingFlow(this, billingFlowParams);
                            });
                            break;
                        }
                        case SKU_TEST_PROD_6MN : {
                            final BillingFlowParams billingFlowParams = BillingFlowParams.newBuilder().setSkuDetails(prodDetail).build();
                            buttonIap6mth.setOnClickListener(v -> {
                                // trigger purchase - Google needs the parent activity to overlay with their UI
                                billingClient.launchBillingFlow(this, billingFlowParams);
                            });
                            break;
                        }
                        case SKU_TEST_PROD_1MN : {
                            final BillingFlowParams billingFlowParams = BillingFlowParams.newBuilder().setSkuDetails(prodDetail).build();
                            buttonIap1mth.setOnClickListener(v -> {
                                // trigger purchase - Google needs the parent activity to overlay with their UI
                                billingClient.launchBillingFlow(this, billingFlowParams);
                            });
                            break;
                        }
                        default :
                            Toast.makeText(this, "Did not find Product in-app: "+ productSku, Toast.LENGTH_SHORT).show();
                    }
                }//end of FOR
            }//end of IF
        });
    } else {
        Toast.makeText(this, "billingClient is NOT ready", Toast.LENGTH_SHORT).show();
    }
}

@Override
public void onPurchasesUpdated(BillingResult billingResult, List<Purchase> list) {

    if (billingResult != null && list != null) {
        if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK) {
            for (Purchase purchase : list) {
                if(!purchase.isAcknowledged()) acknowledgePurchase(purchase.getPurchaseToken());
            }
        }
        else if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.USER_CANCELED) {
            Toast.makeText(this, "User Canceled", Toast.LENGTH_SHORT).show();
        }
        else if(billingResult.getResponseCode()== BillingClient.BillingResponseCode.ITEM_ALREADY_OWNED) {
            Toast.makeText(this, "Already Purchased", Toast.LENGTH_SHORT).show();
        }
    }
}

private void acknowledgePurchase(String purchaseToken) {
    AcknowledgePurchaseParams params = AcknowledgePurchaseParams.newBuilder().setPurchaseToken(purchaseToken).build();
    billingClient.acknowledgePurchase(params, billingResult -> {
        if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK) {
            Toast.makeText(this, "Purchase Acknowledged", Toast.LENGTH_SHORT).show();
        }
    });
}

Когда я нажимаю любую из кнопок [Купить подписку], billingClient.launchBillingFlow(this, billingFlowParams); срабатывает правильно, а SKU - правильно .

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

Ответы [ 2 ]

0 голосов
/ 09 апреля 2020

Код, который я разместил в моем вопросе, полностью функционален. Проблема была на 100% из-за конфигурации консоли разработчика:

Чтобы исправить это:

1) переведите приложение в альфа-версию как минимум (Внутренний тестовый трек не работает!)

2) нажмите [Управление] на альфа-треке и отправьте ссылку на согласие своим тестерам

3) Ваши тестеры скажут «когда» Я нажимаю на эту ссылку, в Play Store говорится, что приложение не найдено ". Скажите им, чтобы они расслабились на 30 минут - консоли Google нужно 30 минут, чтобы обработать эту сложность.

Попросите их загрузить раннюю версию, и IAP неожиданно сработает!

0 голосов
/ 08 апреля 2020

Я думаю, что у вашего loadAllSubscriptionProductIdDetails() метода неправильный дизайн.

Вы должны вызывать querySkuDetailsAsync() только тогда, когда пользователь щелкает, с единственным элементом в аргументе setSkusList(), только с тем, который будет приобретен и затем:

  @Override
  public void onSkuDetailsResponse(BillingResult billingResult, List<SkuDetails> skuDetailsList) {
       if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK && skuDetailsList.size() > 0) {
                    BillingFlowParams flowParams = BillingFlowParams.newBuilder()
                            .setSkuDetails(skuDetailsList.get(0))
                            .build();

                    billingClient.launchBillingFlow(activity, flowParams);

            }

      }
...