Google Play Billing Library in deine App integrieren

In diesem Artikel wird beschrieben, wie du die Google Play Billing Library in deine App einbindest, um mit dem Verkauf von Produkten zu beginnen.

Laufzeit eines Kaufs

Im Folgenden sehen Sie einen typischen Kaufvorgang für einen einmaligen Kauf oder ein Abo.

  1. Zeigen Sie den Nutzern, was sie kaufen können.
  2. Starten Sie den Kaufvorgang, damit der Nutzer den Kauf akzeptieren kann.
  3. Bestätige den Kauf auf deinem Server.
  4. Stellen Sie dem Nutzer Inhalte zur Verfügung.
  5. Die Übermittlung der Inhalte bestätigen. Bei Verbrauchsgütern kannst du den gekauften Artikel noch einmal kaufen.

Abos werden so lange automatisch verlängert, bis sie gekündigt werden. Ein Abo kann die folgenden Status haben:

  • Aktiv:Der Status des Nutzers ist einwandfrei und er hat Zugriff auf das Abo.
  • Gekündigt:Der Nutzer hat gekündigt, hat aber noch bis zum Ablaufdatum Zugriff.
  • Im Kulanzzeitraum:Der Nutzer hat ein Zahlungsproblem festgestellt, hat aber weiterhin Zugriff, während Google versucht, die Zahlungsmethode zu verwenden.
  • Wartephase:Der Nutzer hat ein Zahlungsproblem festgestellt und hat keinen Zugriff mehr, während Google versucht, die Zahlungsmethode zu verwenden.
  • Pausiert: Der Nutzer hat seinen Zugriff pausiert und erhält erst wieder Zugriff, wenn er fortgesetzt wird.
  • Abgelaufen:Der Nutzer hat das Abo gekündigt und keinen Zugriff mehr auf das Abo. Der Nutzer gilt nach Ablauf als abgewandert.

Verbindung zu Google Play herstellen

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

Abhängigkeit der Google Play Billing Library hinzufügen

Füge die Google Play Billing Library-Abhängigkeit wie gezeigt in die Datei build.gradle deiner App ein:

Groovig

dependencies {
    def billing_version = "6.2.1"

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

Kotlin

dependencies {
    val billing_version = "6.2.1"

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

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

Groovig

dependencies {
    def billing_version = "6.2.1"

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

Kotlin

dependencies {
    val billing_version = "6.2.1"

    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 deiner App. BillingClient bietet praktische Methoden, sowohl synchron als auch asynchron, für viele gängige Abrechnungsvorgänge. Wir empfehlen dringend, jeweils eine aktive BillingClient-Verbindung geöffnet zu haben, um mehrere PurchasesUpdatedListener-Callbacks für ein einzelnes Ereignis zu vermeiden.

Verwenden Sie zum Erstellen von BillingClient newBuilder(). Sie können jeden Kontext an newBuilder() übergeben und BillingClient verwendet ihn, um einen Anwendungskontext abzurufen. So müssen Sie sich keine Gedanken über Speicherlecks machen. Um Benachrichtigungen zu Käufen zu erhalten, musst du auch setListener() aufrufen und einen Verweis auf einen PurchasesUpdatedListener übergeben. Dieser Listener erhält Aktualisierungen zu allen Käufen in deiner App.

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

Mit Google Play verbinden

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

Rufen Sie startConnection() auf, um eine Verbindung zu Google Play herzustellen. Der Verbindungsvorgang ist asynchron und Sie müssen einen BillingClientStateListener implementieren, um einen Callback zu erhalten, sobald die Einrichtung des Clients abgeschlossen ist und weitere Anfragen gesendet werden können.

Außerdem müssen Sie eine Wiederholungslogik implementieren, um unterbrochene Verbindungen zu Google Play zu verarbeiten. Zum Implementieren einer Wiederholungslogik musst du die Callback-Methode onBillingServiceDisconnected() überschreiben und BillingClient die Methode startConnection() aufrufen, um die Verbindung zu Google Play wiederherzustellen, 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 eine Abfrage nach Ihren verfügbaren Produkten stellen und sie Ihren Nutzern anzeigen lassen.

Das Abfragen von Produktdetails ist ein wichtiger Schritt, bevor Ihre Produkte Nutzern angezeigt werden, da lokalisierte Produktinformationen zurückgegeben werden. Achten Sie bei Abos darauf, dass Ihre Produktdarstellung allen Google Play-Richtlinien entspricht.

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

Damit das Ergebnis des asynchronen Vorgangs verarbeitet wird, müssen Sie außerdem einen Listener angeben, der die ProductDetailsResponseListener-Schnittstelle implementiert. Sie können dann onProductDetailsResponse() überschreiben, der den Listener benachrichtigt, 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
        }
    }
)

Übergeben Sie beim Abfragen von Produktdetails eine Instanz von QueryProductDetailsParams, die eine Liste von Produkt-ID-Strings angibt, die in der Google Play Console erstellt wurden, zusammen mit einem ProductType. Die 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 die Erweiterungsfunktion queryProductDetails() aufrufen, um Details zu In-App-Produkten abzufragen.

queryProductDetails() nutzt Kotlin-Koroutinen, sodass Sie keinen separaten Listener definieren müssen. Stattdessen hält die Funktion an, 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 können ProductDetails und queryProductDetailsAsync() auf einigen Geräten nicht unterstützt werden. Das liegt meist an veralteten Versionen der Google Play-Dienste. Informationen zur Verwendung der Abwärtskompatibilitätsfunktionen findest du im Migrationsleitfaden für Play Billing Library 5, damit dieses Szenario korrekt unterstützt wird.

Ergebnis verarbeiten

Die Google Play Billing Library speichert die Abfrageergebnisse in einer List mit ProductDetails-Objekten. Anschließend kannst du für jedes ProductDetails-Objekt in der Liste verschiedene Methoden aufrufen, um relevante Informationen zu einem In-App-Produkt wie Preis oder Beschreibung abzurufen. Die verfügbaren Produktdetailinformationen finden Sie in der Liste der Methoden in der Klasse ProductDetails.

Bevor du einen Artikel zum Verkauf anbietest, solltest du prüfen, ob dem Nutzer der Artikel bereits gehört. Wenn der Nutzer ein Verbrauchsmaterial hat, das sich noch in seiner Artikelbibliothek befindet, muss er den Artikel zuerst verbrauchen, bevor er es noch einmal kaufen kann.

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

  • queryProductDetailsAsync() gibt Details zu Abo-Produkten 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 berechtigt ist (z. B. wenn in der App eine veraltete Liste zulässiger Angebote angezeigt wird), teilt Google Play den Nutzer mit, dass er nicht berechtigt ist, und er kann stattdessen das Basis-Abo erwerben.

Kaufvorgang starten

Um eine Kaufanfrage von deiner App aus zu starten, rufe die Methode launchBillingFlow() im Hauptthread deiner App auf. Diese Methode verweist auf ein BillingFlowParams-Objekt, das das relevante ProductDetails-Objekt enthält, das durch den Aufruf von queryProductDetailsAsync() abgerufen wurde. Verwenden Sie zum Erstellen eines BillingFlowParams-Objekts die Klasse 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);

Die Methode launchBillingFlow() gibt einen von mehreren in BillingClient.BillingResponseCode aufgeführten Antwortcodes zurück. Überprüfe dieses Ergebnis, um sicherzustellen, dass beim Starten des Kaufvorgangs keine Fehler aufgetreten sind. Ein BillingResponseCode von OK bedeutet, dass der Start 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 angeboten wird
Abbildung 1: Auf dem Kaufbildschirm bei Google Play wird ein Abo angezeigt, das zum Kauf angeboten wird.

Google Play ruft onPurchasesUpdated() auf, um das Ergebnis des Kaufvorgangs an einen Listener zu übergeben, der die PurchasesUpdatedListener-Schnittstelle implementiert. Der Listener wird mit der Methode setListener() bei der Initialisierung des Clients angegeben.

Sie müssen onPurchasesUpdated() implementieren, um mögliche Antwortcodes zu verarbeiten. Das folgende Beispiel zeigt, 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.
    }
}

Nach einem erfolgreichen Kauf wird bei Google Play ein Bildschirm für den Kaufabschluss angezeigt, der Abbildung 2 ähnelt.

Google Play-Kaufbestätigungsbildschirm
Abbildung 2: Google Play-Bildschirm mit der Kaufbestätigung.

Bei einem erfolgreichen Kauf wird auch ein Kauftoken generiert. Dabei handelt es sich um eine eindeutige Kennung, die den Nutzer und die Produkt-ID des gekauften In-App-Produkts darstellt. Ihre Apps können das Kauftoken lokal speichern. Wir empfehlen jedoch, das Token an Ihren sicheren Backend-Server weiterzugeben, damit Sie den Kauf dann prüfen und vor Betrug schützen können. Dieser Vorgang wird im folgenden Abschnitt näher beschrieben.

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

einen personalisierten Preis angeben,

Wenn deine App an Nutzer in der Europäischen Union vertrieben werden kann, kannst du Nutzern mithilfe der Methode setIsOfferPersonalized() mitteilen, dass der Preis eines Artikels durch automatisierte Entscheidungsfindung personalisiert wurde.

Auf dem Google Play-Kaufbildschirm wird angezeigt, dass der Preis für den Nutzer angepasst wurde.
Abbildung 3: Auf dem Google Play-Kaufbildschirm wird angezeigt, dass der Preis für den Nutzer angepasst wurde.

Sie müssen Art. 6 (1) (ea) CRD der Verbraucherrechtsrichtlinie (2011/83/EU) zur Bestimmung, ob der Preis, den Sie Nutzern anbieten, personalisiert wird.

setIsOfferPersonalized() verwendet eine boolesche Eingabe. Wenn true, enthält die Play-UI 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 dieser Kauf in Ihrer App verarbeitet werden. In den meisten Fällen wird deine App über die PurchasesUpdatedListener über Käufe benachrichtigt. Es gibt jedoch Fälle, in denen deine App auf Käufe aufmerksam wird, indem du BillingClient.queryPurchasesAsync() aufrufst, wie unter Käufe abrufen beschrieben.

Wenn du einen Client für Entwicklerbenachrichtigungen in Echtzeit in deinem sicheren Back-End verwendest, kannst du neue Käufe registrieren, indem du eine subscriptionNotification- oder oneTimeProductNotification-Benachrichtigung (nur für ausstehende Käufe) über einen neuen Kauf erhältst. Nachdem Sie diese Benachrichtigungen erhalten haben, rufen Sie die Google Play Developer API auf, um den vollständigen Status abzurufen und Ihren eigenen Back-End-Status zu aktualisieren.

In Ihrer App sollte ein Kauf folgendermaßen verarbeitet werden:

  1. Bestätigen Sie den Kauf.
  2. Nutzern Inhalte zur Verfügung stellen und deren Übermittlung bestätigen Sie können den Artikel als gebraucht markieren, damit der Nutzer ihn noch einmal kaufen kann.

Für die Bestätigung eines Kaufs muss der Kaufstatus PURCHASED sein. Wenn der Kauf den Status PENDING hat, solltest du den Kauf wie unter Ausstehende Transaktionen verarbeiten beschrieben verarbeiten. Bei Käufen, die du über onPurchasesUpdated() oder queryPurchasesAsync() erhältst, solltest du den Kauf zusätzlich bestätigen, um seine Legitimität sicherzustellen, bevor deine App die Berechtigung erteilt. Informationen zur ordnungsgemäßen Bestätigung eines Kaufs findest du unter Käufe vor dem Gewähren von Berechtigungen prüfen.

Sobald du den Kauf bestätigt hast, kann dem Nutzer über deine App die Berechtigung erteilt werden. Das mit dem Kauf verknüpfte Nutzerkonto kann anhand des ProductPurchase.obfuscatedExternalAccountId identifiziert werden, der von Purchases.products:get für In-App-Produktkäufe und dem SubscriptionPurchase.obfuscatedExternalAccountId von Purchases.subscriptions:get für Abos auf der Serverseite oder mit obfuscatedAccountId von Purchase.getAccountIdentifiers() auf Clientseite zurückgegeben wird, wenn auf [19/2] festgelegt wurde.setObfuscatedAccountId

Nachdem die Berechtigung gewährt wurde, muss Ihre App den Kauf bestätigen. Mit dieser Bestätigung wird Google Play mitgeteilt, dass du eine Berechtigung für den Kauf gewährt hast.

Wie die Berechtigung gewährt und der Kauf bestätigt wird, hängt davon ab, ob es sich beim Kauf um ein Verbrauchsmaterial, ein nicht konsumierbares Produkt oder ein Abo handelt.

Verbrauchsgüter

Wenn deine App ein sicheres Back-End für Verbrauchsgüter hat, empfehlen wir die Verwendung von Purchases.products:consume, um Käufe zuverlässig abzuschließen. Prüfe, ob der Kauf bereits verbraucht wurde. Prüfe dazu consumptionState aus dem Ergebnis des Aufrufs von Purchases.products:get. Wenn deine App nur Client ohne Back-End ist, verwende consumeAsync() aus der Google Play Billing Library. Beide Methoden erfüllen die Anforderung zur Bestätigung und zeigen an, dass Ihre App dem Nutzer eine Berechtigung gewährt hat. Mit diesen Methoden kann Ihre Anwendung außerdem das einmalige Produkt, das dem eingegebenen Kauftoken entspricht, zum erneuten Kauf zur Verfügung stellen. Bei consumeAsync() müssen Sie außerdem ein Objekt übergeben, das die Schnittstelle ConsumeResponseListener implementiert. Dieses Objekt verarbeitet das Ergebnis des Verbrauchsvorgangs. Du kannst die Methode onConsumeResponse() überschreiben, die von der Google Play Billing Library nach Abschluss des Vorgangs aufgerufen wird.

Das folgende Beispiel zeigt, wie ein Produkt mit der Google Play Billing Library mit 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 deine App ein sicheres Back-End hat, empfehlen wir zur Bestätigung von nicht konsumierbaren Käufen Purchases.products:acknowledge zu verwenden, um Käufe zuverlässig zu bestätigen. Prüfe, ob der Kauf zuvor noch nicht bestätigt wurde. Prüfe dazu acknowledgementState aus dem Ergebnis des Aufrufs von Purchases.products:get.

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

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

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 gehandhabt wie Nicht-Verbrauchsgüter. Verwende nach Möglichkeit Purchases.subscriptions.acknowledge aus der Google Play Developer API, um den Kauf über dein sicheres Back-End zuverlässig zu bestätigen. Prüfe, ob der Kauf zuvor nicht bestätigt wurde. Prüfe dazu die acknowledgementState in der Kaufressource von Purchases.subscriptions:get. Alternativ 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 unter dem Thema Abos verkaufen.

Käufe werden abgerufen

Es reicht nicht aus, mit einem PurchasesUpdatedListener auf Kaufaktualisierungen zu warten, um sicherzustellen, dass deine App alle Käufe verarbeitet. Es ist möglich, dass Ihre App nicht alle Käufe eines Nutzers kennt. Hier sind einige Szenarien, in denen Ihre App den Überblick über Käufe verliert oder keine Käufe erkennt:

  • Netzwerkprobleme während des Kaufs: Ein Nutzer schließt einen Kauf ab und erhält eine Bestätigung von Google, aber sein Gerät verliert die Netzwerkverbindung, bevor sein Gerät über die PurchasesUpdatedListener eine Benachrichtigung über den Kauf erhält.
  • Mehrere Geräte: Ein Nutzer kauft einen Artikel auf einem Gerät und erwartet dann, dass der Artikel angezeigt wird, wenn er das Gerät wechselt.
  • Käufe außerhalb deiner App verarbeiten: Einige Käufe, z. B. das Einlösen von Angeboten, können außerhalb deiner App getätigt werden.

Deine App muss in dieser Situation BillingClient.queryPurchasesAsync() in der Methode onResume() aufrufen, damit alle Käufe erfolgreich verarbeitet werden, wie unter Käufe verarbeiten beschrieben.

Das folgende Beispiel zeigt, wie die Abokäufe eines Nutzers abgerufen werden. queryPurchasesAsync() gibt nur aktive Abos und nicht verbrauchte einmalige Käufe zurück.

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

      }
    }
);

Bisherige Käufe werden abgerufen

queryPurchaseHistoryAsync() gibt den letzten Kauf zurück, den der Nutzer für jedes Produkt getätigt hat, auch wenn der Kauf abgelaufen, storniert oder verbraucht wurde.

Wenn Sie Kotlin-Erweiterungen verwenden, können Sie die Erweiterungsfunktion queryPurchaseHistory() verwenden.

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

Käufe außerhalb deiner App verarbeiten

Einige Käufe, z. B. das Einlösen von Angeboten, können außerhalb Ihrer App erfolgen. Wenn ein Nutzer einen Kauf außerhalb Ihrer App tätigt, erwartet er, dass in der App eine In-App-Nachricht angezeigt wird oder dass ein Benachrichtigungsmechanismus verwendet wird, der den Nutzer darüber informiert, dass die App den Kauf korrekt erhalten und verarbeitet hat. Einige akzeptable Mechanismen sind:

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

Deine App kann sich in einem beliebigen Status befinden, wenn sie den Kauf erkennt. Es ist sogar möglich, dass die App zum Zeitpunkt des Kaufs gar nicht installiert wurde. Nutzer erwarten, ihren Kauf zu erhalten, wenn sie die App fortsetzen, unabhängig davon, in welchem Bundesstaat sich die App befindet.

Sie müssen Käufe unabhängig davon erkennen, in welchem Status sich die App zum Zeitpunkt des Kaufs befindet. Es gibt jedoch einige Ausnahmen, bei denen es akzeptabel ist, den Nutzer nicht sofort über den Erhalt des Artikels zu informieren. Beispiele:

  • Während der Aktion eines Spiels kann das Zeigen einer Nachricht den Nutzer ablenken. In diesem Fall müssen Sie den Nutzer benachrichtigen, nachdem die Aktion abgeschlossen ist.
  • Während Zwischensequenzen, wo eine Nachricht den Nutzer ablenken kann. In diesem Fall muss der Nutzer nach Abschluss der Zwischensequenz benachrichtigt werden.
  • Während der ersten Anleitung und der ersten Einrichtung durch den Nutzer im Spiel Wir empfehlen, neue Nutzer sofort nach dem Öffnen des Spiels oder bei der Ersteinrichtung durch den Nutzer über die Prämie zu informieren. Sie können jedoch warten, bis die Hauptspielsequenz verfügbar ist, um den Nutzer zu benachrichtigen.

Bei der Entscheidung, wann und wie du deine Nutzer über Käufe außerhalb deiner App informieren möchtest, solltest du immer den Nutzer im Hinterkopf behalten. Wenn ein Nutzer nicht sofort eine Benachrichtigung erhält, kann er verwirrend sein, deine App nicht mehr verwenden, den Nutzersupport kontaktieren oder dich in den sozialen Medien darüber beschweren. Hinweis: PurchasesUpdatedListener ist bei deinem Kontext deiner App registriert, um Kauf-Updates zu verarbeiten, einschließlich Käufen, die außerhalb deiner App initiiert wurden. Wenn dein Anwendungsprozess also nicht vorhanden ist, wird PurchasesUpdatedListener nicht benachrichtigt. Aus diesem Grund sollte deine App BillingClient.queryPurchasesAsync() in der onResume()-Methode aufrufen, wie unter Käufe abrufen beschrieben.

Ausstehende Transaktionen verarbeiten

Google Play unterstützt ausstehende Transaktionen oder Transaktionen, die einen oder mehrere zusätzliche Schritte zwischen dem Kaufabschluss und der Verarbeitung der Zahlungsmethode für den Kauf erfordern. Ihre App sollte keine Berechtigungen für diese Art von Käufen gewähren, bis Google Sie darüber informiert, dass die Zahlungsmethode des Nutzers erfolgreich belastet wurde.

Ein Nutzer kann beispielsweise einen PENDING-Kauf eines In-App-Artikels erstellen, indem er Bargeld als Zahlungsmittel auswählt. Der Nutzer kann dann ein Geschäft auswählen, in dem er die Transaktion abschließt und einen Code per Benachrichtigung und E-Mail erhält. Wenn der Nutzer im Geschäft ankommt, kann er den Code an der Kasse einlösen und mit Bargeld bezahlen. Google benachrichtigt Sie und den Nutzer, dass Bargeld eingegangen ist. Ihre App kann dem Nutzer dann Berechtigungen gewähren.

Deine App muss ausstehende Transaktionen unterstützen. Dazu muss im Rahmen der Initialisierung der App enablePendingPurchases() aufgerufen werden.

Wenn deine App einen neuen Kauf erhält, entweder über deinen PurchasesUpdatedListener oder durch den Aufruf von queryPurchasesAsync(), verwende die Methode getPurchaseState(), um zu ermitteln, ob der Kaufstatus PURCHASED oder PENDING ist.

Wenn Ihre App ausgeführt wird, nachdem der Nutzer den Kauf abgeschlossen hat, wird PurchasesUpdatedListener noch einmal aufgerufen und PurchaseState ist jetzt PURCHASED. An dieser Stelle kann die App den Kauf mit der Standardmethode zur Verarbeitung einmaliger Käufe verarbeiten. Deine App sollte außerdem queryPurchasesAsync() in der Methode onResume() deiner App aufrufen, um Käufe abzuwickeln, die in den Status PURCHASED übergegangen sind, während deine App nicht ausgeführt wurde.

Deine App kann auch Entwicklerbenachrichtigungen in Echtzeit mit ausstehenden Käufen verwenden, indem sie auf OneTimeProductNotifications wartet. Bei der Umstellung des Kaufs von PENDING auf PURCHASED wird an Ihre App eine ONE_TIME_PRODUCT_PURCHASED-Benachrichtigung gesendet. Wenn der Kauf storniert wird, erhält Ihre App eine ONE_TIME_PRODUCT_CANCELED-Benachrichtigung. Dies kann passieren, wenn Ihr Kunde die Zahlung nicht innerhalb des erforderlichen Zeitraums abschließt. Wenn du diese Benachrichtigungen erhältst, kannst du die Google Play Developer API verwenden, die einen PENDING-Status für Purchases.products enthält.

Eine detaillierte Anleitung zum Testen dieses Szenarios finden Sie unter Ausstehende Käufe testen.

Käufe in variabler Stückzahl verarbeiten

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

Damit Käufe in variabler Stückzahl berücksichtigt werden können, muss die Bereitstellungslogik Ihrer App nach einer Artikelmenge suchen. Sie können über eine der folgenden APIs auf das Feld quantity zugreifen:

Nachdem du die Logik zum Verarbeiten von Käufen in variabler Stückzahl hinzugefügt hast, musst du die Funktion für variable Stückzahlen für das entsprechende Produkt auf der In-App-Produktverwaltungsseite in der Google Play Developer Console aktivieren.

Abrechnungskonfiguration des Nutzers abfragen

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

Sie können die Abrechnungskonfiguration des Nutzers abfragen, nachdem Sie eine BillingClient erstellt haben. Im folgenden Code-Snippet wird beschrieben, wie getBillingConfigAsync() aufgerufen wird. Verarbeiten Sie die Antwort, indem Sie BillingConfigResponseListener implementieren. Dieser Listener erhält Aktualisierungen für alle von Ihrer Anwendung initiierten Abfragen von Abrechnungskonfigurationen.

Wenn das zurückgegebene BillingResult keine Fehler enthält, kannst du das Feld countryCode im Objekt BillingConfig prüfen, um das Play-Land des Nutzers abzurufen.

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