Image credit: https://unsplash.com/photos/rQRKEu9HnZo
Author of this article: zoulp
In recent years, China's mobile applications have a good momentum of going overseas. For overseas applications involving transaction business , Google in-app payment is an essential payment channel. Different from the relatively complete mobile payment system in China, even though the official document provides a basic explanation on how to access Google's in-app payment, there are still many problems in the process of access. This article will introduce the key process and core technical points of the transaction, as well as the issues that need attention.
Access process
Glossary
First, three pairs of concepts are explained to help understand the logic of Google Payments.
One-time items vs. subscription items
A one-time item is an item acquired through a single purchase. Disposable commodities are further divided into consumable commodities and non-consumable commodities . Consumable commodities, as the name suggests, are commodities that can be consumed, such as gold coins or virtual currency provided by the App, which users can purchase repeatedly. Non-consumable items are perpetual benefits that can be obtained through a single purchase, such as paid upgrades.
Subscription products refer to products that are regularly purchased, such as membership services. Subscriptions will automatically renew until cancelled.
The discussion in this article is limited to consumable commodities and does not cover other types of commodities.
Consume vs Acknowledge
Both Consume and Acknowledge have the meaning of confirming after completing the payment, but they are not exactly the same.
Acknowledge is a confirmation operation in the actual sense. After Acknowledge is performed, the order will not be refunded. Acknowledge can be executed by the client API acknowledge() ) or by the Google server API acknowledge() . Google will automatically process refunds after three days for paid but unconfirmed orders.
Consume is an operation specifically for consumable commodities. Consume not only contains the meaning of confirmation, but also enables the commodity to be purchased repeatedly. Consume can be regarded as including the Acknowledge operation. Consume can only be completed by the client API consumeAsync() , not through the server API.
Business Server vs Google Server
This article will mention the operation of the server many times, and use the business server and the Google server to distinguish them to avoid confusion. The business server refers to the server of the App business logic. The Google server in this article refers specifically to the Google in-app payment server, provided by Google.
Overview of the transaction process
From a business point of view, a transaction process can be roughly represented by the following diagram:
However, in the actual transaction process, it is full of uncertain factors, such as unstable network environment of users, misoperation and so on. Due to the sensitivity of the transaction business, users cannot be asked to pay more, less or wrong. Therefore, it is necessary to comprehensively consider various possible situations, and fully consider and deal with the factors that may lead to abnormal order and payment status. From a technical perspective, the complete transaction process is as follows:
Detailed explanation of the key process of the transaction
Create Order
Creating an order here refers to creating an order on the business server. Once the order is created, the business order ID and corresponding Google product ID are passed to the next steps. The business server manages and maintains its own products and orders, which are different from Google's products and orders, and need to establish and maintain the association between them.
establish connection
Before making Google payment, you need to establish a connection with Google Play, and the bridge of the connection is BillingClient. BillingClient is an important tool provided by Google Play Billing Library, and all payment-related operations are related to it. If the connection is disconnected due to network and other reasons, you must reconnect to continue subsequent operations.
Inquire about products
For a product, it needs to be created in the Google background in advance. Querying a product is to query the product information configured in the Google background, confirm that the product information is correct, obtain the product details, and provide the necessary data for initiating payment.
initiate payment
Initiating payment is to call Google's payment interface through BillingClient's API launchBillingFlow()
, and the corresponding Google payment server order is created. The business server order and the Google server order need to be associated. The conventional method is that the client informs the business server the corresponding Google order ID when the order verification is initiated. In reality, the client may not receive the payment result due to some reasons. , in the scenario where the Google developer notifies the callback business server in real time, enough information is also required to associate. Here, the business server ID is passed in in an obfuscated way, so that the business server can associate the Google order with the business server order by means of the obfuscated ID, so as to complete the subsequent confirmation and performance.
Order Confirmation
After receiving the successful payment callback, the client actively calls the consumeAsync()
method provided by BillingClient to ensure that the order has been confirmed and will not be refunded and can be purchased again. Unconfirmed orders will be automatically refunded by Google after three days. In addition, it is necessary to actively initiate an order check to the business server.
order fulfillment
According to the process, the client initiates the verification of the order, and the server needs to perform the contract after confirming the validity of the order. In business, it usually shows the issuance of gold coins and the increase of the balance. The server must ensure the idempotency of this operation, fulfilling the contract once and only once, which is the premise of the order compensation mechanism.
order compensation
A payment process may be interrupted. What needs to be paid attention to is the situation where the user has completed the payment but did not receive the rights. This process is likely to cause customer complaints, and it is necessary to use order compensation as the bottom line.
Order compensation is divided into two scenarios. One is that the business server receives the Pub/Sub message through the real-time developer notification provided by Google, and learns that the payment status of the order has changed. At this time, the status of the order is checked. Perform the contract to protect the rights and interests of the user, and call the server-side acknowledge API to confirm the order to ensure that there is no automatic refund that causes capital loss.
Another scenario is that the client actively initiates the order compensation mechanism, and at the right time, obtains the paid but unconfirmed order for the subsequent consume and fulfillment process. Active compensation can be carried out at multiple times such as launching the App, entering the recharge purchase page, etc., and can be determined according to the business scenario. At the same time, the logic of the first scenario will also be improved. In the first scenario, the server Acknowledge is completed, and the rights are issued, but the product cannot be purchased again. At this time, the client completes the Consume, so that the product can be purchased repeatedly, forming the overall logic closed loop.
Technical realization
An important feature of transaction flow is that it is event-driven. Technically, the next action needs to be decided in a large number of callback methods. In a procedurally oriented way, the code will be nested in layers of callbacks. Such code logic is not clear enough and difficult to understand, and numerous callbacks will lead to complicated exception handling and difficulty in troubleshooting. In order to solve this problem, the entire transaction process can be regarded as a pipeline, and each step can be abstracted into sub-modules.
The callback directly provided by the Google Play Billing Library cannot form a pipeline, and a layer of conversion is required. CallbackFlow provided by Kotlin Coroutine is a Flow builder that converts callback-based APIs into Flows.
Logic encapsulation
The entire transaction process is divided into several sub-modules, so that the sub-modules can be connected and reusable. Each sub-module has specific input and output. The output of the previous sub-module is the input of the next sub-module. For example, the output of the query product sub-module is product details, and the product details are used as the input for initiating payment, which is displayed on the input panel. . Moreover, each sub-module needs to ensure its own logical cohesion, and only care about the work that needs to be done in the current process, not the next process.
We wrap the split independent submodules into CallbackFlow. After the operation is successful, the offer method is used to send data to the subsequent Flow outside the coroutine. If an error occurs, close() or cancel() the current Flow can be terminated. The granularity of the split is determined by the operation and the callback. The principle is that the function of the module is single and cohesive. Additionally, an instance of BillingClient is required throughout the operation, which is passed on input.
fun queryPurchasesFlow(client: BillingClient?): Flow<List<Purchase>> =
callbackFlow {
client?.queryPurchasesAsync(
BillingClient.SkuType.INAPP
) { p0, p1 ->
when (p0.responseCode) {
BillingClient.BillingResponseCode.OK -> {
// emit the value to the flow
offer(p1)
}
else -> {
// close the flow
close()
}
}
}
awaitClose {
// log & release resources
}
}
pipeline formation
After completing the encapsulation of a single operation, these Flows need to be assembled. CallbackFlow provides operators for concatenating and transforming Flows, where flatMapConcat transforms, flattens and returns a new Flow on the upstream elements. flatMapConcat is suitable for the current scene. An example of a series connection is as follows. After establishing a Google connection, obtain the product information, and call the payment panel after verification.
startConnectionFlow(client).flatMapConcat {
querySkuDetailFlow(client, request)
}.flatMapConcat {
launchBillingFlow(activity, client, it, request)
}.catch { e ->
// catch exception
e.printStackTrace()
}.collect {
processNext(it)
}
In addition, Flow can be flexibly orchestrated to implement different business logic. The order compensation process is not exactly the same as the normal payment process, and the corresponding flow needs to be rearranged. The same process can be reused with the payment logic without redevelopment.
overall design
As a core business component, Google Pay is provided to other modules of the App, which is characterized by easy access and simple interface. The architecture of its components is as follows:
Product layer: The caller of payment can be different forms of cashiers, web cashiers and native cashiers.
Interface layer: The payment component provides a simple external interface, payment initiation and order compensation.
Management layer: There are data management and connection management under the controller. Data management is the management of order and commodity-related data. Connection management is to manage the BillingClient provided by Google and disconnect at the right time.
Core layer: The core layer contains the core logic of the business, including establishing connections, obtaining products, etc. And includes the log and monitoring of the payment module.
Support layer: Relying on the existing underlying basic functions of the App.
Stepping on the pit summary
Get product details is empty
billingClient.querySkuDetailsAsync(params) { p0, p1 ->
when (p0.responseCode) {
BillingClient.BillingResponseCode.OK -> {
// p1 is empty
}
}
}
In the early debugging process, the product information obtained by using querySkuDetailsAsync() through google sku id was empty, and several influence points were found after sorting.
- The internal beta version needs to be released , and an internal beta version is released according to the requirements of the Google Console without waiting for approval.
- There is a certain delay in the creation of goods. In the early stage when the payment has never been successfully debugged, there will be a short delay, that is, the goods cannot be obtained at the moment of creation, and they are successfully obtained after a period of time. This situation did not occur subsequently.
- If the package name and signature do not match , you need to use the package name and signature of the uploaded PlayStore configuration. You do not need to use the same package submitted, but the package name and signature must match.
Unable to purchase the item you are looking for
There is a message that the product you want to buy cannot be purchased, and the possible reasons are:
- Check if the test user is in the internal test user list and the licensed test list.
- You need to log in to the account of the internal test, click the accept test invitation link , and accept the invitation.
necessary conditions
To successfully complete a payment, you need to pay attention to the following points in summary.
- The Google Services Framework for the test machine is installed.
- Google PlayStore detects IP non-country areas . Depending on the network environment, the country can also be set in the Google PlayStore (not required).
- The test account has been added to the Google background, including the addition of the internal test user and the addition of the license test , both of which need to be added.
- Accept the test invitation, find the internal test link, and click to accept the internal test invitation. This step is very important and easy to miss.
- Release the beta version , the application release status, without waiting for approval.
- The installation package signature and package name are consistent with the signature submitted to the Google backend.
- Version update for Google PlayStore.
At last
The particularity and importance of transaction business are self-evident. Whether it is to ensure the revenue of the app, or to accurately implement the user's transaction wishes and avoid customer complaints, the transaction business is required to consider various scenarios as much as possible. For developers, it is not only necessary to understand the entire business process of placing an order and payment, but also to abstract the business process through technical means, and realize the flexible arrangement of complex and changeable business scenarios and logical branches. Improve the maintainability and robustness of the system as a whole.
This article first briefly introduces the transaction process, and then uses the CallbackFlow of Kotlin Coroutine to realize the flexible arrangement of business links, and convert the nested callbacks and event notifications into streaming and linear writing. But even so, it still cannot cover all abnormal situations in the real scene. In addition to the order compensation mechanism, it is also necessary to analyze every case of transaction failure through automated and intelligent means, and build a complete monitoring and alarm mechanism. Continue to summarize and improve, which is where continuous investment is required in the follow-up.
Due to space limitations, each point cannot be introduced in detail. Readers are welcome to leave a message for discussion.
Reference link
- Google Play's billing system overview
- Integrate the Google Play Billing Library into your app
- play-billing-samples
- Is it possible to acknowledge consumable products from server side?
- Graphical Monad
- Functors, Applicatives, And Monads In Pictures
- CompletableFuture
- ListenableFutureExplained
- Kotlin flows on Android - Convert callback-based APIs to flows
- Simplifying APIs with coroutines and Flow
This article is published from the NetEase Cloud Music technical team, and any form of reprinting of the article is prohibited without authorization. We recruit various technical positions all year round. If you are ready to change jobs and happen to like cloud music, then join us at grp.music-fe(at)corp.netease.com!
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。