Android

Hướng dẫn sử dụng Google Play Billing Support Library để tích hợp In-app billing trong ứng dụng Android

Để thu phí sử dụng ứng dụng Android qua Google Play, các nhà phát triển có ba cách làm chủ yếu sau: Một là trực tiếp bán phiên bản có phí, bên cạnh việc có hoặc không phân phối một phiên bản miễn phí độc lập, chẳng hạn như Advanced Download Manager phân phối hai phiên bản miễn phí đi kèm quảng cáo, và một phiên bản độc lập với mức phí 59 “cành” cho thị trường Việt Nam. Hai là họ phân phối phiên bản miễn phí với đầy đủ chức năng, và một ứng dụng độc lập đóng vai trò mở khóa các tính năng cao cấp, mà đại diện phổ biến nhất là bộ đôi Nova Launcher và Nova Launcher Prime. Hai cách làm trên tuy đơn giản hơn trong quá trình phân phối, vì chỉ cần phát hành hai ứng dụng riêng biệt là được. Tuy nhiên, đi kèm với đó là việc cần phải xác thực xem có thực sự người dùng đã mua hàng hay không, hay họ chỉ đơn giản là tải và cài đặt tập tin APK từ nguồn cung cấp miễn phí để dùng “chùa”. Đi kèm với đó là bạn cần phải build riêng hai bản với những tính năng khác nhau nếu chọn phân phối theo cách thứ nhất, chẳng hạn với phiên bản miễn phí là một tùy chọn trỏ tới vị trí của phiên bản trả phí trên Google Play, còn trong phiên bản trả phí là hàng loạt những tính năng độc quyền.

Ngoài ra, chúng ta còn có cách phân phối theo hướng thứ ba, là chỉ phân phối một ứng dụng duy nhất với giá 0 USD, AUD, GBP hay VND, và cung cấp tùy chọn trả phí trực tiếp trong ứng dụng dưới dạng in-app billing. Cách này phổ biến nhất ở các games, mà tiên phong là Plants vs. Zombies 2, cho tải về chơi miễn phí, nhưng đâu “dễ ăn của ngoại” khi họ có cách “hút máu” dữ dội hơn với các vật phẩm trong game, tức in-app items, hoặc chính xác hơn là in-games inventories. Nhưng đối với ứng dụng, thì cách làm này cũng được áp dụng rất rộng rãi, đặc biệt là các ứng dụng cung cấp nội dung với hình thức thuê bao như Netflix. Và đây là hướng tiếp cận của bài viết này.

Để thực hiện cách thức thu phí này, thì chúng ta có hai cách: Một là sử dụng trực tiếp Google Play Store AIDL. Cách này thì chúng ta cần phải bỏ ra nhiều thao tác hơn, nhưng được cái cũng nhờ đó mà dễ dàng tùy chỉnh, mở rộng các thao tác hơn. Còn cách thứ hai có phần dễ học, dễ làm và dễ ăn hơn là dùng Google Play Billing Support Library. Thực chất, Billing Lib này là những helper classes được viết trong bộ AIDL kia và đóng gói thành thư viện. Nhưng vì đây là một thư viện chính chủ hẳn hoi nên Google đã catch sẵn một số Exceptions nên nhiệm vụ của bạn không quá phức tạp như dùng AIDL. Và bây giờ, chúng ta bắt đầu tiến hành. Lưu ý: Bạn phải phân phối phiên bản đầu tiên có hỗ trợ thanh toán lên Google Play trước thì mới có thể thử nghiệm được. Sau này, cho dù bạn không phát hành phiên bản thử nghiệm mới có versionCode cao hơn tất cả các phiên bản hiện tại trên Play Store thì vẫn có thể thử nghiệm mua hàng được.

1. Các bước chuẩn bị trên Google Play Console:

Trước hết, tài khoản Google Play Developer của bạn phải là tài khoản merchant, tức là tài khoản – nói ngắn gọn dễ hiểu – là tài khoản có thể bán hàng được trên Google Play. Để kiểm tra, bạn vào Google Play Console, vào mục Settings ở cạnh trái màn hình, chọn Developer account -> Account Details và cuộn xuống dưới. Nếu thấy kết quả như hình bên dưới thì bạn đã sẵn sàng để sang bước kế tiếp. Còn nếu tài khoản của bạn chưa là merchant account thì cứ làm theo hướng dẫn kích hoạt tại đó là được.

Bây giờ, cũng tại Google Play Console, bạn mở ứng dụng mà mình muốn tích hợp In-app billing, chọn Store presence rồi In-app products. Tại đây, bạn chọn Create Managed Products, màn hình sẽ hiện ra tương tự như dưới đây:


Ở đây bạn chú ý phần Product ID. Nó sẽ là SKU để sau này bạn sử dụng để query các thông tin về product. Nói cách khác, nó đại diện cho món hàng của bạn, tương tự như mã vạch của các mặt hàng trong siêu thị. Đương nhiên, nó phải không trùng với các in-app products khác của cùng ứng dụng. Với các ứng dụng khác nhau, thì bạn có thể thoải mái “tái sử dụng” lại chuỗi Product ID hoặc SKU này. Lưu ý là lỡ đặt rồi là không thể thay đổi được. Còn việc điền vào các phần khác như Title hay Description là việc quá đỗi dễ dàng với bạn nên tôi không cần và cũng không nên làm gì khác ngoài việc để đây. Cuối cùng, bạn định giá cho món hàng và chuyển status từ inactive sang active trước khi ấn SAVE là xong việc tại “siêu thị”.

2. Phần Android app

Chuyển sang phần code tại Android Studio, trước hết, bạn phải điều chỉnh Manifest lại với việc thêm quyền mới:

Còn với tập tin build.gradle module app, bạn cần yêu cầu impl thêm bộ thư viện play billing và cho sync:

Và bây giờ, chúng ta đã sẵn sàng để gọi code. Ở thời điểm hiện tại, chúng ta sẽ thực hiện các công việc tạo instance và gọi methods trong Activity. Việc gọi trong hàm trong các class khác sẽ được tôi nói ở cuối bài.

Đầu tiên, chúng ta sẽ tạo một instance của com.android.billingclient.api.BillingClient như sau:

Nếu onBillingSetupFinished được gọi thì chúng ta sẽ tiến hành query (các) sản phẩm trên Google Play Console vừa tạo. Code sẽ như sau:

3. Tiến hành mua hàng:

Để người dùng mua hàng, bạn đơn giản chỉ cần gọi method sau:

Trong đó, skuDetails là một trong những phần tử của skuDetailsList đã được trả về từ onSkuDetailsResponse bên trên. Lưu ý là billingClient.launchBillingFlow trả về giá trị int, nếu responseCode = 0 (tức OK) nghĩa là thanh toán thành công. Tuy nhiên, method trên cũng sẽ gọi tới callback PurchasesUpdatedListener mà ta đã gán cho billingClient ngay từ đầu. Vì vậy, bạn không cần thiết phải xét tới giá trị responseCode của billingClient.launchBillingFlow, mà có thể chỉ cần đặt hàm trong PurchasesUpdatedListener.onPurchasesUpdated, với cùng responseCode, là được. Người dùng sẽ thấy hộp thoại mua hàng khá quen thuộc như dưới đây.

Và nếu responseCode = 0, thì sẽ tiếp tục hiển thị:


4. Kiểm tra và xác thực đơn hàng trên server

Thực tế thì việc hack in-app billing trên Android không phải là hiếm. Do đó, bạn cần xác thực đơn hàng. Đối với các vật phẩm trong game, thì điều này gần như là bắt buộc để tránh tình trạng gian lận. Trong trường hợp này, tốt nhất, bạn nên xác thực đơn hàng bằng server của bạn rồi cộng vật phẩm trực tiếp vào tài khoản của người dùng lưu trữ trên server. Để làm được điều này, thì bạn có thể làm theo hướng dẫn chính chủ ở đây.

Để lấy được các giá trị như orderId và purchaseToken cũng như signature, bạn gọi từ class com.android.billingclient.api.Purchase. Vậy, instance của nó lấy ở đâu ra? Chúng nằm trong argument thứ hai của hàm PurchasesUpdatedListener.onPurchasesUpdated(int, List<Purchase>).

5. Kiểm tra xem người dùng đã mua hàng trước đây hay chưa

Tất nhiên, việc kiểm tra xem người dùng đã mua mặt hàng này trước hay chưa là thao tác không thể không làm với các ứng dụng, chẳng hạn, để mở khóa các tính năng mở rộng hoặc tắt quảng cáo. Ngoài ra, một mặt hàng chỉ có thể được mua một lần duy nhất cho một tài khoản, trừ trường hợp bạn cho phép một mặt hàng có thể mua đi mua lại nhiều lần, chẳng hạn như ngọc hay xu trong các game. Còn đối với game thì như tôi đã nói, bạn nên (và đã) xác thực đơn hàng rồi cộng các vật phẩm vào tài khoản của người dùng trên server rồi, nên có thể không cần thiết phải kiểm tra.

Để tiến hành kiểm tra, bạn gọi method này sau khi billingClient đã connect xong:

List<Purchase> purchases sẽ gồm tất cả các giao dịch mà người dùng đã thực hiện trong ứng dụng của bạn. Hiển nhiên, nếu purchases.size == 0 nghĩa là người dùng chưa mua bất kì món hàng nào. Nếu ứng dụng của bạn chỉ có một in-app product duy nhất và purchases.size == 1, nghĩa là người dùng đã trả tiền cho bạn rồi và bạn nên tắt tùy chọn cho phép người dùng mua tiếp, nếu product chỉ tính phí một lần.

6. BillingClient trong các class khác Activity

Ở mục số 3 thì tôi đã quy ước chúng ta sẽ gọi các hàm trong Activity. Tuy nhiên, tham số trong BillingClient.newBuilder thực chất là một Context, không phải trực tiếp là một Activity. Như vậy, câu hỏi là liệu chúng ta có thể thực hiện giao dịch trong Service hay thậm chí là Broadcast Receiver được không. Tuy nhiên, bạn hãy nhìn lại BillingClient.launchBillingFlow mà tôi đã giới thiệu bên trên: Tham số thứ nhất của nó phải là một Activity. Thực tế thì tất cả các hàm liên quan tới activity được gọi đều chỉ là hàm trong Context thuần mà thôi, tuy nhiên, để startActivity ProxyBillingActivity và đảm bảo Activity “dính liền” với Activity hiện tại, thì tham số truyền vào cần phải là Activity, ngoài ra bạn cũng cần phải xử lí một số tác vụ liên quan tới giao diện khi nhận kết quả trả về, chẳng hạn chí ít cũng cần hiển thị một Dialog thông báo giao dịch đã thành công hay đã bị hủy bỏ. Do đó, bao giờ bạn cũng phải gọi BillingClient.launchBillingFlow trong một Activity. Còn đối với việc query các purchase đã được thực hiện, tức billingClient.queryPurchases, bạn chỉ cần một biến Context, chẳng hạn Service hoặc Context trong BroadcastReceiver, cho BillingClient là đủ.

Và tới đây, phần lí thuyết đã xong. Tuy nhiên, ở đây chỉ trình bày về phần thư viện mà thôi. Còn việc bạn tạo món hàng như nào và sử dụng món hàng đó ra sao để hút khách sẽ tốn khá nhiều chất xám của bạn. Vì vậy, bạn nên nghiên cứu những cách thức chống hack để thu được lợi nhuận xứng đáng. Chúc các bạn code vui vẻ và thành công.

3 thoughts on “Hướng dẫn sử dụng Google Play Billing Support Library để tích hợp In-app billing trong ứng dụng Android”

  1. Chào anh, có thể cho em hỏi khi mua hàng thành công thì làm thế nào để xác thực đơn hàng đó trên server của mình được không ạ vì em có đọc tài liệu của Google về thư viện này thì trong đó có phần “Verify a purchase” giúp bảo vệ ứng khỏi kẻ xấu khi chúng cố gắng dịch ngược lại ứng dụng và disable cơ chế xác thực nhưng em vẫn chưa hiểu lắm cách triển khai như thế nàonếu được mong anh có thể giải đáp giúp em. Em xin cảm ơn!.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.