Integrowanie Biblioteki płatności w Google Play z aplikacją

Z tego artykułu dowiesz się, jak zintegrować Bibliotekę płatności w Google Play z aplikacją, aby zacząć sprzedawać produkty.

Okres obowiązywania zakupu

Oto typowy proces zakupu jednorazowego zakupu lub subskrypcji.

  1. Pokaż użytkownikom, co mogą kupić.
  2. Uruchom proces zakupu, aby użytkownik mógł go zaakceptować.
  3. Sprawdź zakup na swoim serwerze.
  4. Udostępnianie treści użytkownikowi.
  5. Potwierdź dostarczenie treści. W przypadku produktów konsumpcyjnych kup taki produkt, aby użytkownik mógł go kupić ponownie.

Subskrypcje są automatycznie odnawiane, dopóki nie zostaną anulowane. Subskrypcja może mieć te stany:

  • Aktywny: użytkownik ma dobrą opinię i ma dostęp do subskrypcji.
  • Anulowano:użytkownik anulował subskrypcję, ale nadal ma do niego dostęp.
  • W okresie prolongaty:użytkownik napotkał problem z płatnością, ale nadal ma dostęp, gdy Google ponawia próbę użycia formy płatności.
  • Wstrzymano:użytkownik miał problem z płatnością i nie ma już dostępu do konta, gdy Google ponawia próbę użycia formy płatności.
  • Wstrzymany: użytkownik wstrzymał dostęp i nie ma go do czasu wznowienia.
  • Wygasła:użytkownik anulował subskrypcję i utracił do niej dostęp. Konto użytkownika jest uznawane za rezygnowanego po wygaśnięciu.

Inicjowanie połączenia z Google Play

Pierwszym krokiem do przeprowadzenia integracji z systemem rozliczeniowym Google Play jest dodanie Biblioteki płatności w Google Play do aplikacji i zainicjowanie połączenia.

Dodawanie zależności Biblioteki płatności w Google Play

Dodaj zależność Biblioteki płatności w Google Play do pliku build.gradle aplikacji w ten sposób:

Odlotowy

dependencies {
    def billing_version = "6.2.0"

    implementation "com.android.billingclient:billing:$billing_version"
}

Kotlin

dependencies {
    val billing_version = "6.2.0"

    implementation("com.android.billingclient:billing:$billing_version")
}

Jeśli używasz Kotlin, moduł KTX Biblioteki płatności w Google Play zawiera rozszerzenia i obsługę współprogramów Kotlin, które umożliwiają pisanie idiomatycznego kotlin podczas korzystania z Biblioteki płatności w Google Play. Aby uwzględnić te rozszerzenia w projekcie, dodaj tę zależność do pliku build.gradle swojej aplikacji, jak pokazano poniżej:

Odlotowy

dependencies {
    def billing_version = "6.2.0"

    implementation "com.android.billingclient:billing-ktx:$billing_version"
}

Kotlin

dependencies {
    val billing_version = "6.2.0"

    implementation("com.android.billingclient:billing-ktx:$billing_version")
}

Inicjowanie klienta BillingClient

Po dodaniu zależności do Biblioteki płatności w Google Play musisz zainicjować instancję BillingClient. BillingClient to główny interfejs komunikacji między Biblioteką płatności w Google Play a resztą aplikacji. BillingClient udostępnia wygodne metody, zarówno synchroniczne, jak i asynchroniczne, do obsługi wielu typowych operacji rozliczeniowych. Zdecydowanie zalecamy, aby mieć jednocześnie otwarte 1 aktywne połączenie BillingClient, aby uniknąć wielu wywołań zwrotnych PurchasesUpdatedListener dla jednego zdarzenia.

Aby utworzyć BillingClient, użyj newBuilder(). Do funkcji newBuilder() można przekazać dowolny kontekst, a BillingClient pozyskuje kontekst z aplikacji. Oznacza to, że nie musisz martwić się o wycieki pamięci. Aby otrzymywać informacje o zakupach, musisz też wywołać metodę setListener(), przekazując odniesienie do metody PurchasesUpdatedListener. Ten detektor otrzymuje aktualizacje wszystkich zakupów w aplikacji.

Kotlin

private val purchasesUpdatedListener =
   PurchasesUpdatedListener { billingResult, purchases ->
       // To be implemented in a later section.
   }

private var billingClient = BillingClient.newBuilder(context)
   .setListener(purchasesUpdatedListener)
   .enablePendingPurchases()
   .build()

Java

private PurchasesUpdatedListener purchasesUpdatedListener = new PurchasesUpdatedListener() {
    @Override
    public void onPurchasesUpdated(BillingResult billingResult, List<Purchase> purchases) {
        // To be implemented in a later section.
    }
};

private BillingClient billingClient = BillingClient.newBuilder(context)
    .setListener(purchasesUpdatedListener)
    .enablePendingPurchases()
    .build();

Połącz z Google Play

Po utworzeniu BillingClient musisz połączyć się z Google Play.

Aby połączyć się z Google Play, zadzwoń pod numer startConnection(). Proces połączenia jest asynchroniczny i musisz wdrożyć BillingClientStateListener, aby otrzymać wywołanie zwrotne po zakończeniu konfiguracji klienta i przygotowaniu go do wysyłania kolejnych żądań.

Musisz też zaimplementować logikę ponawiania prób, by obsługiwać utracone połączenia z Google Play. Aby wdrożyć logikę ponawiania, zastąp metodę wywołania zwrotnego onBillingServiceDisconnected() i upewnij się, że BillingClient wywołuje metodę startConnection(), aby ponownie połączyć się z Google Play, zanim będziesz wysyłać kolejne żądania.

Ten przykład pokazuje, jak uruchomić połączenie i sprawdzić, czy jest gotowe do użycia:

Kotlin

billingClient.startConnection(object : BillingClientStateListener {
    override fun onBillingSetupFinished(billingResult: BillingResult) {
        if (billingResult.responseCode ==  BillingResponseCode.OK) {
            // The BillingClient is ready. You can query purchases here.
        }
    }
    override fun onBillingServiceDisconnected() {
        // Try to restart the connection on the next request to
        // Google Play by calling the startConnection() method.
    }
})

Java

billingClient.startConnection(new BillingClientStateListener() {
    @Override
    public void onBillingSetupFinished(BillingResult billingResult) {
        if (billingResult.getResponseCode() ==  BillingResponseCode.OK) {
            // The BillingClient is ready. You can query purchases here.
        }
    }
    @Override
    public void onBillingServiceDisconnected() {
        // Try to restart the connection on the next request to
        // Google Play by calling the startConnection() method.
    }
});

Pokaż produkty dostępne do kupienia

Po nawiązaniu połączenia z Google Play możesz wysyłać zapytania o dostępne produkty i wyświetlać je użytkownikom.

Zapytanie o szczegóły produktu to ważny krok przed wyświetleniem produktów użytkownikom, ponieważ powoduje wyświetlenie zlokalizowanych informacji o produktach. W przypadku subskrypcji zadbaj o to, aby wyświetlane produkty były zgodne ze wszystkimi zasadami Google Play.

Aby przesłać zapytanie o szczegóły produktu w aplikacji, wywołaj działanie queryProductDetailsAsync().

Aby obsługiwać wynik operacji asynchronicznej, musisz też określić odbiornik, który implementuje interfejs ProductDetailsResponseListener. Następnie możesz zastąpić wartość onProductDetailsResponse(), co spowoduje powiadomienie odbiornika o zakończeniu wykonywania zapytania, jak pokazano w tym przykładzie:

Kotlin

val queryProductDetailsParams =
    QueryProductDetailsParams.newBuilder()
        .setProductList(
            ImmutableList.of(
                Product.newBuilder()
                    .setProductId("product_id_example")
                    .setProductType(ProductType.SUBS)
                    .build()))
        .build()

billingClient.queryProductDetailsAsync(queryProductDetailsParams) {
    billingResult,
    productDetailsList ->
      // check billingResult
      // process returned productDetailsList
}

Java

QueryProductDetailsParams queryProductDetailsParams =
    QueryProductDetailsParams.newBuilder()
        .setProductList(
            ImmutableList.of(
                Product.newBuilder()
                    .setProductId("product_id_example")
                    .setProductType(ProductType.SUBS)
                    .build()))
        .build();

billingClient.queryProductDetailsAsync(
    queryProductDetailsParams,
    new ProductDetailsResponseListener() {
        public void onProductDetailsResponse(BillingResult billingResult,
                List<ProductDetails> productDetailsList) {
            // check billingResult
            // process returned productDetailsList
        }
    }
)

W zapytaniu o szczegóły produktu przekaż wystąpienie QueryProductDetailsParams, które określa listę ciągów identyfikatorów produktów utworzonych w Konsoli Google Play wraz z parametrem ProductType. Pole ProductType może mieć wartość ProductType.INAPP w przypadku produktów kupowanych raz lub ProductType.SUBS w przypadku subskrypcji.

Wykonywanie zapytań z użyciem rozszerzeń Kotlin

Jeśli używasz rozszerzeń Kotlin, możesz wysyłać zapytania o szczegóły produktu w aplikacji, wywołując funkcję rozszerzenia queryProductDetails().

queryProductDetails() korzysta z współprogramów Kotlin, więc nie musisz definiować osobnego odbiornika. Zamiast tego do momentu zakończenia wykonywania zapytania funkcja zostaje zawieszona, po czym można przetworzyć wynik:

suspend fun processPurchases() {
    val productList = listOf(
        QueryProductDetailsParams.Product.newBuilder()
            .setProductId("product_id_example")
            .setProductType(BillingClient.ProductType.SUBS)
            .build()
    )
    val params = QueryProductDetailsParams.newBuilder()
    params.setProductList(productList)

    // leverage queryProductDetails Kotlin extension function
    val productDetailsResult = withContext(Dispatchers.IO) {
        billingClient.queryProductDetails(params.build())
    }

    // Process the result.
}

Rzadko niektóre urządzenia nie obsługują ProductDetails i queryProductDetailsAsync(). Zazwyczaj są to spowodowane nieaktualnymi wersjami usług Google Play. Aby zapewnić prawidłową obsługę tego scenariusza, z przewodnika po migracji do Biblioteki płatności w Play 5 dowiesz się, jak korzystać z funkcji zgodności wstecznej.

Przetwórz wynik

Biblioteka płatności w Google Play przechowuje wyniki zapytania w obiektach List z ProductDetails. Następnie w każdym obiekcie ProductDetails na liście możesz wywołać szereg metod, aby wyświetlić istotne informacje o produkcie w aplikacji, np. jego cenę lub opis. Aby wyświetlić dostępne informacje o szczegółach produktu, zapoznaj się z listą metod w klasie ProductDetails.

Przed zaoferowaniem produktu do sprzedaży sprawdź, czy użytkownik nie jest już właścicielem tego produktu. Jeśli użytkownik ma produkt konsumpcyjny, który wciąż znajduje się w jego bibliotece, musi go wykorzystać, zanim będzie mógł kupić go ponownie.

Zanim zaoferujesz subskrypcję, sprawdź, czy użytkownik nie ma jeszcze subskrypcji. Pamiętaj też o tych kwestiach:

  • queryProductDetailsAsync() zwraca szczegóły produktu objętego subskrypcją i maksymalnie 50 ofert na subskrypcję.
  • queryProductDetailsAsync() zwraca tylko te oferty, które kwalifikują się do wyświetlenia użytkownikowi. Jeśli użytkownik spróbuje kupić ofertę, do której się nie kwalifikuje (np. w aplikacji wyświetla nieaktualną listę kwalifikujących się ofert), Google Play poinformuje go, że nie spełnia wymagań, a użytkownik może zamiast tego kupić abonament podstawowy.

Rozpoczynanie procesu zakupu

Aby wysłać prośbę o zakup z aplikacji, wywołaj metodę launchBillingFlow() z głównego wątku aplikacji. Ta metoda odwołuje się do obiektu BillingFlowParams zawierającego odpowiedni obiekt ProductDetails uzyskany z wywołania queryProductDetailsAsync(). Aby utworzyć obiekt BillingFlowParams, użyj klasy BillingFlowParams.Builder.

Kotlin

// An activity reference from which the billing flow will be launched.
val activity : Activity = ...;

val productDetailsParamsList = listOf(
    BillingFlowParams.ProductDetailsParams.newBuilder()
        // retrieve a value for "productDetails" by calling queryProductDetailsAsync()
        .setProductDetails(productDetails)
        // For One-time product, "setOfferToken" method shouldn't be called.
        // For subscriptions, to get an offer token, call ProductDetails.subscriptionOfferDetails()
        // for a list of offers that are available to the user
        .setOfferToken(selectedOfferToken)
        .build()
)

val billingFlowParams = BillingFlowParams.newBuilder()
    .setProductDetailsParamsList(productDetailsParamsList)
    .build()

// Launch the billing flow
val billingResult = billingClient.launchBillingFlow(activity, billingFlowParams)

Java

// An activity reference from which the billing flow will be launched.
Activity activity = ...;

ImmutableList<ProductDetailsParams> productDetailsParamsList =
    ImmutableList.of(
        ProductDetailsParams.newBuilder()
             // retrieve a value for "productDetails" by calling queryProductDetailsAsync()
            .setProductDetails(productDetails)
            // For one-time products, "setOfferToken" method shouldn't be called.
            // For subscriptions, to get an offer token, call
            // ProductDetails.subscriptionOfferDetails() for a list of offers
            // that are available to the user.
            .setOfferToken(selectedOfferToken)
            .build()
    );

BillingFlowParams billingFlowParams = BillingFlowParams.newBuilder()
    .setProductDetailsParamsList(productDetailsParamsList)
    .build();

// Launch the billing flow
BillingResult billingResult = billingClient.launchBillingFlow(activity, billingFlowParams);

Metoda launchBillingFlow() zwraca jeden z kilku kodów odpowiedzi wymienionych w BillingClient.BillingResponseCode. Sprawdź ten wynik, aby mieć pewność, że podczas uruchamiania procesu zakupu nie wystąpiły żadne błędy. Wartość BillingResponseCode OK oznacza udane uruchomienie.

Po pomyślnym wywołaniu launchBillingFlow() system wyświetli ekran zakupu w Google Play. Rysunek 1 przedstawia ekran zakupu subskrypcji:

na ekranie zakupu w Google Play widać subskrypcję, którą można kupić
Rysunek 1. Ekran zakupu w Google Play pokazuje subskrypcję, którą można kupić.

Google Play wywołuje onPurchasesUpdated(), aby przekazać wynik operacji zakupu detektorowi, który implementuje interfejs PurchasesUpdatedListener. Detektor jest określony za pomocą metody setListener() podczas inicjowania klienta.

Do obsługi możliwych kodów odpowiedzi musisz zaimplementować onPurchasesUpdated(). Ten przykład pokazuje, jak zastąpić onPurchasesUpdated():

Kotlin

override fun onPurchasesUpdated(billingResult: BillingResult, purchases: List<Purchase>?) {
   if (billingResult.responseCode == BillingResponseCode.OK && purchases != null) {
       for (purchase in purchases) {
           handlePurchase(purchase)
       }
   } else if (billingResult.responseCode == BillingResponseCode.USER_CANCELED) {
       // Handle an error caused by a user cancelling the purchase flow.
   } else {
       // Handle any other error codes.
   }
}

Java

@Override
void onPurchasesUpdated(BillingResult billingResult, List<Purchase> purchases) {
    if (billingResult.getResponseCode() == BillingResponseCode.OK
        && purchases != null) {
        for (Purchase purchase : purchases) {
            handlePurchase(purchase);
        }
    } else if (billingResult.getResponseCode() == BillingResponseCode.USER_CANCELED) {
        // Handle an error caused by a user cancelling the purchase flow.
    } else {
        // Handle any other error codes.
    }
}

Po pomyślnym dokonaniu zakupu w Google Play wyświetlany jest ekran z informacją o powodzeniu zakupu, podobnie jak na ilustracji 2.

ekran udanego zakupu w Google Play
Rysunek 2. Ekran potwierdzenia zakupu w Google Play.

Po pomyślnym dokonaniu zakupu generowany jest również token zakupu, czyli unikalny identyfikator reprezentujący użytkownika i identyfikator produktu zakupionego przez niego w aplikacji. Aplikacje mogą przechowywać token zakupu lokalnie, ale zalecamy przekazanie go na bezpieczny serwer backendu, na którym możesz zweryfikować zakup i chronić się przed oszustwami. Cały proces zostanie szczegółowo opisany w sekcji poniżej.

Użytkownik otrzyma też e-maila z potwierdzeniem transakcji zawierającym identyfikator zamówienia lub unikalny identyfikator transakcji. Użytkownicy otrzymują e-maila z unikalnym identyfikatorem zamówienia w przypadku każdego jednorazowego zakupu produktu, a także pierwszego zakupu subskrypcji oraz kolejnych cyklicznych automatycznych odnowień. Identyfikatora zamówienia możesz używać do zarządzania zwrotami środków w Konsoli Google Play.

pokazywać spersonalizowaną cenę,

Jeśli Twoją aplikację można rozpowszechniać wśród użytkowników w Unii Europejskiej, użyj metody setIsOfferPersonalized(), aby poinformować użytkowników, że cena produktu została spersonalizowana przez automatyczny proces podejmowania decyzji.

Ekran zakupu w Google Play z informacją, że cena została dostosowana do potrzeb użytkownika.
Rysunek 3. Ekran zakupu w Google Play z informacją, że cena została dostosowana do potrzeb użytkownika.

Konieczne jest skonsultowanie się z art. 6 (1) (ea) CRD dyrektywy w sprawie praw konsumentów (2011/83/UE), aby określić, czy cena, którą oferujesz użytkownikom, jest spersonalizowana.

setIsOfferPersonalized() przyjmuje wartość logiczną. Jeśli true, interfejs Google Play zawiera komunikat wyświetlany. Gdy false, interfejs pomija komunikat. Wartością domyślną jest false.

Więcej informacji znajdziesz w Centrum pomocy dla konsumentów.

Przetwarzanie zakupów

Gdy użytkownik dokona zakupu, Twoja aplikacja musi przetworzyć ten zakup. W większości przypadków aplikacja jest powiadamiana o zakupach na stronie PurchasesUpdatedListener. W niektórych przypadkach aplikacja zostanie powiadomiona o zakupach, wywołując metodę BillingClient.queryPurchasesAsync() zgodnie z opisem w sekcji Pobieranie zakupów.

Jeśli masz w swoim bezpiecznym backendzie klienta powiadomień dla deweloperów w czasie rzeczywistym, możesz rejestrować nowe zakupy, gdy otrzymasz alert subscriptionNotification lub oneTimeProductNotification (tylko w przypadku oczekujących zakupów) z alertem o nowym zakupie. Po otrzymaniu tych powiadomień wywołaj interfejs Google Play Developer API, aby uzyskać pełny stan i zaktualizować własny stan backendu.

Aplikacja powinna przetwarzać zakup w taki sposób:

  1. Zweryfikuj zakup.
  2. Dostarczenie treści użytkownikowi i potwierdzenie jej dostarczenia. Opcjonalnie oznacz produkt jako wykorzystany, aby użytkownik mógł go kupić ponownie.

Aby zweryfikować zakup, najpierw sprawdź, czy stan zakupu to PURCHASED. Jeśli zakup to PENDING, musisz go przetworzyć w sposób opisany w sekcji Obsługa oczekujących transakcji. W przypadku zakupów otrzymywanych od: onPurchasesUpdated() lub queryPurchasesAsync() musisz przeprowadzić dalszą weryfikację zakupu, aby sprawdzić jego wiarygodność, zanim aplikacja zacznie odpowiadać. Aby dowiedzieć się, jak prawidłowo zweryfikować zakup, przeczytaj artykuł Weryfikowanie zakupów przed przyznaniem uprawnień.

Po zweryfikowaniu zakupu aplikacja może przyznawać użytkownikowi uprawnienia. Konto użytkownika powiązane z zakupem można zidentyfikować za pomocą ProductPurchase.obfuscatedExternalAccountId zwróconego przez użytkownika Purchases.products:get w przypadku zakupów w aplikacji i SubscriptionPurchase.obfuscatedExternalAccountId zwróconego przez Purchases.subscriptions:get w przypadku subskrypcji po stronie serwera lub obfuscatedAccountId od Purchase.getAccountIdentifiers() po stronie klienta, jeśli podczas zakupu ustawiono wartość setObfuscatedAccountId.

Po przyznaniu uprawnienia aplikacja musi potwierdzić zakup. To potwierdzenie informuje Google Play, że masz uprawnienia do zakupu.

Proces przyznawania uprawnienia i potwierdzania zakupu zależy od tego, czy zakup jest urządzeniem zużywalnym, niezużywanym czy subskrypcją.

Produkty konsumpcyjne

W przypadku materiałów konsumpcyjnych, jeśli aplikacja ma bezpieczny backend, zalecamy korzystanie z Purchases.products:consume w celu niezawodnego korzystania z zakupów. Aby upewnić się, że zakup nie został już wykorzystany, sprawdź consumptionState w wyniku wywołania metody Purchases.products:get. Jeśli Twoja aplikacja jest przeznaczona tylko dla klienta bez backendu, użyj narzędzia consumeAsync() z Biblioteki płatności w Google Play. Obie metody spełniają wymóg potwierdzenia i wskazują, że aplikacja przyznała użytkownikowi takie uprawnienie. Dzięki tym metodom Twoja aplikacja może też udostępniać w aplikacji jednorazowy produkt odpowiadający danemu tokenowi zakupu, który jest dostępny do ponownego zakupu. W przypadku consumeAsync() musisz też przekazać obiekt, który implementuje interfejs ConsumeResponseListener. Ten obiekt obsługuje wynik operacji wykorzystania. Możesz zastąpić metodę onConsumeResponse(), która jest wywoływana przez Biblioteka płatności w Google Play po zakończeniu operacji.

Poniższy przykład pokazuje korzystanie z usługi przy użyciu Biblioteki płatności w Google Play przy użyciu powiązanego tokena zakupu:

Kotlin

suspend fun handlePurchase(purchase: Purchase) {
    // Purchase retrieved from BillingClient#queryPurchasesAsync or your PurchasesUpdatedListener.
    val purchase : Purchase = ...;

    // Verify the purchase.
    // Ensure entitlement was not already granted for this purchaseToken.
    // Grant entitlement to the user.

    val consumeParams =
        ConsumeParams.newBuilder()
            .setPurchaseToken(purchase.getPurchaseToken())
            .build()
    val consumeResult = withContext(Dispatchers.IO) {
        client.consumePurchase(consumeParams)
    }
}

Java

void handlePurchase(Purchase purchase) {
    // Purchase retrieved from BillingClient#queryPurchasesAsync or your PurchasesUpdatedListener.
    Purchase purchase = ...;

    // Verify the purchase.
    // Ensure entitlement was not already granted for this purchaseToken.
    // Grant entitlement to the user.

    ConsumeParams consumeParams =
        ConsumeParams.newBuilder()
            .setPurchaseToken(purchase.getPurchaseToken())
            .build();

    ConsumeResponseListener listener = new ConsumeResponseListener() {
        @Override
        public void onConsumeResponse(BillingResult billingResult, String purchaseToken) {
            if (billingResult.getResponseCode() == BillingResponseCode.OK) {
                // Handle the success of the consume operation.
            }
        }
    };

    billingClient.consumeAsync(consumeParams, listener);
}

Produkty, które się nie zużywają

Jeśli chcesz potwierdzać zakupy, których nie można wykorzystać, jeśli Twoja aplikacja ma bezpieczny backend, zalecamy użycie Purchases.products:acknowledge do wiarygodnego potwierdzania zakupów. Upewnij się, że zakup nie został wcześniej potwierdzony, sprawdzając element acknowledgementState w wyniku wywołania Purchases.products:get.

Jeśli Twoja aplikacja jest przeznaczona tylko dla klienta, użyj w niej metody BillingClient.acknowledgePurchase() z Biblioteki płatności w Google Play. Przed potwierdzeniem zakupu aplikacja powinna sprawdzić, czy została już potwierdzona, korzystając z metody isAcknowledged() w Bibliotece płatności w Google Play.

Ten przykład pokazuje, jak potwierdzić zakup przy użyciu Biblioteki płatności w Google Play:

Kotlin

val client: BillingClient = ...
val acknowledgePurchaseResponseListener: AcknowledgePurchaseResponseListener = ...

suspend fun handlePurchase() {
    if (purchase.purchaseState === PurchaseState.PURCHASED) {
        if (!purchase.isAcknowledged) {
            val acknowledgePurchaseParams = AcknowledgePurchaseParams.newBuilder()
                    .setPurchaseToken(purchase.purchaseToken)
            val ackPurchaseResult = withContext(Dispatchers.IO) {
               client.acknowledgePurchase(acknowledgePurchaseParams.build())
            }
        }
     }
}

Java

BillingClient client = ...
AcknowledgePurchaseResponseListener acknowledgePurchaseResponseListener = ...

void handlePurchase(Purchase purchase) {
    if (purchase.getPurchaseState() == PurchaseState.PURCHASED) {
        if (!purchase.isAcknowledged()) {
            AcknowledgePurchaseParams acknowledgePurchaseParams =
                AcknowledgePurchaseParams.newBuilder()
                    .setPurchaseToken(purchase.getPurchaseToken())
                    .build();
            client.acknowledgePurchase(acknowledgePurchaseParams, acknowledgePurchaseResponseListener);
        }
    }
}

subskrypcji,

Subskrypcje są obsługiwane podobnie jak produkty niezużywalne. Jeśli to możliwe, użyj interfejsu Purchases.subscriptions.acknowledge z interfejsu Google Play Developer API, aby skutecznie potwierdzić zakup z bezpiecznego backendu. Sprawdź, czy zakup nie został wcześniej potwierdzony, sprawdzając wartość acknowledgementState w zasobie zakupu na stronie Purchases.subscriptions:get. Możesz też potwierdzić subskrypcję przy użyciu BillingClient.acknowledgePurchase() w Bibliotece płatności w Google Play po zaznaczeniu pola isAcknowledged(). Wszystkie początkowe zakupy subskrypcji muszą zostać potwierdzone. Odnowienie subskrypcji nie wymaga potwierdzenia. Więcej informacji o tym, kiedy należy potwierdzić subskrypcję, znajdziesz w artykule Sprzedaż subskrypcji.

Pobieranie informacji o zakupach

Słuchanie aktualizacji zakupów za pomocą PurchasesUpdatedListener nie jest wystarczające do przetworzenia wszystkich zakupów przez aplikację. Aplikacja może nie być świadoma wszystkich zakupów dokonanych przez użytkownika. Oto kilka sytuacji, w których aplikacja może stracić informacje o produkcie lub być niezdolna do zakupu:

  • Problemy z siecią podczas zakupu: użytkownik dokonuje zakupu i otrzymuje potwierdzenie od Google, ale jego urządzenie traci połączenie z siecią, zanim otrzyma powiadomienie o zakupie w aplikacji PurchasesUpdatedListener.
  • Wiele urządzeń: użytkownik kupuje produkt na jednym urządzeniu, a potem spodziewa się, że zobaczy produkt po przełączeniu się na inne.
  • Obsługa zakupów zrobionych poza aplikacją: niektórych zakupów, np. skorzystania z promocji, można robić poza aplikacją.

W takiej sytuacji aplikacja musi wywoływać metodę BillingClient.queryPurchasesAsync() w metodzie onResume(), by mieć pewność, że wszystkie zakupy zostały przetworzone zgodnie z opisem w sekcji dotyczącej przetwarzania zakupów.

Z przykładu poniżej dowiesz się, jak pobrać informacje o zakupach subskrypcji użytkownika. Pamiętaj, że queryPurchasesAsync() zwraca tylko aktywne subskrypcje i nieużywane jednorazowe zakupy.

Kotlin

val params = QueryPurchasesParams.newBuilder()
               .setProductType(ProductType.SUBS)

// uses queryPurchasesAsync Kotlin extension function
val purchasesResult = billingClient.queryPurchasesAsync(params.build())

// check purchasesResult.billingResult
// process returned purchasesResult.purchasesList, e.g. display the plans user owns

Java

billingClient.queryPurchasesAsync(
    QueryPurchasesParams.newBuilder()
      .setProductType(ProductType.SUBS)
      .build(),
    new PurchasesResponseListener() {
      public void onQueryPurchasesResponse(BillingResult billingResult, List purchases) {
        // check billingResult
        // process returned purchase list, e.g. display the plans user owns

      }
    }
);

Pobieram historię zakupów

queryPurchaseHistoryAsync() zwraca ostatni zakup dokonany przez użytkownika w przypadku każdego produktu, nawet jeśli zakup wygasł, został anulowany lub wykorzystany.

Jeśli używasz rozszerzeń Kotlin, możesz użyć funkcji rozszerzenia queryPurchaseHistory().

Kotlin

val params = QueryPurchaseHistoryParams.newBuilder()
               .setProductType(ProductType.SUBS)

// uses queryPurchaseHistory Kotlin extension function
val purchaseHistoryResult = billingClient.queryPurchaseHistory(params.build())

// check purchaseHistoryResult.billingResult
// process returned purchaseHistoryResult.purchaseHistoryRecordList, e.g. display purchase

Java

billingClient.queryPurchaseHistoryAsync(
    QueryPurchaseHistoryParams.newBuilder()
        .setProductType(ProductType.SUBS)
        .build(),
    new PurchaseHistoryResponseListener() {
      public void onPurchaseHistoryResponse(
        BillingResult billingResult, List purchasesHistoryList) {
          // check billingResult
          // process returned purchase history list, e.g. display purchase history
        }
    }
);

Obsługa zakupów dokonanych poza aplikacją

Niektóre zakupy, np. wykorzystanie promocji, mogą mieć miejsce poza aplikacją. Gdy użytkownik dokonuje zakupu poza aplikacją, oczekuje, że w aplikacji wyświetli się odpowiednia wiadomość. Może też korzystać z jakiegoś mechanizmu powiadomień, który informuje użytkownika, że aplikacja prawidłowo otrzymała i przetworzyła zakup. Oto niektóre dopuszczalne mechanizmy:

  • Pokaż wyskakujące okienko w aplikacji.
  • umieścić wiadomość w polu wiadomości w aplikacji i wyraźnie poinformować, że w polu wiadomości znajduje się nowa wiadomość;
  • Użyj komunikatu z powiadomieniem dotyczącym systemu operacyjnego.

Pamiętaj, że po rozpoznaniu zakupu aplikacja może się znaleźć w dowolnym stanie. Może się nawet zdarzyć, że aplikacja nie zostanie zainstalowana w chwili zakupu. Użytkownicy oczekują, że po wznowieniu aplikacji otrzymają zakup niezależnie od jej stanu.

Zakupy musisz wykrywać niezależnie od stanu, w którym aplikacja została dokonana w momencie zakupu. Istnieją jednak pewne wyjątki, w których użytkownik nie powinien od razu powiadamiać użytkownika o otrzymaniu produktu. Na przykład:

  • Podczas części gry, w której wyświetlenie komunikatu może rozpraszać użytkownika. W takim przypadku użytkownik musi powiadomić o tym użytkownika po zakończeniu części działania.
  • W przerywnikach, gdzie pokazanie komunikatu może rozpraszać użytkownika. W takim przypadku musisz powiadomić użytkownika po zakończeniu sceny przerywnika.
  • Podczas początkowego samouczka i konfigurowania elementów gry przez użytkownika Zalecamy powiadamianie nowych użytkowników o nagrodzie natychmiast po uruchomieniu gry lub podczas wstępnej konfiguracji. Możesz jednak poczekać, aż użytkownik pojawi się w głównej sekwencji gry.

Podejmując decyzje o tym, kiedy i w jaki sposób powiadamiać użytkowników o zakupach zrobionych poza aplikacją, zawsze pamiętaj o użytkowniku. Jeśli użytkownik nie otrzyma powiadomienia od razu, może się zdezorientować i przestać korzystać z aplikacji, skontaktować się z zespołem pomocy lub narzekać na nie w mediach społecznościowych. Uwaga: usługa PurchasesUpdatedListener jest zarejestrowana w kontekście aplikacji na potrzeby obsługi aktualizacji dotyczących zakupów, w tym także zakupów inicjowanych poza aplikacją. Oznacza to, że jeśli nie istnieje odpowiedni proces zgłoszenia, aplikacja PurchasesUpdatedListener nie zostanie powiadomiona. Dlatego aplikacja powinna wywołać metodę BillingClient.queryPurchasesAsync() w metodzie onResume(), jak wspomniano w sekcji Pobierz informacje o zakupach.

Obsługa oczekujących transakcji

Google Play obsługuje transakcje oczekujące, czyli transakcje, które wymagają co najmniej jednego dodatkowego etapu między zainicjowaniem zakupu przez użytkownika a przetworzeniem formy płatności. Twoja aplikacja nie powinna zezwalać na tego typu zakupy, dopóki Google nie powiadomi Cię, że forma płatności użytkownika została obciążona.

Użytkownik może na przykład utworzyć zakup produktu w aplikacji za PENDING, wybierając gotówkę jako formę płatności. Następnie użytkownik może wybrać sklep stacjonarny, w którym zrealizuje transakcję i otrzyma kod zarówno w powiadomieniu, jak i e-mailem. Gdy użytkownik pojawi się w sklepie stacjonarnym, może wykorzystać kod u kasjera i zapłacić gotówką. Następnie Google powiadamia zarówno Ciebie, jak i użytkownika, że otrzymaliśmy środki. Aplikacja może następnie przyznać uprawnienia użytkownikowi.

Twoja aplikacja musi obsługiwać oczekujące transakcje, wywołując metodę enablePendingPurchases() podczas inicjowania aplikacji.

Gdy w aplikacji zostanie zakupiony nowy zakup (za pomocą PurchasesUpdatedListener lub w wyniku wywołania metody queryPurchasesAsync()), użyj metody getPurchaseState(), aby określić, czy stan zakupu to PURCHASED czy PENDING.

Jeśli aplikacja jest uruchomiona, gdy użytkownik dokona zakupu, PurchasesUpdatedListener zostanie ponownie wywołana, a PurchaseState to teraz PURCHASED. Na tym etapie aplikacja może przetworzyć zakup za pomocą standardowej metody przetwarzania jednorazowych zakupów. Aplikacja powinna też wywoływać metodę queryPurchasesAsync() w metodzie onResume() aplikacji w celu obsługi zakupów, które zostały przeniesione do stanu PURCHASED, gdy aplikacja nie była uruchomiona.

Aplikacja może też korzystać z powiadomień w czasie rzeczywistym dla deweloperów dotyczących oczekujących zakupów, nasłuchując OneTimeProductNotifications. Po przejściu z usługi PENDING na PURCHASED aplikacja otrzyma powiadomienie ONE_TIME_PRODUCT_PURCHASED. Jeśli zakup zostanie anulowany, aplikacja otrzyma powiadomienie ONE_TIME_PRODUCT_CANCELED. Może się tak zdarzyć, jeśli klient nie dokona płatności w wymaganym terminie. Otrzymując takie powiadomienia, możesz użyć interfejsu Google Play Developer API, który zawiera stan PENDING dla Purchases.products.

Szczegółowe instrukcje dotyczące testowania tego scenariusza znajdziesz w artykule Testowanie oczekujących zakupów.

Obsługa zakupów większej liczby sztuk produktu

Ta usługa jest obsługiwana w Bibliotece płatności w Google Play w wersji 4.0 i nowszych. Umożliwia klientom zakup więcej niż jednego produktu w aplikacji w ramach jednej transakcji poprzez określenie ilości produktu z koszyka. Twoja aplikacja ma obsługiwać zakupy obejmujące wiele sztuk produktu i przyznawać uprawnienia na podstawie określonej wielkości zakupu.

Aby można było kupować jednocześnie wiele sztuk tego samego produktu, mechanizm udostępniania aplikacji musi sprawdzać liczbę sztuk produktu. Dostęp do pola quantity możesz uzyskać przez jeden z tych interfejsów API:

Po dodaniu zasad umożliwiających zakup wielu sztuk produktu musisz włączyć funkcję wielu sztuk dla odpowiedniego produktu na stronie zarządzania produktami w aplikacji w Konsoli programisty Google Play.

Zapytanie dotyczące konfiguracji płatności użytkownika

getBillingConfigAsync() to kraj, w którym użytkownik korzysta z Google Play.

Możesz przesłać zapytanie dotyczące konfiguracji płatności użytkownika po utworzeniu BillingClient. Ten fragment kodu opisuje, jak wywołać metodę getBillingConfigAsync(). Przetwarzaj odpowiedź, stosując BillingConfigResponseListener. Ten detektor otrzymuje aktualizacje wszystkich zapytań dotyczących konfiguracji płatności zainicjowanych z Twojej aplikacji.

Jeśli zwrócony BillingResult nie zawiera błędów, możesz sprawdzić pole countryCode w obiekcie BillingConfig, aby uzyskać kraj Google Play użytkownika.

Kotlin

// Use the default GetBillingConfigParams.
val getBillingConfigParams = GetBillingConfigParams.newBuilder().build()
billingClient.getBillingConfigAsync(getBillingConfigParams,
    object : BillingConfigResponseListener {
        override fun onBillingConfigResponse(
            billingResult: BillingResult,
            billingConfig: BillingConfig?
        ) {
            if (billingResult.responseCode == BillingResponseCode.OK
                && billingConfig != null) {
                val countryCode = billingConfig.countryCode
                ...
            } else {
                // TODO: Handle errors
            }
        }
    })

Java

// Use the default GetBillingConfigParams.
GetBillingConfigParams getBillingConfigParams = GetBillingConfigParams.newBuilder().build();
billingClient.getBillingConfigAsync(getBillingConfigParams,
    new BillingConfigResponseListener() {
      public void onBillingConfigResponse(
          BillingResult billingResult, BillingConfig billingConfig) {
        if (billingResult.getResponseCode() == BillingResponseCode.OK
            && billingConfig != null) {
            String countryCode = billingConfig.getCountryCode();
            ...
         } else {
            // TODO: Handle errors
        }
      }
    });