Google in app billing là gì

Lưu ý: Trước khi đọc chủ đề này, hãy đảm bảo bạn đã đọc kỹ Tài liệu về Trung tâm trợ giúp của Play Console, mô tả các khái niệm quan trọng liên quan đến việc mua hàng, cũng như cách tạo và định cấu hình để bán các sản phẩm của bạn. Ngoài ra, hãy nhớ thiết lập trước cấu hình Google Play bằng cách làm theo các bước trong bài viết Chuẩn bị.

Chủ đề này mô tả cách tích hợp Thư viện Google Play Billing vào ứng dụng để bắt đầu bán sản phẩm.

Chủ đề này bao gồm các ví dụ về mã dựa trên ứng dụng mẫu chính thức trên GitHub. Bạn có thể xem các tài nguyên khác để biết danh sách đầy đủ ứng dụng mẫu và tài nguyên khác mà bạn có thể sử dụng trong khi tích hợp.

Vòng đời của một giao dịch mua hàng

Dưới đây là quy trình mua điển hình cho giao dịch mua hàng một lần hoặc một gói thuê bao.

  1. Hiển thị cho người dùng những sản phẩm mà họ có thể mua.
  2. Khởi chạy quy trình mua để người dùng chấp nhận giao dịch mua hàng.
  3. Xác minh giao dịch mua hàng trên máy chủ.
  4. Cung cấp nội dung cho người dùng.
  5. Xác nhận việc phân phối nội dung. Đối với các sản phẩm tiêu dùng, hãy tiến hành giao dịch mua để người dùng có thể mua lại mặt hàng đó.

Các gói thuê bao sẽ tự động gia hạn cho đến khi bị huỷ. Gói thuê bao có thể trải qua các trạng thái sau:

  • Đang hoạt động: Người dùng hiện ở trạng thái tốt và có quyền truy cập vào gói thuê bao.
  • Đã huỷ: Người dùng đã hủy nhưng vẫn có quyền truy cập cho đến khi hết hạn.
  • Trong thời gian gia hạn: Người dùng gặp phải vấn đề thanh toán nhưng vẫn có quyền truy cập trong khi Google đang thử lại phương thức thanh toán.
  • Tạm ngưng: Người dùng gặp phải vấn đề thanh toán và không còn quyền truy cập trong khi Google đang thử lại phương thức thanh toán.
  • Bị tạm dừng: Người dùng đã tạm dừng quyền truy cập và không có quyền truy cập cho đến khi họ tiếp tục.
  • Đã hết hạn: Người dùng đã hủy và mất quyền truy cập vào gói thuê bao. Người dùng được coi là rời bỏ ứng dụng khi gói thuê bao hết hạn.

Mã thông báo giao dịch mua hàng và mã đơn hàng

Google Play theo dõi các sản phẩm và giao dịch bằng cách sử dụng mã thông báo giao dịch mua hàng và mã đơn hàng.

  • Mã thông báo giao dịch mua hàng là một chuỗi thể hiện quyền của người mua đối với một sản phẩm trên Google Play. Nó cho biết người dùng Google có quyền sử dụng một sản phẩm cụ thể do và được đại diện bằng một đối tượng mua hàng. Bạn có thể sử dụng mã mua hàng bằng API Nhà phát triển Google Play.
  • Mã đơn hàng là một chuỗi đại diện cho một giao dịch tài chính trên Google Play. Chuỗi này đi kèm trong biên nhận được gửi qua email cho người mua.

Mã đơn hàng được tạo mỗi khi có giao dịch tài chính. Mã thông báo giao dịch mua chỉ được tạo khi người dùng hoàn tất quy trình mua.

  • Đối với các sản phẩm tính phí một lần, mỗi giao dịch mua hàng đều tạo ra một mã thông báo giao dịch mua hàng mới. Hầu hết các giao dịch mua đều tạo ra một Mã đơn hàng mới. Trường hợp ngoại lệ là khi người dùng không bị tính bất kỳ khoản phí nào như được mô tả trong Mã khuyến mãi.
  • Đối với các gói thuê bao, giao dịch mua ban đầu sẽ tạo mã thông báo giao dịch mua hàng và Mã đơn hàng. Đối với mỗi lần gia hạn tự động, mã mua hàng vẫn giữ nguyên và Mã đơn hàng mới được phát hành. Việc nâng cấp, hạ cấp, thay thế và đăng ký lại đều tạo ra các mã thông báo giao dịch mua và Mã đơn hàng mới.

Đối với các gói thuê bao, hãy lưu ý những nội dung sau:

  • Việc nâng cấp, hạ cấp gói thuê bao và các quy trình mua gói thuê bao khác sẽ tạo ra mã thông báo giao dịch mua thay thế cho mã thông báo giao dịch mua trước đó. Bạn phải vô hiệu hoá mã thông báo giao dịch mua trong trường linkedPurchaseToken của API Nhà phát triển Google Play. Để biết thêm thông tin, hãy xem bài viết Triển khai linkedPurchaseToken chính xác để ngăn các gói thuê bao trùng lặp.
  • Số đơn hàng để gia hạn gói thuê bao có thêm một số nguyên đại diện cho một lần gia hạn cụ thể. Ví dụ: Mã đơn hàng ban đầu của gói thuê bao có thể là GPA.1234-5678-9012-34567, trong đó Mã đơn hàng tiếp theo là GPA.1234-5678-9012-34567..0 [gia hạn lần đầu], GPA.1234-5678-9012-34567..1 [gia hạn lần hai], v.v.
Lưu ý: Nếu người dùng không phải trả tiền khi mua sản phẩm trong ứng dụng, chẳng hạn như trong thời gian dùng thử miễn phí gói thuê bao, Mã đơn hàng sẽ được phát hành với giá 0 USD. Ví dụ: khi người dùng hủy một gói thuê bao thì gói thuê bao vẫn có hiệu lực cho đến khi kỳ thanh toán kết thúc. Nếu người dùng quyết định đăng ký lại, một số tín dụng vẫn còn trong tài khoản của họ. Trong trường hợp này, một mã giao dịch mua hàng mới sẽ được tạo, Mã đơn hàng sẽ được tạo với giá 0 USD và gói thuê bao sẽ được gia hạn sau khi khoản tín dụng hết.

Xử lý lỗi

Thư viện Google Play Billing sẽ trả về lỗi dưới dạng BillingResult. BillingResult chứa BillingResponseCode, giúp phân loại các lỗi khả dĩ liên quan đến việc thanh toán mà ứng dụng của bạn có thể gặp phải. Ví dụ: nếu bạn nhận được mã lỗi SERVICE_DISCONNECTED, ứng dụng phải khởi động lại kết nối với Google Play. Ngoài ra, BillingResult còn chứa thông báo gỡ lỗi. Đây là một thông báo hữu ích trong quá trình phát triển để chẩn đoán lỗi.

Khởi tạo kết nối với Google Play

Bước đầu tiên để tích hợp với hệ thống thanh toán của Google Play là thêm Thư viện Google Play Billing vào ứng dụng của bạn và bắt đầu kết nối.

Thêm phần phụ thuộc Thư viện Google Play Billing

Lưu ý: Nếu đã làm theo hướng dẫn Giai đoạn chuẩn bị thì bạn đã thêm các phần phụ thuộc cần thiết và có thể chuyển sang phần tiếp theo.

Thêm phần phụ thuộc Thư viện Google Play Billing vào tệp build.gradle của ứng dụng như được hiển thị dưới đây:

dependencies { def billing_version = "5.0.0" implementation "com.android.billingclient:billing:$billing_version" }
dependencies { val billing_version = "5.0.0" implementation["com.android.billingclient:billing:$billing_version"] }

Nếu bạn đang sử dụng Kotlin, mô-đun KTX của Thư viện Play Billing chứa phần mở rộng và coroutine của Kotlin, cho phép bạn viết mã Kotlin tương thích khi sử dụng Thư viện Google Play Billing. Để đưa các tiện ích này vào dự án, hãy thêm phần phụ thuộc sau vào tệp build.gradle của ứng dụng như minh hoạ dưới đây:

dependencies { def billing_version = "5.0.0" implementation "com.android.billingclient:billing-ktx:$billing_version" }
dependencies { val billing_version = "5.0.0" implementation["com.android.billingclient:billing-ktx:$billing_version"] }

Khởi chạy BillingClient

Sau khi thêm một phần phụ thuộc vào Thư viện Google Play Billing, bạn cần khởi chạy một bản sao của BillingClient. BillingClient là giao diện chính để giao tiếp giữa Thư viện Google Play Billing và các phần còn lại của ứng dụng. BillingClient cung cấp các phương thức thuận tiện [cả đồng bộ và không đồng bộ] cho nhiều hoạt động thanh toán phổ biến. Chúng tôi đặc biệt khuyến nghị bạn chỉ nên có một kết nối BillingClient hiện hoạt tại một thời điểm để tránh tạo ra nhiều lệnh gọi lại PurchasesUpdatedListener cho một sự kiện duy nhất.

Để tạo BillingClient, hãy sử dụng newBuilder[]. Bạn có thể chuyển bất kỳ ngữ cảnh nào đến hàm newBuilder[], đồng thời BillingClient sử dụng hàm này để nhận ngữ cảnh của ứng dụng. Điều đó có nghĩa là bạn không cần lo lắng về việc rò rỉ bộ nhớ. Để nhận thông tin cập nhật về giao dịch mua, bạn cũng phải gọi hàm setListener[] bằng cách truyền tham chiếu đến một PurchasesUpdatedListener. Trình nghe này nhận nội dung cập nhật cho tất cả giao dịch mua trong ứng dụng.

private val purchasesUpdatedListener = PurchasesUpdatedListener { billingResult, purchases -> // To be implemented in a later section. } private var billingClient = BillingClient.newBuilder[context] .setListener[purchasesUpdatedListener] .enablePendingPurchases[] .build[]
private PurchasesUpdatedListener purchasesUpdatedListener = new PurchasesUpdatedListener[] { @Override public void onPurchasesUpdated[BillingResult billingResult, List purchases] { // To be implemented in a later section. } }; private BillingClient billingClient = BillingClient.newBuilder[context] .setListener[purchasesUpdatedListener] .enablePendingPurchases[] .build[];

Kết nối với Google Play

Sau khi đã tạo một BillingClient, bạn cần thiết lập kết nối với Google Play.

Để kết nối với Google Play, hãy gọi hàm startConnection[]. Quá trình kết nối không đồng bộ, và bạn phải triển khai BillingClientStateListener để nhận một lệnh gọi lại sau khi ứng dụng được thiết lập và sẵn sàng tạo thêm yêu cầu.

Bạn cũng phải triển khai logic thử lại để xử lý việc mất kết nối với Google Play. Để triển khai logic thử lại, hãy ghi đè phương pháp gọi lại onBillingServiceDisconnected[] và đảm bảo rằng BillingClient gọi phương thức startConnection[] để kết nối lại với Google Play trước khi tạo yêu cầu tiếp theo.

Ví dụ sau đây minh hoạ cách bắt đầu một kết nối và kiểm tra xem kết nối đã sẵn sàng để sử dụng chưa:

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. } }]
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. } }];

Lưu ý: Bạn nên triển khai logic kết nối lại của riêng mình và ghi đè phương thức onBillingServiceDisconnected[]. Hãy đảm bảo bạn duy trì kết nối BillingClient khi thực thi bất kỳ phương thức nào.

Hiển thị các sản phẩm có sẵn để mua

Sau khi thiết lập kết nối với Google Play, bạn có thể truy vấn các sản phẩm có sẵn của mình và hiển thị sản phẩm cho người dùng.

Truy vấn thông tin chi tiết về sản phẩm là một bước quan trọng trước khi hiển thị sản phẩm cho người dùng vì việc truy vấn này sẽ trả về thông tin sản phẩm đã bản địa hoá. Đối với gói thuê bao, hãy đảm bảo sản phẩm hiển thị tuân thủ tất cả chính sách của Play.

Để truy vấn thông tin chi tiết về sản phẩm trong ứng dụng, hãy gọi queryProductDetailsAsync[].

Để xử lý kết quả của hoạt động không đồng bộ, bạn cũng phải chỉ định một trình nghe có chức năng triển khai giao diện ProductDetailsResponseListener. Sau đó, bạn có thể ghi đè onProductDetailsResponse[] để thông báo cho trình nghe khi truy vấn kết thúc, như minh hoạ trong ví dụ sau:

val queryProductDetailsParams = QueryProductDetailsParams.newBuilder[] .setProductList[ ImmutableList.of[ Product.newBuilder[] .setProductId["product_id_example"] .setProductType[ProductType.SUBS] .build[]]] .build[] billingClient.queryProductDetailsAsync[ queryProductDetailsParams, ProductDetailsResponseListener { billingResult, productDetailsList -> // check billingResult // process returned productDetailsList } ]
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 productDetailsList] [] { // check billingResult // process returned productDetailsList } } ]

Khi truy vấn thông tin chi tiết về sản phẩm, hãy chuyển một bản sao của QueryProductDetailsParams để chỉ định danh sách các chuỗi mã sản phẩm được tạo trong Google Play Console cùng với ProductType. ProductType có thể là ProductType.INAPP đối với các sản phẩm tính phí một lần hoặc ProductType.SUBS đối với các gói thuê bao.

Truy vấn bằng tiện ích Kotlin

Nếu đang sử dụng phần mở rộng Kotlin, bạn có thể truy vấn thông tin chi tiết về sản phẩm trong ứng dụng bằng cách gọi hàm mở rộng queryProductDetails[].

queryProductDetails[] tận dụng coroutine của Kotlin để bạn không cần xác định một trình nghe riêng biệt. Thay vào đó, hàm này sẽ tạm ngưng cho đến khi truy vấn hoàn tất, sau đó bạn có thể xử lý kết quả:

suspend fun processPurchases[] { val productList = ArrayList[] productList.add["product_id_example"] val params = QueryProductDetailsParams.newBuilder[] params.setProductList[productList] .setType[ProductType.SUBS] // leverage queryProductDetails Kotlin extension function val productDetailsResult = withContext[Dispatchers.IO] { billingClient.queryProductDetails[params.build[]] } // Process the result. }

Xử lý kết quả

Thư viện Google Play Billing lưu trữ các kết quả truy vấn trong một List các đối tượng ProductDetails. Sau đó, bạn có thể gọi nhiều phương thức cho mỗi đối tượng ProductDetails trong danh sách để xem thông tin liên quan về một sản phẩm trong ứng dụng, chẳng hạn như giá hoặc phần mô tả. Để xem thông tin chi tiết về sản phẩm có sẵn, hãy xem danh sách các phương thức trong lớp ProductDetails.

Trước khi chào bán một mặt hàng, hãy kiểm tra để đảm bảo rằng người dùng chưa sở hữu mặt hàng đó. Nếu người dùng có một sản phẩm tiêu dùng vẫn còn trong thư viện mặt hàng, thì họ phải tiêu thụ trước khi có thể mua lại mặt hàng đó.

Trước khi đưa ra ưu đãi một gói thuê bao, hãy xác minh rằng người dùng chưa đăng ký. Ngoài ra, hãy lưu ý những điều sau:

  • queryProductDetailsAsync[] trả về thông tin chi tiết của sản phẩm đăng ký và tối đa 50 ưu đãi cho mỗi gói thuê bao.
  • queryProductDetailsAsync[] chỉ trả về những ưu đãi người dùng đủ điều kiện. Nếu người dùng cố gắng mua một ưu đãi họ không đủ điều kiện [ví dụ: nếu ứng dụng hiển thị danh sách các ưu đãi đủ điều kiện đã hết hạn], thì Play sẽ thông báo cho người dùng việc họ không đủ điều kiện, và họ có thể chọn mua gói cơ bản.
Lưu ý: Một số thiết bị Android có thể có phiên bản ứng dụng cũ của Cửa hàng Google Play và không hỗ trợ một số loại sản phẩm, chẳng hạn như các gói thuê bao. Trước khi ứng dụng bước vào quy trình thanh toán, bạn có thể gọi hàm isFeatureSupported[] để xác định xem thiết bị có hỗ trợ các sản phẩm bạn muốn bán hay không. Để biết danh sách các loại sản phẩm có thể được hỗ trợ, hãy xem BillingClient.FeatureType.

Bắt đầu quy trình mua

Để bắt đầu yêu cầu mua hàng từ ứng dụng của bạn, hãy gọi phương thức launchBillingFlow[] từ luồng chính của ứng dụng. Phương thức này tham chiếu đến đối tượngBillingFlowParams chứa đối tượng ProductDetails liên quan đã nhận được từ việc gọi hàm queryProductDetailsAsync[]. Để tạo một đối tượng BillingFlowParams, hãy dùng lớp BillingFlowParams.Builder.

// An activity reference from which the billing flow will be launched. val activity : Activity = ...; val billingFlowParams = BillingFlowParams.newBuilder[] // retrieve a value for "productDetails" by calling queryProductDetailsAsync[] .setProductDetails[productDetails] // to get an offer token, call ProductDetails.offerDetails[] // for a list of offers that are available to the user .setOfferToken[selectedOfferToken] .build[] // Launch the billing flow val billingResult = billingClient.launchBillingFlow[activity, billingFlowParams]
// An activity reference from which the billing flow will be launched. Activity activity = ...; BillingFlowParams billingFlowParams = BillingFlowParams.newBuilder[] .setProductDetailsParamsList[ ImmutableList.of[ ProductDetailsParams.newBuilder[] // retrieve a value for "productDetails" by calling queryProductDetailsAsync[] .setProductDetails[productDetails] // to get an offer token, call ProductDetails.getSubscriptionOfferDetails[] // for a list of offers that are available to the user .setOfferToken[selectedOfferToken] .build[] ] ] .build[]; // Launch the billing flow BillingResult billingResult = billingClient.launchBillingFlow[activity, billingFlowParams];

Phương thức launchBillingFlow[] trả về một trong nhiều mã phản hồi được liệt kê trong BillingClient.BillingResponseCode. Hãy kiểm tra kết quả này để đảm bảo không có lỗi khi khởi chạy quy trình mua. BillingResponseCode OK cho biết đã khởi chạy thành công.

Khi bạn gọi hàm launchBillingFlow[] thành công, hệ thống sẽ hiển thị màn hình mua hàng trên Google Play. Hình 1 hiển thị màn hình mua cho một gói thuê bao:

Hình 1. Màn hình mua hàng trên Google Play hiển thị một gói thuê bao mà bạn có thể mua.

Google Play gọi hàm onPurchasesUpdated[] để cung cấp kết quả của thao tác mua hàng cho một trình nghe có nhiệm vụ triển khai giao diện PurchasesUpdatedListener. Trình nghe này được chỉ định bằng phương thức setListener[] khi bạn khởi chạy ứng dụng của mình.

Bạn phải thực thi onPurchasesUpdated[] để xử lý các mã phản hồi khả thi. Ví dụ sau đây trình bày cách ghi đè onPurchasesUpdated[]:

override fun onPurchasesUpdated[billingResult: BillingResult, purchases: List?] { 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. } }
@Override void onPurchasesUpdated[BillingResult billingResult, List 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. } }

Giao dịch mua thành công sẽ tạo ra một màn hình mua hàng thành công trên Google Play, tương tự như hình 2.

Hình 2. Màn hình giao dịch mua thành công của Google Play.

Một lượt mua hàng thành công cũng tạo ra một mã mua hàng. Mã này là giá trị nhận dạng duy nhất, đại diện cho người dùng và mã sản phẩm của sản phẩm trong ứng dụng mà họ đã mua. Các ứng dụng có thể lưu trữ cục bộ mã thông báo giao dịch mua tuy nhiên chúng tôi khuyên bạn nên truyền mã thông báo tới máy chủ phụ trợ an toàn, tại đó bạn có thể xác minh giao dịch mua và bảo vệ bản thân khỏi hành vi gian lận. Quy trình này được mô tả kỹ hơn trong phần tiếp theo.

Người dùng cũng sẽ nhận được biên nhận giao dịch chứa Mã đơn hàng hoặc một mã nhận dạng duy nhất của giao dịch qua email. Người dùng sẽ nhận được một email kèm Mã đơn hàng duy nhất cho mỗi lần mua sản phẩm tính phí một lần, cũng như giao dịch mua gói thuê bao lần đầu và những lần gia hạn tự động định kỳ tiếp theo. Bạn có thể sử dụng Mã đơn hàng để quản lý tiền hoàn lại trong Google Play Console.

Báo giá dành riêng cho bạn

Nếu bạn có thể phân phối ứng dụng cho người dùng ở Liên minh Châu Âu, hãy sử dụng phương thức setIsOfferPersonalized[] để cho người dùng biết giá của mặt hàng được cá nhân hóa bằng quyết định tự động.

Hình 3. Màn hình mua hàng trên Google Play cho biết giá này được điều chỉnh cho phù hợp với người dùng.

Bạn phải tham khảo qua Art. 6 [1] [ea] CRD của Chỉ thị về quyền của người tiêu dùng [2011/83/EU] để xác định xem giá bạn cung cấp cho người dùng có được cá nhân hóa hay không.

setIsOfferPersonalized[] nhận giá trị nhập boolean. Khi true, giao diện người dùng Play có bao gồm thông tin công bố. Khi false, giao diện người dùng bỏ qua thông tin công bố. Giá trị mặc định là false.

Hãy truy cập vào Trung tâm trợ giúp người tiêu dùng để biết thêm thông tin.

Xử lý giao dịch mua hàng

Sau khi người dùng hoàn tất giao dịch mua, ứng dụng cần xử lý giao dịch mua đó. Trong hầu hết các trường hợp, ứng dụng sẽ được thông báo về giao dịch mua thông qua PurchasesUpdatedListener. nhưng có những trường hợp ứng dụng nhận biết được việc gọi hàm BillingClient.queryPurchasesAsync[] như mô tả trong phần Tìm nạp giao dịch mua.

Ứng dụng nên xử lý giao dịch mua theo cách sau:

  1. Xác minh giao dịch mua hàng.
  2. Cung cấp nội dung cho người dùng và xác nhận việc phân phối nội dung. Đánh dấu mặt hàng là đã tiêu thụ để người dùng có thể mua lại [không bắt buộc].

Để xác minh một giao dịch mua hàng, trước tiên hãy kiểm tra xem trạng thái mua hàng có phải là PURCHASED hay không. Nếu giao dịch mua là PENDING, bạn nên xử lý giao dịch mua như được mô tả trong phần Xử lý các giao dịch đang chờ xử lý. Đối với các giao dịch mua nhận được từ onPurchasesUpdated[] hoặc queryPurchasesAsync[], bạn nên xác minh thêm để đảm bảo tính hợp pháp của giao dịch mua trước khi ứng dụng cấp quyền. Để tìm hiểu cách xác minh giao dịch mua một cách chính xác, hãy xem phần Xác minh giao dịch mua trước khi cấp quyền.

Sau khi xác minh giao dịch mua, ứng dụng sẽ sẵn sàng cấp quyền cho người dùng. Sau khi cấp quyền, ứng dụng phải xác nhận giao dịch mua. Hoạt động xác nhận này cho Google Play biết rằng bạn đã cấp quyền cho giao dịch mua.

Lưu ýNếu bạn không xác nhận giao dịch mua trong vòng 3 ngày, người dùng sẽ tự động được hoàn tiền và Google Play sẽ thu hồi giao dịch mua đó.

Quy trình cấp quyền và xác nhận giao dịch mua phụ thuộc vào việc giao dịch mua thuộc loại giao dịch sản phẩm không phải hàng tiêu dùng, sản phẩm tiêu dùng hay một gói thuê bao.

Đối với giao dịch mua sản phẩm tiêu dùng, phương thức consumeAsync[] sẽ đáp ứng yêu cầu xác nhận và cho biết rằng ứng dụng đã cấp quyền cho người dùng. Phương thức này cũng cho phép ứng dụng đổi trạng thái của sản phẩm tính phí một lần thành có thể mua lại.

Để xác định sản phẩm tính phí một lần đã được tiêu thụ, hãy gọi hàm consumeAsync[] và bao gồm mã thông báo giao dịch mua mà Google Play cung cấp để mua lại. Bạn cũng phải truyền một đối tượng sẽ triển khai giao diện ConsumeResponseListener. Đối tượng này xử lý kết quả của hoạt động tiêu thụ. Bạn có thể ghi đè phương thức onConsumeResponse[] mà Thư viện Google Play Billing này sẽ dùng khi hoạt động hoàn tất.

Ví dụ sau minh hoạ việc tiêu thụ một sản phẩm bằng mã mua hàng được liên kết:

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

Lưu ý: Đôi khi, yêu cầu tiêu thụ có thể không thành công, do đó bạn phải kiểm tra máy chủ phụ trợ bảo mật để đảm bảo rằng mọi mã thông báo giao dịch mua đều chưa được sử dụng và ngăn ứng dụng cấp quyền nhiều lần cho cùng một giao dịch mua. Hoặc ứng dụng có thể chờ cho đến khi bạn nhận được phản hồi tiêu thụ thành công từ Google Play trước khi cấp quyền. Nếu bạn chọn giữ lại giao dịch mua hàng của người dùng cho đến khi Google Play gửi phản hồi tiêu thụ thành công, bạn phải hết sức cẩn thận để không mất dấu giao dịch mua sau khi nhận được yêu cầu tiêu thụ.

Để xác nhận giao dịch mua sản phẩm không phải hàng tiêu dùng, hãy sử dụng BillingClient.acknowledgePurchase[] từ Thư viện Billing hoặc Product.Purchases.Acknowledge từ API Nhà phát triển Google Play. Trước khi xác nhận giao dịch mua hàng, ứng dụng của bạn phải kiểm tra xem giao dịch đã được xác nhận hay chưa bằng cách sử dụng phương thức isAcknowledged[] trong Thư viện Google Play Billing hoặc trường acknowledgementState trong API Google Developers.

Ví dụ sau cho biết cách xác nhận giao dịch mua bằng cách sử dụng Thư viện Google Play Billing:

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[]] } } } }
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]; } } }

Gói thuê bao được xử lý tương tự như sản phẩm không phải hàng tiêu dùng. Bạn có thể xác nhận việc Xác nhận gói thuê bao bằng cách sử dụng hàm BillingClient.acknowledgePurchase[] từ Thư viện Google Play Billing hoặc Purchases.Subscriptions.Acknowledge từ API Nhà phát triển Google Play. Bạn cần xác nhận tất cả giao dịch mua gói thuê bao ban đầu. Không cần xác nhận việc gia hạn gói thuê bao. Để biết thêm thông tin về thời điểm cần xác nhận việc đăng ký, hãy xem chủ đề Bán gói thuê bao.

Tìm nạp các giao dịch mua

Theo dõi thông tin cập nhật về giao dịch mua bằng cách sử dụng PurchasesUpdatedListener là không đủ để đảm bảo rằng ứng dụng sẽ xử lý tất cả giao dịch mua. Có thể ứng dụng không biết tất cả giao dịch mua mà người dùng đã thực hiện. Dưới đây là một số trường hợp ứng dụng có thể bị mất dấu hoặc không biết về giao dịch mua:

  • Các vấn đề về mạng trong khi mua hàng: Người dùng mua hàng thành công và nhận được xác nhận từ Google, nhưng thiết bị của họ mất kết nối mạng trước khi thiết bị của họ nhận được thông báo về gia dịch mua thông qua PurchasesUpdatedListener.
  • Nhiều thiết bị: Người dùng mua một mặt hàng trên một thiết bị và kỳ vọng thấy mặt hàng đó khi chuyển đổi thiết bị.
  • Xử lý giao dịch mua mà bạn thực hiện bên ngoài ứng dụng: Người dùng có thể thực hiện một số giao dịch mua [như sử dụng các mã khuyến mãi] bên ngoài ứng dụng của bạn.

Để xử lý những trường hợp này, hãy đảm bảo ứng dụng gọi hàm BillingClient.queryPurchasesAsync[] trong phương thức onResume[] và để đảm bảo rằng tất cả giao dịch mua đều được xử lý thành công như mô tả trong phần xử lý giao dịch mua.

Xử lý giao dịch mua hàng được thực hiện bên ngoài ứng dụng

Một số giao dịch mua như sử dụng các mã khuyến mãi có thể diễn ra bên ngoài ứng dụng của bạn. Khi người dùng mua hàng bên ngoài ứng dụng, họ muốn ứng dụng hiển thị thông báo trong ứng dụng hoặc sử dụng một số cơ chế thông báo để người dùng biết rằng ứng dụng đã nhận và xử lý giao dịch mua một cách chính xác. Một số cơ chế được chấp nhận là:

  • Hiển thị một cửa sổ bật lên trong ứng dụng.
  • Chuyển thông báo tới hộp thông báo trong ứng dụng và nêu rõ rằng có một tin nhắn mới trong hộp thông báo trong ứng dụng.
  • Sử dụng một nội dung thông báo trên hệ điều hành.

Xin lưu ý rằng ứng dụng có thể ở bất kỳ trạng thái nào khi phát hiện giao dịch mua. Thậm chí ứng dụng có thể không được cài đặt khi giao dịch mua hàng được thực hiện. Người dùng mong muốn nhận thông tin về giao dịch mua khi tiếp tục sử dụng ứng dụng, bất kể ứng dụng đó đang trong trạng thái sử dụng nào.

Bạn phải phát hiện các giao dịch mua hàng bất kể ứng dụng đang trong trạng thái nào tại thời điểm người dùng mua hàng. Tuy nhiên, đôi khi cũng có những ngoại lệ có thể chấp nhận về việc không thông báo ngay lập tức cho người dùng rằng họ đã nhận được mặt hàng. Ví dụ:

  • Khi họ đang tham gia vào phần hành động của một trò chơi, thông báo hiển thị có thể khiến người dùng mất tập trung. Trong trường hợp này, bạn phải thông báo cho người dùng sau khi phần hành động này kết thúc.
  • Khi đoạn phim cắt cảnh đang chạy, việc hiển thị thông báo có thể khiến người dùng bị phân tâm. Trong trường hợp này, bạn phải thông báo cho người dùng sau khi đoạn phim cắt cảnh chạy hết.
  • Trong quá trình hướng dẫn ban đầu và thiết lập người dùng của trò chơi. Bạn nên thông báo cho người dùng mới về phần thưởng ngay sau khi họ mở trò chơi hoặc trong quá trình thiết lập người dùng ban đầu. Tuy nhiên, bạn có thể đợi cho đến khi cảnh chính trong trò chơi xuất hiện để thông báo cho người dùng.

Luôn nghĩ tới trải nghiệm của người dùng khi quyết định thời điểm và cách thông báo cho họ về giao dịch mua được thực hiện bên ngoài ứng dụng. Bất cứ khi nào người dùng không nhận được thông báo ngay lập tức, họ có thể cảm thấy bối rối, từ đó ngừng sử dụng ứng dụng, liên hệ với bộ phận hỗ trợ người dùng hoặc than phiền về việc đó trên mạng xã hội. Lưu ý: PurchasesUpdatedListenerđã đăng kýbối cảnh cho ứng dụng của bạn để xử lý thông tin cập nhật về giao dịch mua, bao gồm cả các giao dịch mua thực hiện bên ngoài ứng dụng của bạn. Điều này có nghĩa là nếu quy trình đăng ký của bạn không tồn tại, PurchasesUpdatedListener sẽ không được thông báo. Đây là lý do ứng dụng của bạn nên gọi BillingClient.queryPurchasesAsync[] trong phương thức onResume[] như đã đề cập trong Tìm nạp giao dịch.

Xử lý các giao dịch đang chờ

Lưu ý: Bạn phải xử lý các Giao dịch đang chờ xử lý trong Thư viện Google Play Billing phiên bản 2.0 trở lên. Bạn nên xử lý các giao dịch đang chờ xử lý một cách rõ ràng.Lưu ý: Bạn không thể sử dụng phương thức thanh toán bổ sung cho các giao dịch mua gói thuê bao.

Google Play hỗ trợ giao dịch đang chờ xử lý hoặc giao dịch yêu cầu một hoặc nhiều bước bổ sung giữa thời điểm người dùng thực hiện giao dịch mua và khi phương thức thanh toán cho giao dịch mua được xử lý. Ứng dụng không được cấp quyền cho các giao dịch mua này cho đến khi Google thông báo cho bạn rằng đã tính phí thành công phương thức thanh toán của người dùng.

Ví dụ: người dùng có thể tạo một giao dịch mua mặt hàng PENDING trong ứng dụng bằng cách chọn phương thức thanh toán là tiền mặt. Sau đó, người dùng có thể chọn một cửa hàng thực tế để hoàn tất giao dịch và nhận mã thông qua cả thông báo và email. Khi đến cửa hàng thực tế, người dùng có thể sử dụng mã này và thanh toán cho thu ngân bằng tiền mặt. Sau đó, Google sẽ thông báo cho cả bạn và người dùng rằng đã nhận được tiền mặt. Sau đó, ứng dụng có thể cấp quyền cho người dùng.

Ứng dụng phải hỗ trợ các giao dịch đang chờ xử lý bằng cách gọi hàm enablePendingPurchases[] trong khi khởi chạy ứng dụng.

Khi ứng dụng nhận được một giao dịch mua mới, thông qua PurchasesUpdatedListener hoặc từ việc gọi hàm queryPurchasesAsync[], hãy sử dụng phương thức getPurchaseState[] để xác định trạng thái mua hàng là PURCHASED hay PENDING.

Lưu ý: Bạn chỉ nên cấp quyền khi trạng thái là PURCHASED. Hãy sử dụng hàm getPurchaseState[] thay vì hàm getOriginaljson[] và đảm bảo xử lý giao dịch PENDING một cách phù hợp.

Nếu ứng dụng đang chạy khi người dùng hoàn tất giao dịch mua, PurchasesUpdatedListener sẽ được gọi lại và PurchaseState hiện là PURCHASED. Tại thời điểm này, ứng dụng có thể xử lý giao dịch mua hàng bằng cách sử dụng phương thức tiêu chuẩn để xử lý giao dịch mua hàng một lần. Ứng dụng cũng nên gọi hàm queryPurchasesAsync[] trong các phương thức onResume[] và PURCHASED của ứng dụng để xử lý những giao dịch mua đã chuyển sang trạng thái trong khi ứng dụng không chạy.

Lưu ý: Bạn chỉ nên xác nhận giao dịch mua hàng khi trạng thái là PURCHASED, tức là không xác nhận giao dịch mua hàng trong trạng thái PENDING. Thời hạn xác nhận ba ngày chỉ bắt đầu khi trạng thái mua hàng chuyển đổi từ "PENDING" [ĐANG CHỜ XỬ LÝ] thành "PURCHASED" [ĐÃ MUA].

Ứng dụng cũng có thể sử dụng Thông báo theo thời gian thực dành cho nhà phát triển cho các giao dịch mua đang chờ xử lý bằng cách lắng nghe OneTimeProductNotifications. Khi giao dịch mua chuyển từ trạng thái PENDING sang PURCHASED, ứng dụng sẽ nhận được thông báo ONE_TIME_PRODUCT_PURCHASED. Nếu giao dịch mua bị huỷ, ứng dụng sẽ nhận được thông báo ONE_TIME_PRODUCT_CANCELED. Điều này có thể xảy ra nếu khách hàng không hoàn tất việc thanh toán trong khung thời gian yêu cầu. Khi nhận được những thông báo này, bạn có thể sử dụng API Nhà phát triển Google Play, bao gồm trạng thái PENDING cho Purchases.products.

Lưu ý: Bạn có thể kiểm tra các giao dịch đang chờ xử lý bằng cách sử dụng trình kiểm thử giấy phép. Ngoài hai thẻ tín dụng kiểm thử, trình kiểm thử được cấp phép có quyền truy cập vào hai công cụ kiểm thử cho các phương thức thanh toán bị trì hoãn do khoản thanh toán tự động hoàn thành hoặc huỷ sau vài phút. Trong quá trình kiểm thử ứng dụng, bạn nên xác minh rằng ứng dụng không cấp quyền hoặc xác nhận giao dịch mua ngay sau khi mua bằng một trong hai công cụ này. Khi mua hàng bằng công cụ kiểm thử tự động hoàn tất, bạn nên xác minh rằng ứng dụng cấp quyền và xác nhận giao dịch mua hàng sau khi hoàn tất.

Bạn có thể tìm thấy các bước chi tiết về cách kiểm thử tình huống này trong phần Kiểm thử giao dịch mua hàng đang chờ xử lý.

Xử lý giao dịch mua số lượng nhiều

Được hỗ trợ trong phiên bản 4.0 trở lên của Thư viện Google Play Billing, Google Play cho phép khách hàng mua nhiều lần cùng một sản phẩm trong ứng dụng trong một giao dịch bằng cách chỉ định số lượng trong giỏ hàng. Ứng dụng cần xử lý các giao dịch mua hàng số lượng nhiều và cấp quyền dựa trên số lượng mặt hàng đã chỉ định.

Lưu ý:Số lượng nhiều dành cho các sản phẩm tiêu dùng trong ứng dụng, tức là các mặt hàng có thể mua, tiêu dùng và mua lại. Không bật tính năng này cho những sản phẩm chỉ mua một lần.

Để xử lý các giao dịch mua với số lượng nhiều, logic cấp phép của ứng dụng cần kiểm tra số lượng mặt hàng. Bạn có thể truy cập trường quantity từ một trong các API sau:

Sau khi thêm logic để xử lý giao dịch mua số lượng nhiều, bạn cần bật tính năng số lượng lớn cho sản phẩm tương ứng trên trang quản lý sản phẩm trong ứng dụng trong Google Play Console.

Lưu ý: Hãy đảm bảo rằng ứng dụng của bạn thực hiện giao dịch mua với số lượng nhiều trước khi bật tính năng này trong bảng điều khiển. Có thể bạn buộc phải cập nhật lên phiên bản ứng dụng hỗ trợ tính năng này trước khi có thể bật tính năng trên sản phẩm.

Ví dụ về mã

Truy vấn về giao dịch mua

Ví dụ sau đây cho thấy cách truy vấn giao dịch mua gói thuê bao của người dùng. Lưu ý queryPurchasesAsync[] chỉ trả về thuê bao đang hoạt động và không truy vấn được các giao dịch mua hàng một lần.

billingClient.queryPurchasesAsync[ QueryPurchasesParams.newBuilder[] .setProductType[ProductType.SUBS] .build[], /* purchaseResponseListener= */ this ]; // PurchaseResponseListener implementation. public void onQueryPurchasesResponse[BillingResult billingResult, List purchases] { // check BillingResult // process returned purchase list, e.g. display the plans user owns }

Đang tìm nạp lịch sử mua

queryPurchaseHistoryAsync[] trả về giao dịch mua gần đây nhất của người dùng đối với từng sản phẩm, ngay cả khi giao dịch mua đó đã hết hạn, bị hủy hoặc đã hoàn tất.

billingClient.queryPurchaseHistoryAsync[ QueryPurchaseHistoryParams.newBuilder[] .setProductType[ProductType.SUBS] .build[], /* purchaseHistoryResponseListener= */ this ]; // PurchaseHistoryResponseListener implementation. public void onQueryPurchaseHistoryResponse[ BillingResult billingResult, List purchasesHistoryList] { // check BillingResult // process returned purchase history list, e.g. display purchase history }

Video liên quan

Chủ Đề