In-app Billing trong android - làm giàu không khó : Part 2 - work flow

Tiếp tục bài giới thiệu lần trước, hôm nay mình xin được tiếp tục trình bày về cách implement code hoàn chỉnh và cách để test dịch vụ này !

Pre-conditions

  • Như mình đã nói ở bài trước, có rất nhiều loại sản phẩm mà bạn có thể bán trong app của mình, đó là managed productsubscription, Managed product được gọi là các vật phẩm, sản phẩm mà người dùng có thể mua và sử dụng ngay tại trong ứng dụng hoặc game. Còn subscription đó là việc người dùng mua các nội dung, dịch vụ hay tính năng ở bên trong ứng dụng của bạn bằng cách trả tiền hàng tháng hoặc định kỳ, một loại đều có những đặc điểm riêng tùy thuộc vào nhu cầu sử dụng của bạn, chi tiết hơn có thể xem ở đây, điều quan trọng là chúng được đại diện bởi một product ID, đây là key được sử dụng đồng bộ giữa app và google play server.
  • Thêm ứng dụng của bạn vào Play console :
    • Đăng nhập vào trang google play console, nếu bạn chưa có tài khoản developer thì phải đăng kí trước khi tiếp tục, à, để bán được sản phẩm trong app, bạn cũng cần một tài khoản Google payments,
    • Trong All Applications tab:
      1. Click Add new application.
      2. Nhập tên của ứng dụng.
      3. Click Prepare Store Listing.
    • Trong Services & APIs tab, tìm và lưu lại public license key mà Google Play đã tạo ra cho ứng dụng của bạn. Đây là một chuỗi kí tự Base64, chúng ta sẽ khai báo nó trong code của mình để có thể sử dụng được dịch vụ in-app billing.

Work flow

Có một điều tuyệt vời là google đã code hết mọi thứ cho chúng ta, từ việc khởi tạo đến việc mã hóa các giá trị cần thiết, tất nhiên là bạn có thể tự làm tất cả những việc này, nhưng mà theo mình nghĩ là không nên, nó sẽ khiến ứng dụng của bạn bị reject khi publish. Về cơ chế hoạt động thì đầu tiên, chúng ta sẽ phải tạo 1 sản phẩm ở phía Google Play có 1 product id , sau đó tạo 1 sản phẩm phía client và đặt product id là id vừa được tạo ở phía Google Play. Sản phẩm này có thể là maganed product hoặc subscription tuỳ bạn chọn. Khi user thực hiện mua sản phẩm, sẽ có một pop-up của Google Play để thực hiện việc thanh toán. Sau khi thực hiện các bước thanh toán như nhập thẻ visa, nhập mật khẩu, confirm thanh toán… Google Play sẽ xử lý đơn hàng. Sau khi xử lý thành công đơn hàng, Google Play server sẽ trả thông tin về receipt(hoá đơn) cũng như transaction(giao dịch) . Và phía client sẽ xử lý các vật phẩm hoặc chức năng tương ứng mà user đã đặt mua.

Thực tế thì ứng dụng của chúng ta không kết nói trực tiếp với  Google Play server mà thông qua  Google Play của thiết bị, và việc handle mọi kết quả trả về ở chính ứng dụng của mình không phải là một cách bảo mật tốt, việc sử dụng một server riêng và các cơ chế để tăng tính bảo mật cho các hoạt động giao dịch thì mình sẽ đề cập ở một bài khác, còn trong nội dung bài viết này, mình sẽ demo một ứng dụng in-app billing loại subscription, sau đây là một số hàm chính để thực hiện các tác vụ cơ bản:

setup billing

Hàm gọi đầu tiên để thực hiện quá trình setup PREMIUM_MONTHLY: đây chính là product Id, id này mà một giá trị trùng với giá trị được khai báo trên Google Play console. BillingUtil.BILLING_PUBLIC_KEY: public key mà mình đã đề cập ở trên

 mBillingHelper = new IabHelper(this, BillingUtil.BILLING_PUBLIC_KEY);
        mBillingHelper.startSetup(new IabHelper.OnIabSetupFinishedListener() {
            public void onIabSetupFinished(IabResult result) {
                if (result.isFailure()) {
                    // onSetupFailure
                } else {
                    Inventory inventory = null;
                    try {
                        inventory = mBillingHelper.queryInventory(true, new ArrayList<String>() {
                            {
                                add(PREMIUM_MONTHLY);
                            }
                        });
                    } catch (IabException e) {
                      // failed to get price
                    }
                    if (inventory != null && inventory.hasDetails(PREMIUM_MONTHLY)) 
                        // handle iab setup finished 
                    }
                }
            }
        });

purchase

Hàm gọi một hành động khi user quyết định mua mặt hàng này, request lên Google Play server tiến hàng thanh toán và trả về kết quả

mBillingHelper.launchSubscriptionPurchaseFlow(this, PREMIUM_MONTHLY, REQUEST_CODE_PURCHASE,
                new IabHelper.OnIabPurchaseFinishedListener() {
                    public void onIabPurchaseFinished(IabResult result, Purchase purchase) {
                        if (result.isFailure()) {
                           // onPurchaseFailure
                        } else {
                            if (purchase.getSku().equals(PREMIUM_MONTHLY)) {
                                // onPurchaseSuccess
                                // savePurchaseStatus
                            } else {
                            // Purchase item not found
                            }
                        }
                    }
                })

restore

Giả sử user đã mua mặt hàng PREMIUM_MONTHLY nhưng lỡ tay xóa app hay clear mất data, app phải cho phép user được restore lại thông qua việc gọi hàm queryInventoryAsync

 mBillingHelper.queryInventoryAsync(new IabHelper.QueryInventoryFinishedListener() {
            public void onQueryInventoryFinished(IabResult result, Inventory inventory) {
                if (result.isFailure()) {
                    // onRestoreFailure
                } else {
                    if (inventory.hasPurchase(PREMIUM_MONTHLY)) {
                        // onRestoreSuccess
                        
                    } else {
                       // purchase history not found
                    }
                }
            }
        });

Sync Purchase status

Trong demo của mình, mặt hàng mình bán ra cho user là một gói premium theo tháng, trạng thái đó được lưu ở local (khá nguy hiểm, thực ra mình không khuyến khích cách làm này, tuy nhiên nếu bạn không có khả năng để build một server của riêng mình, thì cũng vẫn có nhưng cách để bảo mật giá trị này). Chúng ta phải kiểm tra xem gói đã hết hạn hay chưa thông qua việc check trạng thái của SKU đó:

// If premium flag is true, check whether it was expired
  mBillingHelper = new IabHelper(this, BillingUtil.BILLING_PUBLIC_KEY);
        mBillingHelper.startSetup(new IabHelper.OnIabSetupFinishedListener() {
            public void onIabSetupFinished(IabResult result) {
                if (result.isFailure()) {
                   //  BillingUtil.savePurchaseStatus =  IabHelper.BILLING_RESPONSE_RESULT_NOT_SET);
                } else {
                    mBillingHelper.queryInventoryAsync(new IabHelper.QueryInventoryFinishedListener(){
                        @Override
                        public void onQueryInventoryFinished(IabResult result, Inventory inventory) {
                            // If expired or invalid, remove premium flag.
                            if (inventory == null || inventory.getPurchase(PREMIUM_MONTHLY) == null) {
                                // BillingUtil.savePurchaseStatus = IabHelper.BILLING_RESPONSE_RESULT_NOT_SET
                            }
                            startMain(getIntent(), false);
                            if (dlg.isShowing()) dlg.dismiss();
                        }
                    });
                }

            }
        });

End

Sau bài viết này, hy vọng mọi người sẽ thấy việc tích hợp thanh toán vào ứng dụng của mình thật dễ dàng và thú vị, chúc các bạn sẽ gặt gái được nhiều thành công, à ý mình là tiền từ những dòng code của mình, ở bài viết sau, mình sẽ chia sẻ một số cách để bảo mật dữ liệu và các để test ưng dụng sử dụng in-app billing, cảm ơn vì đã theo dõi bài viết, have fun.


All Rights Reserved