App-Praxis im Ausland: Google Play-Abrechnungssystem

Autor: Ye Zhichen

Heutzutage ist die Beliebtheit, für Apps ins Ausland zu gehen, ungebrochen, und diese Marktrichtung wird von vielen Unternehmen und einzelnen Entwicklern gewählt. Um Rentabilität zu erzielen, bieten Apps neben Werbung, der gängigsten Monetarisierungsmethode, verschiedene virtuelle Güter oder Mitgliedschaftsdienste an, um Benutzer zum Bezahlen zu bewegen. Derzeit ist das Abrechnungssystem von Google Play das Android-Terminal. Ein Zahlungskanal, der die Anwendung muss verwendet werden

Google und Google Play 结算系统的简介: Das Abrechnungssystem von Google Play ist ein Dienst, der es Ihnen ermöglicht, digitale Produkte und Inhalte in Ihrer Android-App zu verkaufen, unabhängig davon, ob Sie durch einmalige Käufe Geld verdienen oder Abonnements für Ihre Dienste anbieten möchten. Google Play bietet einen vollständigen Satz von APIs für die Integration sowohl in Ihre Android-App als auch in Ihr Server-Backend, die Ihren Nutzern die Vertrautheit und Sicherheit von Google Play-Käufen ermöglichen.

Mit anderen Worten: Google Play Billing ist ein Dienst, der es uns ermöglicht, digitale Waren und Inhalte in Android-Apps zu verkaufen. Unabhängig davon, ob wir Einnahmen aus einmaligen Käufen erzielen oder Benutzern einen Abonnementdienst anbieten möchten, kann es uns dabei helfen. Google Play bietet einen umfassenden Satz an APIs, die in Android-Anwendungen und Server-Backends integriert werden können, um Benutzern vertraute und sichere Google Play-Kauftransaktionen zu ermöglichen.

Im letzten Jahr war ich für die Entwicklung eines Auslandsprojekts verantwortlich und wurde dabei auch an das Abrechnungssystem von Google Play angeschlossen. Da ich die einzelnen Konzepte zu Beginn nicht gut genug verstand und der gesamte Zahlungsprozess sich stark von den verschiedenen in China üblichen Zahlungsdiensten unterschied, machte ich viele Umwege.

Hier werde ich einen Artikel schreiben, um das Google Play-Abrechnungssystem im Detail vorzustellen. Ich hoffe, er wird Ihnen hilfreich sein.

I. Übersicht

Wenn Sie Produkte über das Google Play-Abrechnungssystem anzeigen und den Nutzern verkaufen möchten, müssen Sie natürlich zuerst Produkte erstellen. Es gibt zwei Möglichkeiten, Produkte zu erstellen:

  • Manuell in der Google Play Console erstellen
  • Erstellt im Code über die Google Play Developer API

Die in Google Play erstellten Produkte sind alle virtuelle Produkte. Jedes Produkt stellt einen Vorteil dar, den die App den Benutzern bietet, und jedes Produkt enthält eine eindeutige Kennung, nämlich ProductId. Im Geschäftsleben müssen wir ProductId-Benennungsregeln verwenden, um das Spezifische zu definieren Arten von Rechten und Interessen, die das Produkt repräsentiert

Jedes Produkt kann in zwei Typen unterteilt werden:

  • Einwegartikel. Die Produkte, die Benutzer durch eine einzige Zahlung erhalten, gehören zum Buyout-System und entsprechen der Google Play-Abrechnungsbibliothek.BillingClient.ProductType.INAPP
  • Abonnementprodukte. Produkte, die Nutzer in einem festgelegten Zeitraum wiederholt bezahlen, sind abonnementbasiert und entsprechen der Google Play-Abrechnungsbibliothek.BillingClient.ProductType.SUBS

Nachdem der Benutzer das Produkt gekauft hat, muss die App auch die Bestellung abbuchen. Der Verarbeitungsprozess hängt von der Art des Produkts ab und wird in zwei Arten unterteilt:

  • Bestätigen Sie die Transaktion. Unabhängig davon, welche Art von Produkt gekauft wird, muss die App zunächst die Transaktion bestätigen . Wenn die Bestätigung nicht innerhalb der begrenzten Zeit abgeschlossen wird, widerruft Google Play die Transaktion automatisch und erstattet dem Nutzer das Geld. Der Vorgang „Transaktion bestätigen“ sollte von Google Play durchgeführt werden, um sicherzustellen, dass die App dem Benutzer Rechte und Interessen gewährt hat, und um die Situation zu vermeiden, in der der Benutzer bezahlt hat, die App dem Benutzer jedoch keine Rechte gewährt hat . Der Bestätigungsvorgang kann entsprechend acknowledgePurchasedem Vorgang durch den Server oder das mobile Endgerät implementiert werden
  • Waren konsumieren. Verbrauchsprodukte sind auf Verbrauchsprodukte unter den Einwegprodukten ausgerichtet, das heißt, es werden Verbrauchsvorgänge an ihnen durchgeführt. Durch die Durchführung des Verbrauchsvorgangs kann der Benutzer das Produkt anschließend erneut erwerben. Der Verbrauchsvorgang kann entsprechend consumePurchasedem Vorgang durch den Server oder das mobile Endgerät implementiert werden

2. Einwegartikel

Einmalprodukte werden auch In-App-Produkte genannt, bei denen es sich um einmalige Buy-out-Produkte handelt. Sie können in zwei Untertypen unterteilt werden:

  • Konsumgüter. Das heißt, dieses Produkt kann nach dem Kauf konsumiert werden, sodass der Benutzer wiederholte Einkäufe tätigen kann. Dieses Produkt kann beispielsweise zur Darstellung von Goldmünzen im Spiel verwendet werden. Nachdem der Benutzer die Goldmünzen verwendet hat, werden die durch das Produkt repräsentierten Rechte ungültig. Der Benutzer muss das Produkt erneut kaufen, um erneut Goldmünzen zu erhalten.
  • Nicht verbrauchbare Güter. Mit anderen Worten: Dieses Produkt ist nach dem Kauf nicht verbrauchbar und Benutzer können die Rechte und Interessen, die das Produkt vertritt, dauerhaft erwerben. Mit diesem Produkt können beispielsweise die Anzeigerechte eines bestimmten Kurses dargestellt werden. Solange der Nutzer das Produkt kauft, kann er die Anzeigerechte des Kurses dauerhaft genießen.

Ob ein einmaliges Produkt konsumierbar oder nicht konsumierbar ist , hängt von der Geschäftsdefinition der App ab. In der Google Play Console werden sie einheitlich als In- App-Produkte bezeichnet und es gibt keine Möglichkeit, bei der Erstellung von einmaligen Produkten Untertypen zu unterscheiden .

Unter der Annahme, dass unsere Geschäftsdefinition eines einmaligen Artikels ein Verbrauchsartikel ist, können wir consumePurchaseeinen „Verbrauchs“-Vorgang dafür durchführen, indem wir ihn zum entsprechenden Zeitpunkt ausführen. Wenn der Benutzer beispielsweise durch den Kauf eines einmaligen Produkts Spielgoldmünzen erhält und diese Goldmünzen im weiteren Verlauf zum Kauf von Spielzubehör verwendet, muss der Entwickler gleichzeitig ausführen, um das Produkt zu verbrauchen und so consumePurchaseherzustellen Das Produkt ist ungültig. Benutzer können dieses Produkt auch später erneut kaufen

Für nicht verbrauchbare Waren stellen sie im geschäftlichen Sinne bestimmte Rechte und Interessen dar, die der Benutzer dauerhaft genießen kann. Solange die Waren gekauft werden, gehen die Rechte und Interessen nicht verloren. Daher sollte der Benutzer sie nicht erneut kaufen. Natürlich besteht weder die Notwendigkeit noch die Möglichkeit, es zu konsumieren

3. Abonnementprodukte

Abonnementprodukte sind Produkte, bei denen Benutzer regelmäßig in einem festgelegten Zeitraum bezahlen müssen. Während des Zahlungszeitraums können Benutzer die durch das Produkt repräsentierten Rechte genießen. Das häufigste Anwendungsszenario sind verschiedene Mitgliedschaftsdienste: Benutzer zahlen monatlich und die App bietet Benutzern während jedes Abonnementzyklus einzigartige Funktionen, bis der Benutzer das Abonnement kündigt.

Abonnementprodukte umfassen vier wichtige Konzepte:

  • Grundplan
  • Erneuerungstyp
  • Rabatt
  • Preisstufe

Grundplan

Basisplan, auch BasePaln genannt. Jedes Abonnementprodukt muss einen oder mehrere Basispläne enthalten, bevor Benutzer es kaufen können

Der Basisplan wird verwendet, um die Verkaufsregeln für Produkte zu definieren, einschließlich Abrechnungszyklus, Verlängerungstyp, Abonnementpreis, Rabattstrategie usw. Beispielsweise kann ein Abonnementprodukt den Benutzern zwei Basispläne zur Auswahl bieten, eine monatliche Zahlung und eine jährliche Zahlung . Für jeden Zyklus werden unterschiedliche Preise festgelegt, und Benutzer können je nach ihren Vorlieben verschiedene Pläne zum Abonnieren auswählen.

Erneuerungstyp

Für jeden Basisplan muss ein Verlängerungstyp angegeben werden, der zur Angabe der Zahlungsmethode des Benutzers verwendet wird.

Es gibt zwei Arten von Verlängerungen:

  • Automatisch erneuern. Ziehen Sie am Ende jedes Abrechnungszyklus aktiv die Zahlung von den Benutzern ab und verlängern Sie so automatisch den Zeitraum der Nutzungsrechte. Bezahlte Vorgänge sind für Benutzer passiv
  • Prepaid. Es erfolgt keine automatische Verlängerung und Zahlung. Benutzer müssen aktive Zahlungen leisten, um das Ablaufdatum der Rechte zu verschieben, um die Abonnementinhalte ununterbrochen genießen zu können. Der Zahlungsvorgang ist für Benutzer proaktiv

Rabatt

Rabatte, auch Angebote genannt, können nur für Basispläne mit automatischer Verlängerung festgelegt werden.

In jedem Basisplan mit automatischer Verlängerung können mehrere Rabatte gleichzeitig festgelegt werden, sodass Benutzer zu Beginn des Abonnements von einem bestimmten Preisnachlass profitieren oder diesen direkt kostenlos nutzen können, wodurch Benutzer zum Kauf angeregt werden

Es gibt drei Arten von Angeboten, also drei Vorzugsstrategien. Wenn wir beispielsweise davon ausgehen, dass es ein einfaches monatliches Abonnement gibt, können wir den Benutzern die folgenden drei Angebote zur Auswahl hinzufügen:

  • Kostenlose Testphase. Benutzer können es innerhalb der ersten sieben Tage kostenlos testen und nach sieben Tagen offiziell monatlich bezahlen.
  • Einmalzahlung. Nutzer zahlen einmalig eine dreimonatige Abonnementgebühr im Voraus und erhalten 30 % Rabatt auf den Gesamtpreis. Nach drei Monaten können Nutzer ein monatliches Abonnement zum ursprünglichen Preis abschließen.
  • Wiederkehrende Zahlungsrabatte. Benutzer abonnieren weiterhin auf monatlicher Basis, können jedoch in den ersten drei Monaten bei jeder Zahlung einen Rabatt von 20 % erhalten. Nach drei Monaten können sie monatlich zum ursprünglichen Preis abonnieren.

Preisstufe

Preisphasen, auch PricingPhases genannt, können als internes Attribut des Angebots betrachtet werden

Da ein Angebot mehrere Vorzugsstrategien gleichzeitig enthalten kann, ändert sich der Preis, den ein Benutzer zahlen muss, im Laufe der Zeit mehrmals, wenn ein Benutzer ein Angebot in Anspruch nimmt. Jeder Zeitraum entspricht einem anderen Preis. PricingPhases wird verwendet, um die Gebührenregeln anzugeben für das Angebot in jedem Zeitraum

Beispielsweise beinhaltet ein Basisplan mit automatischer monatlicher Verlängerung ein Angebot, das eine siebentägige kostenlose Testversion beinhaltet. Dann sind die Preisstufen dieses Angebots:

  • Benutzer genießen zunächst eine siebentägige kostenlose Testversion
  • Nach sieben Tagen zahlen Nutzer monatlich den ursprünglichen Preis.

Wenn Sie diesem Angebot die Vorzugsstrategie „30 % Rabatt und einmonatige Zahlung“ hinzufügen, beträgt die Preisstufe des Angebots:

  • Benutzer genießen zunächst eine siebentägige kostenlose Testversion
  • Nach sieben Tagen zahlt der Nutzer 30 % Rabatt auf den ursprünglichen Preis und erhält eine einmonatige Abonnementlaufzeit.
  • Nach einem Monat zahlen Nutzer monatlich den ursprünglichen Preis.

Daher bestimmt die Preisstufe die Gebühren, die Benutzer in verschiedenen Zeiträumen ausgeben müssen. Jedes Angebot darf bis zu zwei Preisstufen addieren, d. h. es treten bis zu drei Preisänderungen auf, und Benutzer erhalten die Preisänderungen der Reihe nach.

Zusammenfassen

Google Play bietet ein hohes Maß an Freiheit bei der Festlegung von Basisplan und Angebot. Der Zahlungszeitraum für die automatische Verlängerung des BasePlan kann zwischen einer Woche und einem Jahr liegen, und der Zahlungszeitraum für den Prepaid-BasePlan kann zwischen einem Tag und einem Jahr liegen. Auch der Rabattzeitraum und der Rabattpreis jeder Rabattstrategie sind flexibel einstellbar. Wir können versuchen, die Zahlungsrate des Benutzers zu erhöhen, indem wir verschiedene Zykluslängen und Rabattstrategien festlegen, aus denen Benutzer wählen können.

Darüber hinaus können für jedes abonnementbasierte Produkt bis zu 250 Basispläne und -angebote erstellt werden, es können jedoch nicht mehr als 50 Basispläne und -angebote gleichzeitig aktiviert werden. Die zusätzlichen Basispläne und -angebote müssen sich im Entwurfs- oder inaktiven Status befinden.

4. Abrechnungs-SDK

Nachdem wir die oben genannten Grundkonzepte verstanden haben, wollen wir sehen, wie diese Konzepte dem Billing SDK entsprechen.

Alle Codebeispiele in diesem Artikel verwenden die neueste Version des SDK des aktuellen Google Play-Abrechnungssystems auf der Android-Seite und sind Coroutine-Versionen. Leser müssen über ein gewisses Verständnis von Coroutinen verfügen.

dependencies {
    val billingVersion = "6.0.1"
    implementation("com.android.billingclient:billing-ktx:$billingVersion")
}

Der gesamte Bezahlvorgang lässt sich wie folgt zusammenfassen:

  1. Stellen Sie über BillingClient eine Verbindung mit Google Play her und binden Sie die PurchasesUpdatedListener-Schnittstelle für Rückrufzahlungsergebnisse.
  2. Fragen Sie lokalisierte Produktinformationen, nämlich ProductDetails, über BillingClient ab, um Produktbeschreibung, Basisplan, Preisinformationen, Rabattstrategie und andere Attribute zu erhalten.
  3. Starten Sie basierend auf den gefundenen Produktdetails eine Zahlungsanforderung an BillingClient und aktivieren Sie das Zahlungs-Popup-Fenster.
  4. Rufen Sie das Zahlungsergebnis in PurchasesUpdatedListener ab und ermitteln Sie den Zahlungsstatus des Benutzers
  5. Nachdem festgestellt wurde, dass die Zahlung des Benutzers erfolgreich war, wird das Produkt je nach Produkttyp bestätigt oder verbraucht .

BillingClient

BillingClient ist die Hauptschnittstelle für die Google Play-Abrechnungsbibliothek zur Kommunikation mit der App. Bevor die App zahlungsbezogene Vorgänge ausführen kann, muss sie über BillingClient eine Verbindung mit Google Play herstellen. Beim Initialisieren der BillingClient-Instanz müssen Sie gleichzeitig PurchasesUpdatedListener binden, um Rückrufbenachrichtigungen über Zahlungsergebnisse zu erhalten. Aus diesem Grund kann die App höchstens eine aktive BillingClient-Verbindung im gleichen Zeitraum aufrechterhalten, um zu verhindern, dass dasselbe Zahlungsereignis mehrere PurchasesUpdatedListener gleichzeitig zurückruft.

private val purchasesUpdatedListener =
    PurchasesUpdatedListener { billingResult: BillingResult, purchases: List<Purchase>? ->

    }

private lateinit var billingClient: BillingClient

suspend fun startConnection(context: Context) {
    billingClient = buildBillingClient(context = context, purchasesUpdatedListener)
    startConnection(billingClient = mBillingClient)
}

private fun buildBillingClient(
    context: Context,
    listener: PurchasesUpdatedListener
): BillingClient {
    return BillingClient.newBuilder(context)
        .setListener(listener)
        .enablePendingPurchases()
        .build()
}

private suspend fun startConnection(billingClient: BillingClient): BillingResult? {
    return withContext(context = Dispatchers.Default) {
        if (billingClient.isReady) {
            return@withContext null
        }
        return@withContext suspendCancellableCoroutine { continuation ->
            billingClient.startConnection(object : BillingClientStateListener {
                override fun onBillingSetupFinished(billingResult: BillingResult) {
                    if (!continuation.isCompleted) {
                        continuation.resume(value = billingResult)
                    }
                }

                override fun onBillingServiceDisconnected() {
                    if (!continuation.isCompleted) {
                        continuation.resume(value = null)
                    }
                }
            })
        }
    }
}

Produktdetails

ProductDetails sind auch die Produktdetails. Unabhängig davon, ob es sich um ein einmaliges Produkt oder ein Abonnementprodukt handelt, werden ProductDetails zum Übertragen spezifischer Produktinformationen verwendet.

Für die Abfrage von ProductDetails sind zwei Abfrageparameter erforderlich: ProductId und Produkttyp. Der Produkttyp ist Einmalprodukt INAPP und Abonnementprodukt SUBS .

private suspend fun queryProductDetails() {
    //查询一次性商品
    queryProductDetails(
        billingClient = mBillingClient,
        productIdList = setOf("1", "2"),
        productType = BillingClient.ProductType.INAPP
    )
    //查询订阅型商品
    queryProductDetails(
        billingClient = mBillingClient,
        productIdList = setOf("1", "2"),
        productType = BillingClient.ProductType.SUBS
    )
}

private suspend fun queryProductDetails(
    billingClient: BillingClient,
    productIdList: Set<String>,
    productType: String
): List<ProductDetails>? {
    return withContext(context = Dispatchers.Default) {
        if (!billingClient.isReady || productIdList.isEmpty()) {
            return@withContext null
        }
        val productDetailParamsList = productIdList.map {
            QueryProductDetailsParams
                .Product
                .newBuilder()
                .setProductId(it)
                .setProductType(productType)
                .build()
        }
        val queryProductDetailsParams = QueryProductDetailsParams
            .newBuilder()
            .setProductList(productDetailParamsList)
            .build()
        val productDetailsResult = billingClient.queryProductDetails(queryProductDetailsParams)
        productDetailsResult.productDetailsList
    }
}

Die Datenstruktur von ProductDetails ist wie folgt, und wir können uns auf diese Informationen verlassen, um dem Benutzer Produktdetails anzuzeigen. Die beiden Felder oneTimePurchaseOfferDetails und subscriptionOfferDetails werden verwendet, um die Preisinformationen von Einmalprodukten bzw. Abonnementprodukten zu übertragen.

{
	"productId": "",
	"productType": "",
	"title": "",
	"name": "",
	"description": "",
	"oneTimePurchaseOfferDetails": {},
	"subscriptionOfferDetails": []
}

oneTimePurchaseOfferDetails

oneTimePurchaseOfferDetails entspricht den Details einmaliger Produkte. Die Datenstruktur ist relativ einfach, hauptsächlich die Preisinformationen.

{
	"priceAmountMicros": 548000000,
	"priceCurrencyCode": "HKD",
	"formattedPrice": "HK$548.00"
}

Es ist zu beachten, dass die von Google Play zurückgegebenen Preisinformationen lokalisiert sind und die Details automatisch entsprechend dem Land und der Region zurückgegeben werden, die dem Google Play-Konto des aktuellen Geräts entsprechen. Daher der Preiswährungscode des Produkts und des formatierten Produkts Der Preis priceCurrencyCodekann formattedPriceaufgrund der tatsächlichen Umstände variieren

subscriptionOfferDetails

subscriptionOfferDetails entspricht den Details des Abonnementprodukts

Da Abonnementprodukte mehrere BasePlans enthalten können und jeder BasePlan mehrere Angebote enthalten kann, ist der entsprechende Datentyp des Felds subscriptionOfferDetails in ProductDetails List<SubscriptionOfferDetails>. Jedes SubscriptionOfferDetails entspricht einem Angebot und jedes Angebot ist einem BasePlan zugeordnet. Google Play gibt Preisinformationen in Angebotseinheiten zurück.

[
    {
        "basePlanId": "yearly",
        "offerId": null,
        "offerToken": "xxx",
        "pricingPhases": {
            "pricingPhaseList": [
                {
                    "formattedPrice": "HK$469.00",
                    "priceAmountMicros": 469000000,
                    "priceCurrencyCode": "HKD",
                    "billingPeriod": "P1Y",
                    "billingCycleCount": 0,
                    "recurrenceMode": 1
                }
            ]
        }
    },
    {
        "basePlanId": "yearly",
        "offerId": "xxx",
        "offerToken": "xxx",
        "pricingPhases": {
            "pricingPhaseList": [
                {
                    "formattedPrice": "免費",
                    "priceAmountMicros": 0,
                    "priceCurrencyCode": "HKD",
                    "billingPeriod": "P1W",
                    "billingCycleCount": 1,
                    "recurrenceMode": 2
                },
                {
                    "formattedPrice": "HK$469.00",
                    "priceAmountMicros": 469000000,
                    "priceCurrencyCode": "HKD",
                    "billingPeriod": "P1Y",
                    "billingCycleCount": 0,
                    "recurrenceMode": 1
                }
            ]
        }
    }
]

Wie oben erwähnt, beinhaltet Offer das Konzept der PricingPhases. Dieses Konzept spiegelt sich im obigen JSON wider, aus dem die folgenden Produktinformationen interpretiert werden können:

  • Dieses Produkt enthält einen Basisplan mit der ID „jährlich“ und insgesamt zwei Angebote.
  • offerToken wird zur eindeutigen Identifizierung jedes Angebots verwendet und ist einzigartig
  • billingPeriod wird verwendet, um den Abrechnungszeitraum darzustellen, der im ISO 8601-Format angegeben wird. Beispielsweise steht P1W für eine Woche, P1Y für ein Jahr und P1M3D für einen Monat plus drei Tage.
  • billingCycleCount wird verwendet, um die Anzahl der Zyklen im Abrechnungszyklus darzustellen. Beispielsweise bedeuten die ersten PricingPhases des zweiten Angebots oben, dass Benutzer eine Woche lang kostenlos testen dürfen; wenn billingCycleCount 2 ist, bedeutet dies, dass Benutzer zwei Wochen lang kostenlos testen dürfen
  • recurrenceMode wird verwendet, um den Wiederholungsmodus der Preisstufe darzustellen. Wenn der Wert 1 oder 3 ist, ist der billingCycleCount-Wert 0.
    • Ein Wert von 1 bedeutet, dass es innerhalb eines unendlichen Abrechnungszeitraums wiederholt wird, sofern der Benutzer nicht aktiv kündigt.
    • Ein Wert von 2 bedeutet, dass die Abrechnung innerhalb des durch billingCycleCount angegebenen Zeitraums wiederholt wird.
    • Ein Wert von 3 gibt eine einmalige Gebühr an und wird nicht wiederholt.
  • Die Angebots-ID des ersten Angebots ist null, was bedeutet, dass dieses Angebot nicht die tatsächliche Vorzugsstrategie enthält, sondern tatsächlich den ursprünglichen Preis von BasePlan darstellt, sodass die PreisphaseListe nur einen Wert hat. Und da der Abrechnungszeitraum P1Y ist, bedeutet dies, dass der Zahlungszyklus des zugehörigen BasePlans ein Jahr beträgt. Nach Auswahl dieses Angebots müssen Benutzer für das Abonnement direkt den ursprünglichen Preis von 469,00 HK$ bezahlen.
  • Die offerId des zweiten Angebots ist nicht null, was darauf hinweist, dass dieses Angebot eine echte Vorzugsstrategie enthält, sodass die Größe von pricingPhaseList größer als eins sein wird. Dieses Angebot ermöglicht es Benutzern, es eine Woche lang kostenlos zu testen und es dann zum gleichen Preis und Zeitraum wie das erste Angebot zu abonnieren.

Wenn Sie daher die Preisstrategie von BasePlan und die Vorzugsstrategie von Offer interpretieren möchten, müssen Sie alle Felder zur Analyse kombinieren. Unabhängig davon, ob wir bei der Erstellung eine Rabattstrategie für BasePlan festlegen, behandelt Google Play zunächst den ursprünglichen Preis von BasePlan als Angebot und gibt es zurück. In diesem Fall hat das Angebot nur eine Preisstufe. Für eine echte Rabattstrategie muss die Angebots-ID festgelegt werden. Diese ist natürlich nicht null und es gibt bis zu drei Preisstufen. Wir müssen zwischen „gefälschten“ Angeboten und „echten“ Angeboten unterscheiden. Verwenden Sie dann PricingPhases, um den Abonnementzyklus und den Preis von BasePlan, die Rabattstrategie des Angebots und die konkrete Festlegung der Preisstufe des Angebots zu analysieren. Auf diese Weise können wir dem Benutzer die Preisinformationen des gesamten Produkts vollständig anzeigen.

launchBillingFlow

launchBillingFlow wird zum Aufrufen des Zahlungs-Popup-Fensters zum Einleiten von Zahlungsvorgängen verwendet. Je nach Produkttyp ist die Aufrufmethode in zwei Typen unterteilt:

Wenn Sie ein einmaliges Produkt kaufen möchten, benötigen die Zahlungsparameter nur ProductDetails.

private suspend fun launchBilling(
    activity: Activity,
    billingClient: BillingClient,
    productDetails: ProductDetails
): BillingResult {
    return withContext(context = Dispatchers.Main.immediate) {
        val productDetailsParams = BillingFlowParams
            .ProductDetailsParams
            .newBuilder()
            .setProductDetails(productDetails)
            .build()
        val billingFlowParams = BillingFlowParams
            .newBuilder()
            .setProductDetailsParamsList(listOf(productDetailsParams))
            .build()
        billingClient.launchBillingFlow(activity, billingFlowParams)
    }
}

Wenn Sie ein Abonnementprodukt erwerben möchten, müssen Sie ProductDetails und offerToken gleichzeitig übergeben

Da ein Abonnementprodukt mehrere BasePlans und mehrere Angebote gleichzeitig enthalten kann, sind die Rabattstrategien der einzelnen Angebote unterschiedlich. Wenn die App einen Zahlungsvorgang initiiert, muss sie daher das offerToken verwenden, um anzugeben, welchen BasePlan der Benutzer kaufen möchte und welches Angebot ausgewählt ist. Und da Google Play auch den ursprünglichen Preis von BasePlan als Angebot betrachtet und zurückgibt, können wir entscheiden, ob wir den Nutzern den Rabatt gewähren möchten, und der Grad der Freiheit ist relativ hoch.

private suspend fun launchBilling(
    activity: Activity,
    billingClient: BillingClient,
    productDetails: ProductDetails,
    offerToken: String
): BillingResult {
    return withContext(context = Dispatchers.Main.immediate) {
        val productDetailsParams = BillingFlowParams
            .ProductDetailsParams
            .newBuilder()
            .setProductDetails(productDetails)
            .setOfferToken(offerToken)
            .build()
        val billingFlowParams = BillingFlowParams
            .newBuilder()
            .setProductDetailsParamsList(listOf(productDetailsParams))
            .build()
        billingClient.launchBillingFlow(activity, billingFlowParams)
    }
}

Danach erhalten wir das Zahlungsergebnis des Benutzers im PurchasesUpdatedListener-Callback.

Wenn der Benutzer erfolgreich bezahlt hat, enthält Purchase die spezifischen Informationen dieser Bestellung, einschließlich ProductId, OrderId, Quantity, PurchaseTime usw.

private val purchasesUpdatedListener =
    PurchasesUpdatedListener { billingResult: BillingResult, purchases: List<Purchase>? ->
        when (billingResult.responseCode) {
            BillingClient.BillingResponseCode.OK -> {
                if (!purchases.isNullOrEmpty()) {
                    purchases.forEach {
                        when (it.purchaseState) {
                            Purchase.PurchaseState.PURCHASED -> {
                                //用户支付成功
                            }

                            Purchase.PurchaseState.PENDING -> {
                                //用户仅是预创建了订单,还未真正付款
                            }

                            Purchase.PurchaseState.UNSPECIFIED_STATE -> {
                                //未知
                            }
                        }
                    }
                }
            }

            BillingClient.BillingResponseCode.USER_CANCELED -> {
                //用户取消支付
            }

            else -> {

            }
        }
    }

Bestätigen Sie den Kauf

Nachdem die Zahlung des Nutzers erfolgreich war, muss die Bestellung bestätigt werden, andernfalls erstattet Google Play dem Nutzer innerhalb einer begrenzten Zeit den Betrag.

private suspend fun acknowledgePurchase(
    billingClient: BillingClient,
    purchase: Purchase
): Boolean {
    return withContext(context = Dispatchers.Default) {
        if (purchase.purchaseState != Purchase.PurchaseState.PURCHASED) {
            return@withContext false
        }
        if (purchase.isAcknowledged) {
            return@withContext true
        }
        if (!billingClient.isReady) {
            return@withContext false
        }
        val acknowledgePurchaseParams = AcknowledgePurchaseParams
            .newBuilder()
            .setPurchaseToken(purchase.purchaseToken)
            .build()
        val acknowledgePurchase = billingClient.acknowledgePurchase(acknowledgePurchaseParams)
        acknowledgePurchase.responseCode == BillingClient.BillingResponseCode.OK
    }
}

verbrauchenKauf

Wenn der Benutzer ein einmaliges Verbrauchsprodukt kauft, muss er basierend auf dem tatsächlichen Geschäft eine Möglichkeit auswählen, Verbrauchsvorgänge für die Bestellung durchzuführen.

private suspend fun consumePurchase(
    billingClient: BillingClient,
    purchase: Purchase
): Boolean {
    return withContext(context = Dispatchers.Default) {
        if (purchase.purchaseState != Purchase.PurchaseState.PURCHASED) {
            return@withContext false
        }
        if (!billingClient.isReady) {
            return@withContext false
        }
        val consumeParams = ConsumeParams
            .newBuilder()
            .setPurchaseToken(purchase.purchaseToken)
            .build()
        val consumeResult = billingClient.consumePurchase(consumeParams)
        consumeResult.billingResult.responseCode == BillingClient.BillingResponseCode.OK
    }
}

5. Authentifizierung

Nachdem ein Benutzer ein Produkt gekauft hat, muss er darüber nachdenken, wie er den Benutzer authentifiziert. Wenn die Authentifizierung fehlschlägt oder falsch ist, führt dies nicht nur zu schlechten Erfahrungen für die Benutzer und zieht Benutzerbeschwerden nach sich, sondern kann auch zu unermesslichen finanziellen Verlusten für das Projekt führen.

Wenn eine App von einem Benutzer verwendet wird, erstellt die App im Allgemeinen eine Benutzeridentität unter ihrem eigenen Kontosystem für den aktuellen Benutzer, die wir appUser nennen können. Wenn ein Benutzer ein Produkt kauft, wird die Bestellung auch an das Google Play-Konto gebunden, mit dem das aktuelle Gerät bezahlt wurde, das wir gpUser nennen können.

Auf diese Weise wird diese Bestellung aus zwei verschiedenen Perspektiven auf Benutzer bezogen. Damit stellt sich auch die Frage in der Kette: Auf welchen Benutzernamen sollen die durch das Produkt repräsentierten Rechte eingetragen werden? appUser oder gpUser?

Beide Optionen haben ihre Vor- und Nachteile

Unter dem Namen appUser gemountet:

  • Vorteile: Benutzerrechte sind klar und deutlich und der Rechtestatus der Benutzer kann genau isoliert werden.
  • Nachteile: Im Ausland ist es sehr üblich, als Tourist virtuelle Güter zu kaufen. Wenn die App nur offiziellen Nutzern (mit einer E-Mail-Adresse oder Telefonnummer) den Kauf von Gütern ermöglicht, ist es sehr wahrscheinlich, dass dies die meisten potenziellen zahlenden Nutzer sein werden verloren. Wenn der App-Benutzer ein Tourist ist und der Benutzer die App deinstalliert, das Gerät ändert oder zurücksetzt, kann der zahlende Benutzer die Bestellung daher möglicherweise nicht mehr abrufen.

Unter dem Namen gpUser gemountet:

  • queryPurchasesAsyncVorteile: Selbst wenn der Benutzer die App deinstalliert, das Gerät ändert oder zurücksetzt, kann die App über das Billing SDK alle Bestellinformationen unter dem Kontonamen abrufen , solange das aktuelle Gerät mit dem für die Zahlung verwendeten Google Play-Konto angemeldet ist Methode, ohne Rücksicht auf Rechte und Interessen. Verlorene Situation. Das gleiche Google Play-Konto kann auch die Rechte der App auf verschiedenen Geräten teilen, und das Benutzererlebnis ist das Beste
  • Nachteile: Die App kann die eindeutige Identität des gpUser nicht erhalten und es kann leicht zu einem Weiterverkauf des Kontos kommen. Mehrere Benutzer teilen sich dasselbe Google Play-Konto, um die Rechte und Interessen derselben Reihenfolge zu genießen.

Daher muss die App anhand ihres Geschäftstyps und ihrer Benutzerattribute entscheiden, ob Touristen Einkäufe tätigen dürfen. In welcher Dimension sollte der Benutzer seine Identität authentifizieren? Wenn festgestellt wird, dass dieselbe Bestellung auf mehreren Geräten gültig ist, und wie dies vermieden werden kann Vermögensverluste

6. Endlich

In diesem Artikel wird dies hauptsächlich aus der Perspektive des mobilen Endgeräts erläutert. Obwohl das Google Play-Abrechnungssystem auch die direkte Durchführung des gesamten Zahlungsvorgangs und der Benutzerauthentifizierung ohne Beteiligung des App-Backend-Dienstes ermöglicht, ist dies aus Sicherheitsgründen am besten Die Bestellinformationen werden synchron auf dem Server gespeichert und der Server überprüft die Bestellung, bevor er entscheidet, ob die Rechte erteilt werden. Darüber hinaus können Benutzer Abonnements direkt von Google Play aus kündigen oder wiederherstellen, ohne die App nutzen zu müssen. Die App kann die Statusänderungen der Bestellung nicht in Echtzeit erkennen. Derzeit benachrichtigt Google Play den Entwickler nur in Echtzeit über solche Änderungen . Änderungen werden dem Server mitgeteilt. In diesem Fall ist auch die Beteiligung des Servers erforderlich, um die gesamte Zahlungsstatusänderung des Benutzers vollständig zu erfassen.

Android-Studiennotizen

Artikel zur Optimierung der Android-Leistung: https://qr18.cn/FVlo89
Artikel zum Android-Fahrzeug: https://qr18.cn/F05ZCM
Hinweise zur Android-Reverse-Sicherheitsstudie: https://qr18.cn/CQ5TcL
Artikel zu den zugrunde liegenden Prinzipien des Android-Frameworks: Artikel zu https://qr18.cn/AQpN4J
Android-Audio und -Video: Artikel https://qr18.cn/Ei3VPD
zum Jetpack-Familien-Bucket (einschließlich Compose): https://qr18.cn/A0gajp
Kotlin-Artikel: https://qr18.cn/CdjtAF
Gradle-Artikel: https://qr18.cn/DzrmMB
Hinweise zur OkHttp-Quellcode-Analyse: https://qr18.cn/Cw0pBD
Flutter-Artikel : https://qr18.cn/DIvKma
Acht Wissenssammlungen zu Android: https://qr18.cn/CyxarU
Android-Kernnotizen: https://qr21.cn/CaZQLo
Android-Interviewfragen aus früheren Jahren: https://qr18.cn/CKV8OZ
Die neuesten Android-Interviewfragen im Jahr 2023: https://qr18.cn/CgxrRy
Android-Interviewübungen für Fahrzeugentwicklungspositionen: https://qr18.cn/FTlyCJ
Audio- und Videointerviewfragen:https://qr18.cn/AcV6Ap

Guess you like

Origin blog.csdn.net/weixin_61845324/article/details/132760296