1. Introduction
I have been working on the overseas project of Android recently, and I need to use Google’s settlement database. Here is a summary of the integration process, the important points, and the potholes.
2. Introduction
Google Pay is an in-app payment service provided by Google Paly. You can use Gradle to remotely rely on the Google Clearing library.
Use 3.
3.1 Prerequisites
Before integrating a settlement repository, you need to have the following things in place:
- Scientific Internet access through VPN and other means.
- Google Developer Account
- Release the app (official or beta) and create in-app merchandise.
There are many steps to publish an application and create a product, which are described in detail here. Our ultimate goal is to be able to release the app into beta or final release. Only after all the information about the app to be published has been filled in and all the checkboxes have turned green. To release the version. For example, when filling in the pricing and distribution range, you need to upload an APK first before you can continue filling in. Then you need to upload an APK in the application version before you continue filling in. Be patient and follow the instructions. Create goods to add to in-app goods. In-order goods are created in managed goods and subscription products are created in subscriptions. So fill in the information, you can go to the application version -> Administration -> View -> publish to XX version to publish.
3.2 Integrate Google Settlement library
Main reference to official documents, if you can scientific Internet access as much as possible to see official documents, patience will step on a lot of pits. Integration is simple, just rely on it:
implementation 'com. Android. Billingclient: billing: the 2.0.3'
Copy the code
3.3 the use of
The whole payment process is divided into 5 steps in android client:
- Establish a connection
- Query the goods
- Tuning up the payment
- Payment result callback
- Consumer goods
The whole process is to first establish a connection with Google Play, check whether the application exists the product through the product ID, then pay, if the payment is successful, the consumption of the product. The client verifies the payment with the server.
The payment tool class is encapsulated as follows:
public class GooglePayUtils implements PurchasesUpdatedListener {
String TAG = ".GooglePayUtils"; private BillingClient mBillingClient = null; // Whether a connection has been established private Boolean isClientInit =false; Private MyListener mListener = null; private Context mContext = null; private String orderId ="";
private String purchaseId = ""; / / buy type: purchase, subscription, the default for the purchase private String purchaseType = BillingClient. SkuType. INAPP; public GooglePayUtils(Context context, MyListener mListener, String orderId, String purchaseId, String purchaseType) { this.mContext = context; this.mListener = mListener; this.orderId = orderId; this.purchaseId = purchaseId; this.purchaseType = purchaseType; } // 1. Set up a connection to public GooglePayUtilspay() {
mBillingClient = BillingClient.newBuilder(mContext).enablePendingPurchases().setListener(this).build();
mBillingClient.startConnection(new BillingClientStateListener() {
@Override
public void onBillingSetupFinished(BillingResult billingResult) {
Log.e(TAG, "onBillingSetupFinished code = " + billingResult.getResponseCode() + " , msg = " + billingResult.getDebugMessage());
if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK) {
isClientInit = true;
queryAndPayPurchases(purchaseId);
}
}
@Override
public void onBillingServiceDisconnected() {
isClientInit = false; }});returnthis; } private void QueryAndPayID (@nonNULL final String purchaseId) {private void QueryAndPayID (@nonNULL final String purchaseId) {if(! isClientInit) {if(mListener ! = null) { mListener.onError(mContext.getResources().getString(R.string.not_connect)); }return;
}
List<String> skuList = new ArrayList<>();
skuList.add(purchaseId);
// skuList.add("xxx"); / / this parameter cannot be null, preach SkuDetailsParams casually. The Builder params = SkuDetailsParams. NewBuilder (); params.setSkusList(skuList).setType(purchaseType); mBillingClient.querySkuDetailsAsync(params.build(), newSkuDetailsResponseListener() {
@Override
public void onSkuDetailsResponse(BillingResult billingResult,
List<SkuDetails> skuDetailsList) {
Log.e(TAG, "onSkuDetailsResponse code = " + billingResult.getResponseCode() + " , msg = " + billingResult.getDebugMessage() + " , skuDetailsList = " + skuDetailsList);
// Process the result.
if(billingResult.getResponseCode()! = BillingClient.BillingResponseCode.OK) { onFail(mContext.getResources().getString(R.string.no_goods));return;
}
if (skuDetailsList == null || skuDetailsList.isEmpty()) {
if(mListener ! = null) { mListener.onError(mContext.getResources().getString(R.string.no_goods)); }return;
}
SkuDetails skuDetails = null;
for (SkuDetails details : skuDetailsList) {
Log.e(TAG, "onSkuDetailsResponse skuDetails = " + details.toString());
if(purchaseId.equals(details.getSku())) { skuDetails = details; }}if(skuDetails ! = null) { pay(skuDetails); }else {
if(mListener ! = null) { mListener.onError(mContext.getResources().getString(R.string.no_goods)); }}}}); } / / 3. The pay for private void pay (SkuDetails SkuDetails) {BillingFlowParams flowParams = BillingFlowParams. NewBuilder () .setSkuDetails(skuDetails) .build(); int code = mBillingClient.launchBillingFlow((Activity) mContext, flowParams).getResponseCode();if(BillingClient.BillingResponseCode.OK! =code) { onFail(mContext.getResources().getString(R.string.dump_pay_faile)); }} //4. Payment callback @override public void onPurchasesUpdated(BillingResult BillingResult, @Nullable List<Purchase> purchases) { Log.e(TAG,"onPurchasesUpdated code = " + billingResult.getResponseCode() + " , msg = " + billingResult.getDebugMessage());
if(billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK && purchases ! = null) {for(Purchase purchase : purchases) { handlePurchase(purchase); }}else if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.USER_CANCELED) {
if (mListener != null) {
mListener.onError(mContext.getResources().getString(R.string.pay_cancle));
}
} else {
// Handle any other error codes.
if(mListener ! = null) { mListener.onError(mContext.getResources().getString(R.string.pay_faile)); }}} //5. If the payment is successful, go to consume the payment. If the payment is successful, no consumption will be automatically refunded. private void handlePurchase(Purchase purchase) { //if (purchase.getPurchaseState() == Purchase.PurchaseState.PURCHASED) {
// }
if(! purchase.isAcknowledged()) {if(BillingClient.SkuType.INAPP.equals(purchaseType)){
ConsumeParams consumeParams =
ConsumeParams.newBuilder()
.setPurchaseToken(purchase.getPurchaseToken())
.setDeveloperPayload(orderId)
.build();
mBillingClient.consumeAsync(consumeParams, new ConsumeResponseListener() {
@Override
public void onConsumeResponse(BillingResult billingResult, String purchaseToken) {
Log.e(TAG, "onConsumeResponse code = " + billingResult.getResponseCode() + " , msg = " + billingResult.getDebugMessage() + " , purchaseToken = "+ purchase.getPurchaseToken()); // The consumer successfully handles its own process, I choose to save the database firstif (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK) {
if (mListener != null) {
mListener.onSuccess(purchase.getPurchaseToken());
}
} else{// Failed to consume, then query the consumption record and consume again, otherwise, you can only wait for the refundif(mListener ! = null) { mListener.onError(mContext.getResources().getString(R.string.pay_success_comfirm_faile)); }}}}); }else {
AcknowledgePurchaseParams acknowledgePurchaseParams =
AcknowledgePurchaseParams.newBuilder()
.setPurchaseToken(purchase.getPurchaseToken()).setDeveloperPayload(orderId)
.build();
mBillingClient.acknowledgePurchase(acknowledgePurchaseParams, new AcknowledgePurchaseResponseListener() {
@Override
public void onAcknowledgePurchaseResponse(BillingResult billingResult) {
Log.e(TAG, "onConsumeResponse code = " + billingResult.getResponseCode() + " , msg = " + billingResult.getDebugMessage() + " , purchaseToken = "+ purchase.getPurchaseToken()); // The consumer successfully handles its own process, I choose to save the database firstif (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK) {
if (mListener != null) {
mListener.onSuccess(purchase.getPurchaseToken());
}
} else{// Failed to consume, then query the consumption record and consume again, otherwise, you can only wait for the refundif(mListener ! = null) { mListener.onError(mContext.getResources().getString(R.string.pay_success_comfirm_faile)); }}}}); }}else {
if(mListener ! = null) { mListener.onError(mContext.getResources().getString(R.string.pay_success_comfirm_faile)); } } } public interface MyListener { void onSuccess(String purchaseToken); void onError(String msg); } private void onFail(String str){if(mListener ! = null) { mListener.onError(str); }}}Copy the code
3.4 test
Once the code is written, all you have to do is test it. There are two types of test purchases, one is consumable that is, the type of purchase is in-app purchase. One is non-consumable, and the purchase type is subscription. To test in-app purchase, simply upload a few preset product ids to the settlement database for testing, and view them in the official documentation. In the case of subscription, the application needs to be published to the official release before it can be tested. After the first release, the review time will be relatively long, about 3-4 days. The page shows that the update is being processed or reviewed.
- Adding a Test Account
To test payments, you need to add a Google Test account to the console. Add a test account here: Console -> Developer Account -> Account Details -> Gmail account available for testing
With all this in place, you can test the payment by passing the item ID and item type to the payment tool class above.
What are the pits in the testing process:
-
There is no scientific Internet, resulting in less than query goods.
-
The mobile phone login is not the newly added test account, so the payment box is activated, but a message such as unable to pay is displayed. Go to Mobile -> Settings -> Accounts/Sync -> Google Account.
-
The version number verionCode, applicationId applicationId, and signature must be consistent with those uploaded to the console.
-
Subscriptions are automatically renewed, and you need to find the unsubscribe entry in the renewal email sent by Google to continue testing subscription payments. If not, the system is processing your order, try again later.
4. To summarize
- Create apps and in-app products on the Google Play console.
- Publish the application to beta or beta (test subscription required).
- Integrate settlement library and encapsulate payment tool class according to official documents.
- Add a test account to the Google Play console and use this account to test payments.
5. Catalogue of historical articles
- Juejin. Cn/post / 684490…