Я пытаюсь интегрировать Библиотеку выставления счетов Google Play в наше приложение, чтобы продавать расходные материалы внутри приложения. Согласно официальному руководству по интеграции от разработчика android .com, использование метода consumerAsyn c при покупке позволит пользователю купить продукт снова. Однако для меня этот метод не всегда работает правильно, и пользователь не может купить продукт снова.
Кроме того, в случае сценария «медленная тестовая карта, платеж отклонен», платеж никогда не завершается а метод consumerAsyn c вообще не работает.
Я рассмотрел все похожие вопросы о переполнении стека, но решение не работает. Кроме того, официальный пример приложения от Google в основном ориентирован на модель подписки, поэтому это тоже не помогает.
Вы можете взглянуть на мою реализацию ниже:
public class PremiumMembershipActivity extends AppCompatActivity implements AcknowledgePurchaseResponseListener {
// Billing Client
private BillingClient billingClient;
private List<String> skuList = new ArrayList<String>();
private String sku = "buy_1000_credits";
private PurchasesUpdatedListener purchaseUpdateListener = new PurchasesUpdatedListener() {
@Override
public void onPurchasesUpdated(@NonNull BillingResult billingResult, @Nullable List<Purchase> list) {
methodForPurchaseUpdated(billingResult, list);
}
};
private ConsumeResponseListener consumeResponseListener = new ConsumeResponseListener() {
@Override
public void onConsumeResponse(BillingResult billingResult, @NotNull String s) {
if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK){
}
}
};
private AcknowledgePurchaseResponseListener acknowledgePurchaseResponseListener = new AcknowledgePurchaseResponseListener() {
@Override
public void onAcknowledgePurchaseResponse(@NotNull BillingResult billingResult) {
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_premium);
mBuyCredits = findViewById(R.id.premium_membership_buy_credits_card);
skuList.add(sku);
setupBillingClient();
}
private void setupBillingClient() {
billingClient = BillingClient
.newBuilder(PremiumMembershipActivity.this)
.enablePendingPurchases()
.setListener(purchaseUpdateListener)
.build();
billingClient.startConnection(new BillingClientStateListener() {
@Override
public void onBillingSetupFinished(@NotNull BillingResult billingResult) {
if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK) {
// The BillingClient is ready. You can query purchases here.
loadAllSkus();
}else if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.ERROR) {
Toast.makeText(PremiumMembershipActivity.this, R.string.buy_credits_added_error, Toast.LENGTH_SHORT).show();
}else if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.BILLING_UNAVAILABLE) {
Toast.makeText(PremiumMembershipActivity.this, R.string.buy_credits_client_unavailable, Toast.LENGTH_SHORT).show();
}
}
@Override
public void onBillingServiceDisconnected() {
// Try to restart the connection on the next request to
// Google Play by calling the startConnection() method.
Toast.makeText(PremiumMembershipActivity.this, R.string.buy_credits_client_disconnected, Toast.LENGTH_SHORT).show();
}
});
}
private void loadAllSkus() {
if (billingClient.isReady()){
SkuDetailsParams params = SkuDetailsParams.newBuilder()
.setSkusList(skuList)
.setType(BillingClient.SkuType.INAPP)
.build();
billingClient.querySkuDetailsAsync(params, new SkuDetailsResponseListener() {
@Override
public void onSkuDetailsResponse(@NotNull BillingResult billingResult, List<SkuDetails> list) {
if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK){
for (Object skuDetailsObject : list){
final SkuDetails skuDetails = (SkuDetails) skuDetailsObject;
if (skuDetails.getSku().equals(sku)){
//Only enable the Buy credits button when the required SKU (from Google Play Console Managed Products) is found
mBuyCredits.setEnabled(true);
mBuyCredits.setOnClickListener(buyCreditsOnClickListener(skuDetails));
}
}
}
}
});
}
else{
Toast.makeText(PremiumMembershipActivity.this, R.string.buy_credits_client_notready, Toast.LENGTH_SHORT).show();
}
}
private View.OnClickListener buyCreditsOnClickListener(final SkuDetails skuDetails) {
return new View.OnClickListener() {
@Override
public void onClick(View view) {
BillingFlowParams params = BillingFlowParams
.newBuilder()
.setSkuDetails(skuDetails)
.build();
billingClient.launchBillingFlow(PremiumMembershipActivity.this, params);
}
};
}
public void methodForPurchaseUpdated(BillingResult billingResult, @Nullable List<Purchase> list) {
int responseCode = billingResult.getResponseCode();
if (responseCode == BillingClient.BillingResponseCode.OK && list != null){
for (Purchase purchase : list) {
handlePurchase(purchase);
}
}else if (responseCode == BillingClient.BillingResponseCode.ITEM_ALREADY_OWNED) {
Toast.makeText(PremiumMembershipActivity.this, R.string.buy_item_owned, Toast.LENGTH_SHORT).show();
}else if (responseCode == BillingClient.BillingResponseCode.USER_CANCELED) {
Toast.makeText(PremiumMembershipActivity.this, R.string.buy_credits_added_cancel, Toast.LENGTH_SHORT).show();
}else if (responseCode == BillingClient.BillingResponseCode.SERVICE_TIMEOUT){
Toast.makeText(PremiumMembershipActivity.this, R.string.buy_credits_added_error, Toast.LENGTH_SHORT).show();
}else{
Toast.makeText(PremiumMembershipActivity.this, R.string.buy_credits_card_declined, Toast.LENGTH_SHORT).show();
}
}
public void handlePurchase(Purchase purchase) {
if (purchase.getSku().equals(sku) && purchase.getPurchaseState() == Purchase.PurchaseState.PURCHASED){
// Add Credits in user account in backend
addCreditsinBackend(1000);
// Add the purchase token to backend so transaction can be tracked
String token = purchase.getPurchaseToken();
addPurchaseToken(token);
// Consume the credits so they can be bought again
ConsumeParams consumeParams = ConsumeParams.newBuilder()
.setPurchaseToken(purchase.getPurchaseToken())
.build();
billingClient.consumeAsync(consumeParams, consumeResponseListener);
// Acknowledge the purchase if it hasn't already been acknowledged.
if (!purchase.isAcknowledged()) {
AcknowledgePurchaseParams acknowledgePurchaseParams = AcknowledgePurchaseParams.newBuilder()
.setPurchaseToken(purchase.getPurchaseToken())
.build();
billingClient.acknowledgePurchase(acknowledgePurchaseParams, acknowledgePurchaseResponseListener);
}
}
else if (purchase.getSku().equals(sku) && purchase.getPurchaseState() == Purchase.PurchaseState.PENDING){
Toast.makeText(PremiumMembershipActivity.this, R.string.buy_credits_card_slow, Toast.LENGTH_SHORT).show();
} else if (purchase.getSku().equals(sku) && purchase.getPurchaseState() == Purchase.PurchaseState.UNSPECIFIED_STATE){
Toast.makeText(PremiumMembershipActivity.this, R.string.buy_credits_card_unspecified, Toast.LENGTH_SHORT).show();
}
}
@Override
public void onAcknowledgePurchaseResponse(@NonNull BillingResult billingResult) {
}
private void addCreditsinBackend(int credits) {
//Code for adding credits to the users' account in the backend
}
private void addPurchaseToken (String token) {
//Code for adding PurchaseToken of the purchase to our backend
}
}