Google Play Billing Library in deine App integrieren

In diesem Thema wird beschrieben, wie Sie die Google Play Billing Library in Ihre App einbinden, um Produkte zu verkaufen.

Ablauf eines Kaufs

Hier sehen Sie einen typischen Kaufvorgang für einen Einmalkauf oder ein Abo.

  1. Zeigen Sie den Nutzern, was sie kaufen können.
  2. Starte den Kaufvorgang, damit der Nutzer den Kauf akzeptieren kann.
  3. Bestätige den Kauf auf deinem Server.
  4. Stellen Sie Nutzern Inhalte zur Verfügung.
  5. Bestätige die Zustellung der Inhalte. Verbrauchen Sie bei Verbrauchsgütern den Kauf, damit der Nutzer den Artikel noch einmal kaufen kann.

Abos werden automatisch verlängert, bis sie gekündigt werden. Ein Abo kann folgende Status haben:

  • Aktiv: Der Nutzer hat einen aktiven Status und Zugriff auf das Abo.
  • Abgebrochen:Der Nutzer hat die Mitgliedschaft beendet, hat aber noch bis zum Ablauf Zugriff.
  • Kulanzzeitraum: Der Nutzer hat ein Zahlungsproblem, hat aber weiterhin Zugriff, während Google die Zahlungsmethode noch einmal versucht.
  • In der Schwebe: Der Nutzer hat ein Zahlungsproblem und hat keinen Zugriff mehr, während Google die Zahlungsmethode noch einmal versucht.
  • Pausiert:Der Nutzer hat seinen Zugriff pausiert und hat erst wieder Zugriff, wenn er die Pausierung aufhebt.
  • Abgelaufen: Der Nutzer hat das Abo gekündigt und hat keinen Zugriff mehr darauf. Der Nutzer gilt nach Ablauf als abgewandert.

Verbindung mit Google Play initialisieren

Der erste Schritt zur Einbindung in das Abrechnungssystem von Google Play besteht darin, Ihrer App die Google Play Billing Library hinzuzufügen und eine Verbindung zu initialisieren.

Abhängigkeit von der Google Play Billing Library hinzufügen

Fügen Sie der build.gradle-Datei Ihrer App die Abhängigkeit „Google Play Billing Library“ hinzu, wie hier gezeigt:

Cool

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")
}

Wenn Sie Kotlin verwenden, enthält das KTX-Modul der Google Play Billing Library Kotlin-Erweiterungen und Unterstützung für Tasks, mit denen Sie bei Verwendung der Google Play Billing Library idiomatischen Kotlin-Code schreiben können. Um diese Erweiterungen in Ihr Projekt aufzunehmen, fügen Sie der Datei build.gradle Ihrer Anwendung die folgende Abhängigkeit hinzu:

Cool

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")
}

BillingClient initialisieren

Nachdem du eine Abhängigkeit von der Google Play Billing Library hinzugefügt hast, musst du eine BillingClient-Instanz initialisieren. BillingClient ist die Hauptschnittstelle für die Kommunikation zwischen der Google Play Billing Library und dem Rest Ihrer App. BillingClient bietet sowohl synchrone als auch asynchrone Methoden für viele gängige Abrechnungsvorgänge. Wir empfehlen dringend, immer nur eine aktive BillingClient-Verbindung zu haben, um mehrere PurchasesUpdatedListener-Callbacks für ein einzelnes Ereignis zu vermeiden.

Verwenden Sie newBuilder(), um eine BillingClient zu erstellen. Sie können einen beliebigen Kontext an newBuilder() übergeben. BillingClient verwendet diesen dann, um einen Anwendungskontext abzurufen. Das bedeutet, dass Sie sich keine Gedanken über Speicherlecks machen müssen. Wenn du aktuelle Informationen zu deinen Käufen erhalten möchtest, musst du außerdem setListener() aufrufen und einen Verweis auf ein PurchasesUpdatedListener-Objekt übergeben. Dieser Listener empfängt Updates für alle Käufe in Ihrer App.

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();

Mit Google Play verbinden

Nachdem Sie eine BillingClient erstellt haben, müssen Sie eine Verbindung zu Google Play herstellen.

Rufen Sie startConnection() auf, um eine Verbindung zu Google Play herzustellen. Der Verbindungsaufbau ist asynchron. Du musst BillingClientStateListener implementieren, um einen Callback zu erhalten, sobald die Einrichtung des Clients abgeschlossen ist und er weitere Anfragen stellen kann.

Sie müssen außerdem eine Wiederholungslogik implementieren, um den Verlust von Verbindungen zu Google Play zu verarbeiten. Wenn Sie die Wiederholungslogik implementieren möchten, überschreiben Sie die Rückrufmethode onBillingServiceDisconnected() und achten Sie darauf, dass BillingClient die Methode startConnection() aufruft, um eine neue Verbindung zu Google Play herzustellen, bevor weitere Anfragen gesendet werden.

Das folgende Beispiel zeigt, wie Sie eine Verbindung starten und testen, ob sie einsatzbereit ist:

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.
    }
});

Zum Kauf verfügbare Produkte anzeigen

Nachdem Sie eine Verbindung zu Google Play hergestellt haben, können Sie nach Ihren verfügbaren Produkten suchen und sie Ihren Nutzern anzeigen.

Das Abfragen von Produktdetails ist ein wichtiger Schritt, bevor deine Produkte für Nutzer angezeigt werden. Denn dadurch werden lokalisierte Produktinformationen zurückgegeben. Achten Sie bei Abos darauf, dass Ihre Produktdarstellung allen Play-Richtlinien entspricht.

Rufen Sie queryProductDetailsAsync() auf, um Details zu In-App-Produkten abzufragen.

Um das Ergebnis des asynchronen Vorgangs zu verarbeiten, müssen Sie auch einen Listener angeben, der die Schnittstelle ProductDetailsResponseListener implementiert. Sie können dann onProductDetailsResponse() überschreiben, wodurch der Listener benachrichtigt wird, wenn die Abfrage abgeschlossen ist, wie im folgenden Beispiel gezeigt:

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
        }
    }
)

Wenn Sie Produktdetails abfragen, übergeben Sie eine Instanz von QueryProductDetailsParams, die eine Liste von Produkt-ID-Strings angibt, die in der Google Play Console erstellt wurden, zusammen mit einer ProductType. ProductType kann entweder ProductType.INAPP für Einmalkaufprodukte oder ProductType.SUBS für Abos sein.

Abfragen mit Kotlin-Erweiterungen

Wenn Sie Kotlin-Erweiterungen verwenden, können Sie In-App-Produktdetails abfragen, indem Sie die Erweiterungsfunktion queryProductDetails() aufrufen.

queryProductDetails() nutzt Kotlin-Coroutinen, sodass Sie keinen separaten Listener definieren müssen. Stattdessen wird die Funktion angehalten, bis die Abfrage abgeschlossen ist. Anschließend können Sie das Ergebnis verarbeiten:

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.
}

In seltenen Fällen unterstützen einige Geräte ProductDetails und queryProductDetailsAsync() nicht. Das liegt in der Regel an veralteten Versionen der Google Play-Dienste. Informationen zur Verwendung von Abwärtskompatibilitätsfunktionen finden Sie in der Migrationsanleitung zu Play Billing Library 5, damit dieses Szenario richtig unterstützt wird.

Ergebnis verarbeiten

Die Google Play Billing Library speichert die Abfrageergebnisse in einer List von ProductDetails-Objekten. Sie können dann für jedes ProductDetails-Objekt in der Liste verschiedene Methoden aufrufen, um relevante Informationen zu einem In-App-Produkt aufzurufen, z. B. den Preis oder die Beschreibung. Eine Liste der verfügbaren Produktdetails findest du in der Liste der Methoden in der Klasse ProductDetails.

Bevor du einen Artikel zum Verkauf anbietest, solltest du prüfen, ob der Nutzer den Artikel bereits besitzt. Wenn der Nutzer einen Verbrauchsartikel hat, der sich noch in seiner Artikelbibliothek befindet, muss er ihn aufbrauchen, bevor er ihn noch einmal kaufen kann.

Bevor du ein Abo anbietest, solltest du prüfen, ob der Nutzer bereits ein Abo hat. Beachten Sie außerdem Folgendes:

  • queryProductDetailsAsync() gibt Aboproduktdetails und maximal 50 Angebote pro Abo zurück.
  • queryProductDetailsAsync() gibt nur Angebote zurück, für die der Nutzer berechtigt ist. Wenn der Nutzer versucht, ein Angebot zu kaufen, für das er nicht infrage kommt (z. B. wenn in der App eine veraltete Liste der infrage kommenden Angebote angezeigt wird), wird er von Google Play darüber informiert, dass er nicht berechtigt ist. Er kann dann stattdessen das Basis-Abo kaufen.

Kaufvorgang starten

Wenn du eine Kaufanfrage über deine App starten möchtest, rufe die Methode launchBillingFlow() aus dem Hauptthread deiner App auf. Diese Methode nimmt eine Referenz auf ein BillingFlowParams-Objekt an, das das relevante ProductDetails-Objekt enthält, das durch Aufrufen von queryProductDetailsAsync() abgerufen wurde. Verwenden Sie die Klasse BillingFlowParams.Builder, um ein BillingFlowParams-Objekt zu erstellen.

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);

Die launchBillingFlow()-Methode gibt einen der in BillingClient.BillingResponseCode aufgeführten Antwortcodes zurück. Prüfen Sie dieses Ergebnis, um sicherzustellen, dass beim Starten des Kaufvorgangs keine Fehler aufgetreten sind. Ein BillingResponseCode von OK gibt an, dass die Einführung erfolgreich war.

Bei einem erfolgreichen Aufruf von launchBillingFlow() zeigt das System den Google Play-Kaufbildschirm an. Abbildung 1 zeigt einen Kaufbildschirm für ein Abo:

Auf dem Google Play-Kaufbildschirm wird ein Abo angezeigt, das zum Kauf verfügbar ist.
Abbildung 1. Auf dem Google Play-Kaufbildschirm wird ein verfügbares Abo angezeigt.

Google Play ruft onPurchasesUpdated() auf, um das Ergebnis des Kaufvorgangs an einen Listener zu senden, der die PurchasesUpdatedListener-Schnittstelle implementiert. Der Listener wird mit der Methode setListener() angegeben, wenn du deinen Client initialisiert hast.

Sie müssen onPurchasesUpdated() implementieren, um mögliche Antwortcodes zu verarbeiten. Im folgenden Beispiel wird gezeigt, wie onPurchasesUpdated() überschrieben wird:

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.
    }
}

Bei einem erfolgreichen Kauf wird bei Google Play ein Bildschirm mit dem Kauferfolg angezeigt, ähnlich wie in Abbildung 2.

Google Play-Bildschirm „Kauf erfolgreich“
Abbildung 2: Google Play-Bildschirm mit dem Kauferfolg.

Bei einem erfolgreichen Kauf wird außerdem ein Kauftoken generiert. Das ist eine eindeutige Kennung, die den Nutzer und die Produkt-ID des gekauften In-App-Produkts angibt. Das Kauftoken kann lokal in der App gespeichert werden. Wir empfehlen jedoch, das Token an Ihren sicheren Back-End-Server zu senden, wo Sie den Kauf dann bestätigen und Betrug verhindern können. Dieser Vorgang wird im folgenden Abschnitt näher beschrieben.

Der Nutzer erhält außerdem per E-Mail einen Beleg mit einer Bestell-ID oder einer eindeutigen Transaktions-ID. Nutzer erhalten eine E-Mail mit einer eindeutigen Bestell-ID für jeden einmaligen Produktkauf sowie für den ersten Abokauf und die nachfolgenden automatischen Verlängerungen. Mit der Bestell-ID kannst du Erstattungen in der Google Play Console verwalten.

Personalisierten Preis angeben

Wenn Ihre App für Nutzer in der Europäischen Union verfügbar ist, müssen Sie Nutzern mithilfe der Methode setIsOfferPersonalized() mitteilen, dass der Preis eines Artikels mithilfe automatisierter Entscheidungsfindung personalisiert wurde.

Der Google Play-Kaufbildschirm, auf dem angegeben ist, dass der Preis für den Nutzer angepasst wurde.
Abbildung 3: Der Google Play-Kaufbildschirm, auf dem angegeben ist, dass der Preis für den Nutzer angepasst wurde.

Sie müssen Artikel 6 (1) (ea) CRD der Richtlinie zum Verbraucherrecht 2011/83/EU, um festzulegen, ob der von dir angebotene Preis personalisiert wurde.

setIsOfferPersonalized() nimmt eine boolesche Eingabe an. Wenn true, enthält die Google Play-Benutzeroberfläche die Offenlegung. Bei false wird die Offenlegung in der Benutzeroberfläche weggelassen. Der Standardwert ist false.

Weitere Informationen finden Sie in der Hilfe für Verbraucher.

Käufe werden verarbeitet

Sobald ein Nutzer einen Kauf abgeschlossen hat, muss Ihre App diesen Kauf verarbeiten. In den meisten Fällen wird deine App über deine PurchasesUpdatedListener über Käufe informiert. In einigen Fällen wird Ihre App jedoch über Käufe informiert, indem BillingClient.queryPurchasesAsync() aufgerufen wird, wie unter Käufe abrufen beschrieben.

Wenn Sie in Ihrem sicheren Backend einen Client für Entwicklerbenachrichtigungen in Echtzeit haben, können Sie neue Käufe registrieren, indem Sie eine subscriptionNotification oder eine oneTimeProductNotification erhalten, die Sie über einen neuen Kauf informiert. Rufen Sie nach Erhalt dieser Benachrichtigungen die Google Play Developer API auf, um den vollständigen Status abzurufen und Ihren eigenen Backend-Status zu aktualisieren.

In Ihrer App sollte ein Kauf so verarbeitet werden:

  1. Bestätigen Sie den Kauf.
  2. Stellen Sie dem Nutzer Inhalte zur Verfügung und bestätigen Sie die Zustellung der Inhalte. Optional können Sie den Artikel als verbraucht markieren, damit der Nutzer ihn noch einmal kaufen kann.

Prüfe zuerst, ob der Kaufstatus PURCHASED lautet. Wenn der Kauf PENDING ist, solltest du ihn wie unter Umgang mit ausstehenden Transaktionen beschrieben abwickeln. Bei Käufen über onPurchasesUpdated() oder queryPurchasesAsync() sollten Sie den Kauf zusätzlich prüfen, um seine Legitimität zu bestätigen, bevor Ihre App die Berechtigung gewährt. Informationen zur ordnungsgemäßen Bestätigung eines Kaufs findest du unter Käufe bestätigen, bevor Berechtigungen gewährt werden.

Sobald Sie den Kauf bestätigt haben, kann Ihre App dem Nutzer die Berechtigung gewähren. Das mit dem Kauf verknüpfte Nutzerkonto kann anhand der ProductPurchase.obfuscatedExternalAccountId identifiziert werden, die von Purchases.products:get für In-App-Produktkäufe und der SubscriptionPurchase.obfuscatedExternalAccountId zurückgegeben wird, die von Purchases.subscriptions:get für Abos auf der Serverseite oder der obfuscatedAccountId von Purchase.getAccountIdentifiers() auf der Clientseite zurückgegeben wird, sofern beim Kauf eine mit setObfuscatedAccountId festgelegt wurde.

Nachdem die Berechtigung erteilt wurde, muss der Kauf durch deine App bestätigt werden. Das bedeutet, dass Google Play darüber informiert wird, dass du den Kauf genehmigt hast.

Wie du die Berechtigung erteilst und den Kauf bestätigst, hängt davon ab, ob es sich beim Kauf um einen kurzfristig nutzbaren, nicht nutzbaren oder einen Abokauf handelt.

Verbrauchsprodukte

Wenn Ihre App ein sicheres Back-End hat, empfehlen wir für Verbrauchsmaterialien die Verwendung von Purchases.products:consume, um Käufe zuverlässig zu nutzen. Prüfe, ob der Kauf bereits in Anspruch genommen wurde. Dazu musst du den Wert consumptionState aus dem Ergebnis des Aufrufs von Purchases.products:get prüfen. Wenn deine App nur clientseitig und ohne Back-End ausgeführt wird, verwende consumeAsync() aus der Google Play Billing Library. Beide Methoden erfüllen die Bestätigungsanforderung und geben an, dass Ihre App dem Nutzer eine Berechtigung gewährt hat. Mit diesen Methoden kann Ihre App das einmalige Produkt, das dem eingegebenen Kauftoken entspricht, auch noch einmal zum Kauf anbieten. Mit consumeAsync() müssen Sie auch ein Objekt übergeben, das die Schnittstelle ConsumeResponseListener implementiert. Dieses Objekt verarbeitet das Ergebnis des Verbrauchsvorgangs. Sie können die Methode onConsumeResponse() überschreiben, die von der Google Play Billing Library aufgerufen wird, wenn der Vorgang abgeschlossen ist.

Das folgende Beispiel zeigt, wie ein Produkt mit der Google Play Billing Library und dem zugehörigen Kauftoken genutzt wird:

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);
}

Nicht konsumierbare Produkte

Wenn Ihre App ein sicheres Back-End hat, empfehlen wir, Purchases.products:acknowledge zu verwenden, um Käufe zuverlässig zu bestätigen. Prüfe, ob der Kauf bereits bestätigt wurde. Dazu prüfe den Wert acknowledgementState im Ergebnis des Aufrufs von Purchases.products:get.

Wenn deine App nur Client ist, verwende BillingClient.acknowledgePurchase() aus der Google Play Billing Library in deiner App. Bevor du einen Kauf bestätigst, sollte deine App mithilfe der isAcknowledged()-Methode in der Google Play Billing Library prüfen, ob er bereits bestätigt wurde.

Das folgende Beispiel zeigt, wie du einen Kauf über die Google Play Billing Library bestätigst:

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);
        }
    }
}

Abos

Abos werden ähnlich wie nicht verbrauchbare Artikel behandelt. Verwenden Sie nach Möglichkeit Purchases.subscriptions.acknowledge aus der Google Play Developer API, um den Kauf über Ihr sicheres Backend zuverlässig zu bestätigen. Prüfe, ob der Kauf noch nicht bestätigt wurde. Dazu musst du in der Kaufressource von Purchases.subscriptions:get die acknowledgementState prüfen. Andernfalls kannst du ein Abo mit BillingClient.acknowledgePurchase() in der Google Play Billing Library bestätigen, nachdem du isAcknowledged() geprüft hast. Alle ersten Abokäufe müssen bestätigt werden. Aboverlängerungen müssen nicht bestätigt werden. Weitere Informationen dazu, wann Abos bestätigt werden müssen, finden Sie im Hilfeartikel Abos verkaufen.

Käufe werden abgerufen

Es reicht nicht aus, Kaufaktualisierungen über einen PurchasesUpdatedListener zu empfangen, um sicherzustellen, dass Ihre App alle Käufe verarbeitet. Möglicherweise sind in Ihrer App nicht alle Käufe eines Nutzers erfasst. Hier sind einige Szenarien, in denen Ihre App den Überblick verlieren oder Käufe nicht erkennen kann:

  • Netzwerkprobleme während des Kaufs: Ein Nutzer schließt einen Kauf ab und erhält eine Bestätigung von Google, aber die Netzwerkverbindung des Geräts wird unterbrochen, bevor es über die PurchasesUpdatedListener eine Benachrichtigung über den Kauf erhält.
  • Mehrere Geräte: Ein Nutzer kauft einen Artikel auf einem Gerät und erwartet, dass er den Artikel auch sieht, wenn er das Gerät wechselt.
  • Käufe außerhalb Ihrer App verarbeiten: Einige Käufe, z. B. die Inanspruchnahme von Angeboten, können außerhalb Ihrer App erfolgen.

Damit Sie diese Situationen bewältigen können, muss Ihre App in der onResume()-Methode BillingClient.queryPurchasesAsync() aufrufen, damit alle Käufe wie unter Käufe verarbeiten beschrieben verarbeitet werden.

Das folgende Beispiel zeigt, wie du die Abokäufe eines Nutzers abrufen kannst. Hinweis: Mit queryPurchasesAsync() werden nur aktive Abos und nicht in Anspruch genommene Einmalkäufe zurückgegeben.

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

      }
    }
);

Käufe außerhalb Ihrer App verarbeiten

Einige Käufe können außerhalb Ihrer App erfolgen, z. B. das Einlösen von Angeboten oder Erinnerungen an nicht abgeschlossene Käufe für In-App-Produkte in Google Play Spiele. Wenn ein Nutzer einen Kauf außerhalb deiner App tätigt, erwartet er, dass in deiner App eine In-App-Nachricht angezeigt wird, oder er verwendet eine Art Benachrichtigungsmechanismus, um den Nutzer darüber zu informieren, dass die App den Kauf korrekt erhalten und verarbeitet hat. Zulässige Mechanismen sind:

  • Ein In-App-Pop-up anzeigen.
  • Senden Sie die Nachricht in ein In-App-Nachrichtenfeld und geben Sie deutlich an, dass sich eine neue Nachricht im Nachrichtenfeld der App befindet.
  • Verwenden Sie eine Betriebssystembenachrichtigung.

Beachten Sie, dass sich Ihre App in einem beliebigen Zustand befinden kann, wenn der Kauf erkannt wird. Es ist sogar möglich, dass Ihre App zum Zeitpunkt des Kaufs noch nicht installiert war. Nutzer erwarten, dass sie ihren Kauf erhalten, wenn sie die App fortsetzen, unabhängig vom Status der App.

Sie müssen Käufe unabhängig vom Status der App zum Zeitpunkt des Kaufs erkennen. Es gibt jedoch einige Ausnahmen, in denen es akzeptabel ist, den Nutzer nicht sofort über den Erhalt des Artikels zu informieren. Beispiel:

  • Während des Action-Teils eines Spiels, da eine Meldung den Nutzer ablenken könnte. In diesem Fall müssen Sie den Nutzer nach Abschluss des Aktionsteils benachrichtigen.
  • In Zwischensequenzen, in denen eine Nachricht den Nutzer ablenken könnte In diesem Fall müssen Sie den Nutzer nach dem Ende der Zwischensequenz benachrichtigen.
  • Während der ersten Anleitung und der Nutzereinrichtung des Spiels Wir empfehlen, neue Nutzer sofort nach dem Öffnen des Spiels oder während der Ersteinrichtung über die Prämie zu informieren. Es ist jedoch akzeptabel, mit der Benachrichtigung zu warten, bis die Hauptsequenz des Spiels verfügbar ist.

Behalte immer den Nutzer im Hinterkopf, wenn er entscheidet, wann und wie er über Käufe außerhalb deiner App informiert werden soll. Wenn ein Nutzer nicht sofort eine Benachrichtigung erhält, könnte er verwirrt sein und deine App nicht mehr verwenden, sich an den Nutzersupport wenden oder sich in sozialen Medien darüber beschweren.

Erinnerungen an abgebrochene Einkäufe auf der Startseite von Google Play Spiele (standardmäßig aktiviert)

Für Spieleentwickler, die mit In-App-Käufen Einnahmen erzielen, können in der Google Play Console aktive Artikelnummern (SKUs) außerhalb der App verkauft werden. Mit der Funktion „Einkaufswagen verlassen“ werden Nutzer dazu ermuntert, zuvor abgebrochene Käufe im Google Play Store abzuschließen. Diese Käufe erfolgen außerhalb Ihrer App, im Google Play Games-Dashboard im Google Play Store.

Diese Funktion ist standardmäßig aktiviert, damit Nutzer dort weitermachen können, wo sie aufgehört haben, und Entwickler helfen, den Umsatz zu maximieren. Sie können diese Funktion für Ihre App jedoch deaktivieren, indem Sie das Formular zur Deaktivierung der Funktion „Einkaufswagen verlassen“ einreichen. Best Practices zum Verwalten von Artikelnummern in der Google Play Console findest du unter In-App-Produkte erstellen.

Auf den folgenden Bildern sehen Sie, wie die Erinnerung an den Einkaufswagen im Google Play Store angezeigt wird:

Auf dem Google Play Store-Bildschirm wird für einen zuvor abgebrochenen Kauf eine Aufforderung zum Kauf angezeigt.
Abbildung 2: Auf dem Google Play Store-Bildschirm wird für einen zuvor abgebrochenen Kauf eine Aufforderung zum Kauf angezeigt.

Auf dem Google Play Store-Bildschirm wird eine Kaufaufforderung für einen zuvor abgebrochenen Kauf angezeigt.
Abbildung 3: Auf dem Google Play Store-Bildschirm wird eine Kaufaufforderung für einen zuvor abgebrochenen Kauf angezeigt.

Umgang mit ausstehenden Transaktionen

Google Play unterstützt ausstehende Transaktionen, also Transaktionen, die einen oder mehrere zusätzliche Schritte erfordern, zwischen dem Zeitpunkt, an dem ein Nutzer einen Kauf auslöst, und dem Zeitpunkt, an dem die Zahlungsmethode für den Kauf verarbeitet wird. Ihre App sollte Nutzern erst dann Zugriff auf diese Arten von Käufen gewähren, wenn Google Sie darüber informiert hat, dass die Zahlungsmethode des Nutzers erfolgreich belastet wurde.

Beispielsweise kann ein Nutzer eine Transaktion initiieren, indem er ein Ladengeschäft auswählt, in dem er später mit Bargeld bezahlt. Der Nutzer erhält einen Code sowohl per Benachrichtigung als auch per E-Mail. Wenn der Nutzer im Geschäft ankommt, kann er den Code an der Kasse einlösen und bar bezahlen. Google benachrichtigt dann sowohl Sie als auch den Nutzer darüber, dass die Zahlung eingegangen ist. Ihre App kann dem Nutzer dann eine Berechtigung gewähren.

Rufen Sie enablePendingPurchases() im Rahmen der Initialisierung von BillingClient auf, um ausstehende Transaktionen für Ihre App zu aktivieren. Ihre App muss ausstehende Transaktionen für Einmalkaufprodukte aktivieren und unterstützen. Bevor du Unterstützung hinzufügst, solltest du dich mit dem Kaufzyklus für ausstehende Transaktionen vertraut machen.

Wenn Ihre App einen neuen Kauf erhält, entweder über PurchasesUpdatedListener oder durch Aufrufen von queryPurchasesAsync(), verwenden Sie die Methode getPurchaseState(), um zu ermitteln, ob der Kaufstatus PURCHASED oder PENDING ist. Sie sollten die Berechtigung nur gewähren, wenn der Status PURCHASED ist.

Wenn Ihre App ausgeführt wird, wenn der Nutzer den Kauf abschließt, wird PurchasesUpdatedListener noch einmal aufgerufen und PurchaseState ist jetzt PURCHASED. An diesem Punkt kann Ihre App den Kauf mit der Standardmethode für die Verarbeitung von Käufen verarbeiten. Ihre App sollte auch queryPurchasesAsync() in der onResume()-Methode Ihrer App aufrufen, um Käufe zu verarbeiten, die in den Status PURCHASED gewechselt sind, während Ihre App nicht aktiv war.

Wenn der Kauf von PENDING zu PURCHASED übergeht, erhält Ihr Kunde mit Entwicklerbenachrichtigungen in Echtzeit eine ONE_TIME_PRODUCT_PURCHASED- oder SUBSCRIPTION_PURCHASED-Benachrichtigung. Wenn der Kauf storniert wird, erhalten Sie eine ONE_TIME_PRODUCT_CANCELED- oder SUBSCRIPTION_PENDING_PURCHASE_CANCELED-Benachrichtigung. Das kann passieren, wenn Ihr Kunde die Zahlung nicht innerhalb des erforderlichen Zeitraums abschließt. Sie können den aktuellen Status eines Kaufs jederzeit mit der Google Play Developer API prüfen.

Mehrere Stückzahlen verarbeiten

Google Play wird ab Version 4.0 der Google Play Billing Library unterstützt und ermöglicht es Kunden, mehr als ein In-App-Produkt in einer Transaktion zu kaufen, indem sie eine Menge im Einkaufswagen angeben. Ihre App muss Käufe in mehreren Stückzahlen verarbeiten und Berechtigungen basierend auf der angegebenen Kaufmenge gewähren.

Damit Käufe mit mehreren Artikeln berücksichtigt werden können, muss die Bereitstellungslogik Ihrer App eine Artikelmenge prüfen. Sie können über eine der folgenden APIs auf ein quantity-Feld zugreifen:

Nachdem Sie die Logik für den Umgang mit Käufen mit mehreren Stückzahlen hinzugefügt haben, müssen Sie die Funktion für die Stückzahl in der Google Play Console auf der Seite „In-App-Produktverwaltung“ für das entsprechende Produkt aktivieren.

Abrechnungskonfiguration des Nutzers abfragen

getBillingConfigAsync() gibt das Land an, das der Nutzer für Google Play verwendet.

Du kannst die Abrechnungskonfiguration des Nutzers abfragen, nachdem du eine BillingClient erstellt hast. Im folgenden Code-Snippet wird beschrieben, wie getBillingConfigAsync() aufgerufen wird. Verarbeite die Antwort, indem du BillingConfigResponseListener implementierst. Dieser Listener empfängt Aktualisierungen für alle Abfragen zur Abrechnungskonfiguration, die von Ihrer App initiiert wurden.

Wenn die zurückgegebene BillingResult keine Fehler enthält, kannst du im Feld countryCode des BillingConfig-Objekts das Land des Nutzers in Google Play abrufen.

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
        }
      }
    });