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.
- Pokaż użytkownikom, co mogą kupić.
- Uruchom proces zakupu, aby użytkownik mógł go zaakceptować.
- Sprawdź zakup na swoim serwerze.
- Udostępnianie treści użytkownikowi.
- 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 = "7.0.0" implementation "com.android.billingclient:billing:$billing_version" }
Kotlin
dependencies { val billing_version = "7.0.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 = "7.0.0" implementation "com.android.billingclient:billing-ktx:$billing_version" }
Kotlin
dependencies { val billing_version = "7.0.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) // Configure other settings. .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) // Configure other settings. .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ć](https://developer.android.google.cn/static/images/google/play/billing/purchase-screen.png?authuser=6&hl=pl)
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](https://developer.android.google.cn/static/images/google/play/billing/purchase-success.png?authuser=6&hl=pl)
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.](https://developer.android.google.cn/static/images/google/play/billing/personalized-pricing.png?authuser=6&hl=pl)
Konieczne jest skonsultowanie się z art. 6 (1) (ea) CRD z 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, otrzymując subscriptionNotification
lub oneTimeProductNotification
z powiadomieniem 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:
- Zweryfikuj zakup.
- 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); } } }
Subskrypcje
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<Purchase> purchases) { // check billingResult // process returned purchase list, e.g. display the plans user owns } } );
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. 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.
Na przykład użytkownik może zainicjować transakcję, wybierając sklep stacjonarny, w którym będzie płacił później gotówką. Użytkownik otrzymuje kod zarówno w powiadomieniu, jak i e-mailem. Gdy użytkownik dotrze do sklepu stacjonarnego, może wykorzystać kod u kasjera i zapłacić gotówką. Następnie Google powiadamia zarówno Ciebie, jak i użytkownika o otrzymaniu płatności. Aplikacja może następnie przyznać uprawnienia użytkownikowi.
Wywołaj enablePendingPurchases()
w ramach inicjowania BillingClient
, aby włączyć transakcje oczekujące w aplikacji. Aplikacja musi włączyć i obsługiwać oczekujące transakcje w przypadku produktów jednorazowych. Zanim dodasz pomoc, zapoznaj się z cyklem życia zakupów w przypadku oczekujących transakcji.
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
. Upoważnienie należy przyznawać tylko wtedy, gdy stan to PURCHASED
.
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 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.
Po przejściu z usługi PENDING
na PURCHASED
Twój klient korzystający z powiadomień w czasie rzeczywistym dla deweloperów otrzyma powiadomienie ONE_TIME_PRODUCT_PURCHASED
lub SUBSCRIPTION_PURCHASED
. Jeśli zakup zostanie anulowany, otrzymasz powiadomienie ONE_TIME_PRODUCT_CANCELED
lub SUBSCRIPTION_PENDING_PURCHASE_CANCELED
. Może się tak zdarzyć, jeśli klient nie dokona płatności w wymaganym terminie. Pamiętaj, że zawsze możesz sprawdzić bieżący stan zakupu za pomocą interfejsu Google Play Developer API.
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:
getQuantity()
z Biblioteki płatności w Google Play.Purchases.products.quantity
z interfejsu Google Play Developer 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
}
}
});