หัวข้อนี้จะอธิบายวิธีผสานรวม Google Play Billing Library เข้ากับแอปเพื่อเริ่มขายผลิตภัณฑ์
ตลอดอายุการซื้อ
ขั้นตอนการซื้อทั่วไปสำหรับการซื้อแบบครั้งเดียวหรือการสมัครใช้บริการมีดังนี้
- แสดงสิ่งที่ผู้ใช้ซื้อได้
- เปิดใช้งานขั้นตอนการซื้อเพื่อให้ผู้ใช้ยอมรับการซื้อ
- ยืนยันการซื้อในเซิร์ฟเวอร์
- มอบเนื้อหาให้ผู้ใช้
- ยอมรับการนำส่งเนื้อหา สำหรับผลิตภัณฑ์ที่ใช้แล้วหมดไป ให้ใช้การซื้อเพื่อให้ผู้ใช้ซื้อไอเทมนั้นอีกครั้งได้
การสมัครใช้บริการจะต่ออายุโดยอัตโนมัติจนกว่าจะยกเลิก การสมัครใช้บริการอาจมีสถานะต่อไปนี้
- ใช้งานอยู่: ผู้ใช้มีสถานะดีและมีสิทธิ์เข้าถึงการสมัครใช้บริการ
- ยกเลิกแล้ว: ผู้ใช้ยกเลิกแล้ว แต่ยังมีสิทธิ์เข้าถึงจนกว่าจะหมดอายุ
- อยู่ในระยะเวลาผ่อนผัน: ผู้ใช้พบปัญหาการชำระเงินแต่ยังคงมีสิทธิ์เข้าถึงขณะที่ Google พยายามใช้วิธีการชำระเงินนั้นอีกครั้ง
- ถูกระงับ: ผู้ใช้พบปัญหาเกี่ยวกับการชำระเงินและไม่มีสิทธิ์เข้าถึงอีกต่อไปขณะที่ Google พยายามเรียกเก็บเงินจากวิธีการชำระเงินนั้นอีกครั้ง
- หยุดชั่วคราว: ผู้ใช้หยุดการเข้าถึงไว้ชั่วคราวและจะไม่มีสิทธิ์เข้าถึงจนกว่าจะกลับมาเปิดใช้อีกครั้ง
- หมดอายุแล้ว: ผู้ใช้ยกเลิกและสูญเสียสิทธิ์เข้าถึงการสมัครใช้บริการ ระบบจะถือว่าผู้ใช้เลิกใช้งานเมื่อหมดอายุ
เริ่มต้นการเชื่อมต่อกับ Google Play
ขั้นตอนแรกในการผสานรวมกับระบบการเรียกเก็บเงินของ Google Play คือการเพิ่ม Google Play Billing Library ลงในแอปและเริ่มต้นการเชื่อมต่อ
เพิ่มข้อกำหนดของไลบรารี Google Play Billing
เพิ่มการพึ่งพา Google Play Billing Library ลงในbuild.gradle
ไฟล์
ของแอปดังที่แสดง
ดึงดูด
dependencies { def billing_version = "7.0.0" implementation "com.android.billingclient:billing:$billing_version" }
Kotlin
dependencies { val billing_version = "7.0.0" implementation("com.android.billingclient:billing:$billing_version") }
หากคุณใช้ Kotlin โมดูล KTX ของ Google Play Billing Library จะมีส่วนขยายของ Kotlin และการสนับสนุนโครูทีนที่ช่วยให้คุณเขียน Kotlin สำนวนได้เมื่อใช้ Google Play Billing Library หากต้องการรวมส่วนขยายเหล่านี้ไว้ในโปรเจ็กต์ ให้เพิ่มการพึ่งพาต่อไปนี้ลงในไฟล์ build.gradle
ของแอปดังที่แสดง
ดึงดูด
dependencies { def billing_version = "7.0.0" implementation "com.android.billingclient:billing-ktx:$billing_version" }
Kotlin
dependencies { val billing_version = "7.0.0" implementation("com.android.billingclient:billing-ktx:$billing_version") }
เริ่มต้น BillingClient
เมื่อเพิ่มทรัพยากร Dependency ใน Google Play Billing Library แล้ว คุณจะต้องเริ่มต้นอินสแตนซ์ BillingClient
BillingClient
เป็นอินเทอร์เฟซหลักสำหรับการติดต่อสื่อสารระหว่าง Google Play Billing Library กับส่วนที่เหลือของแอป BillingClient
มีวิธีการที่สะดวกทั้งแบบซิงค์และแบบไม่ซิงค์สําหรับการดำเนินการเรียกเก็บเงินทั่วไปหลายรายการ เราขอแนะนําอย่างยิ่งให้คุณเปิดการเชื่อมต่อ BillingClient
ที่ใช้งานอยู่เพียงครั้งละ 1 รายการเพื่อหลีกเลี่ยงการเรียกกลับ PurchasesUpdatedListener
หลายรายการสําหรับเหตุการณ์เดียว
หากต้องการสร้าง BillingClient
ให้ใช้ newBuilder()
คุณสามารถส่งบริบทใดก็ได้ให้กับ newBuilder()
และ BillingClient
จะใช้บริบทนั้นเพื่อรับบริบทแอปพลิเคชัน
คุณจึงไม่ต้องกังวลเรื่องการรั่วไหลของหน่วยความจํา หากต้องการรับข้อมูลอัปเดตเกี่ยวกับการซื้อ คุณต้องเรียกใช้ setListener()
ด้วย โดยส่งการอ้างอิงไปยัง PurchasesUpdatedListener
โปรแกรมฟังนี้จะได้รับการอัปเดตการซื้อทั้งหมดในแอป
Kotlin
private val purchasesUpdatedListener = PurchasesUpdatedListener { billingResult, purchases -> // To be implemented in a later section. } private var billingClient = BillingClient.newBuilder(context) .setListener(purchasesUpdatedListener) // Configure other settings. .build()
Java
private PurchasesUpdatedListener purchasesUpdatedListener = new PurchasesUpdatedListener() { @Override public void onPurchasesUpdated(BillingResult billingResult, List<Purchase> purchases) { // To be implemented in a later section. } }; private BillingClient billingClient = BillingClient.newBuilder(context) .setListener(purchasesUpdatedListener) // Configure other settings. .build();
เชื่อมต่อกับ Google Play
หลังจากสร้าง BillingClient
แล้ว คุณต้องสร้างการเชื่อมต่อกับ Google Play
หากต้องการเชื่อมต่อกับ Google Play ให้โทรไปที่ startConnection()
กระบวนการเชื่อมต่อเป็นแบบไม่พร้อมกัน และคุณต้องติดตั้งใช้งาน BillingClientStateListener
เพื่อรับการเรียกกลับเมื่อการตั้งค่าไคลเอ็นต์เสร็จสมบูรณ์และพร้อมที่จะส่งคำขอเพิ่มเติม
นอกจากนี้คุณยังต้องใช้ตรรกะการลองอีกครั้งเพื่อจัดการกับการสูญเสียการเชื่อมต่อกับ Google Play
หากต้องการใช้ตรรกะการลองอีกครั้ง ให้ลบล้างเมธอดการเรียกกลับ onBillingServiceDisconnected()
และตรวจสอบว่า BillingClient
เรียกใช้เมธอด startConnection()
เพื่อเชื่อมต่อกับ Google Play อีกครั้งก่อนที่จะส่งคำขอเพิ่มเติม
ตัวอย่างต่อไปนี้แสดงวิธีเริ่มการเชื่อมต่อและทดสอบว่าพร้อมใช้งานแล้ว
Kotlin
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. } })
Java
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. } });
แสดงผลิตภัณฑ์ที่พร้อมจำหน่าย
หลังจากเชื่อมต่อกับ Google Play แล้ว คุณก็พร้อมที่จะค้นหาผลิตภัณฑ์ที่พร้อมจำหน่ายและแสดงต่อผู้ใช้
การค้นหารายละเอียดผลิตภัณฑ์เป็นขั้นตอนสำคัญก่อนที่จะแสดงผลิตภัณฑ์ต่อผู้ใช้ เนื่องจากผลการค้นหาจะแสดงข้อมูลผลิตภัณฑ์ที่แปลแล้ว สำหรับแพ็กเกจการสมัครใช้บริการ โปรดตรวจสอบว่าการแสดงผลิตภัณฑ์เป็นไปตามนโยบายทั้งหมดของ Play
หากต้องการค้นหารายละเอียดผลิตภัณฑ์ในแอป ให้โทรไปที่ queryProductDetailsAsync()
หากต้องการจัดการผลลัพธ์ของการดำเนินการแบบไม่พร้อมกัน คุณต้องระบุโปรแกรมรับฟังที่ใช้อินเทอร์เฟซ ProductDetailsResponseListener
ด้วย
จากนั้นคุณสามารถลบล้าง onProductDetailsResponse()
ซึ่งจะแจ้งเตือน Listener เมื่อการค้นหาเสร็จสิ้น ดังที่แสดงในตัวอย่างต่อไปนี้
Kotlin
val queryProductDetailsParams = QueryProductDetailsParams.newBuilder() .setProductList( ImmutableList.of( Product.newBuilder() .setProductId("product_id_example") .setProductType(ProductType.SUBS) .build())) .build() billingClient.queryProductDetailsAsync(queryProductDetailsParams) { billingResult, productDetailsList -> // check billingResult // process returned productDetailsList }
Java
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<ProductDetails> productDetailsList) { // check billingResult // process returned productDetailsList } } )
เมื่อค้นหารายละเอียดผลิตภัณฑ์ ให้ส่งอินสแตนซ์ของ QueryProductDetailsParams
ที่ระบุรายการสตริงรหัสผลิตภัณฑ์ซึ่งสร้างขึ้นใน Google Play Console พร้อมกับ ProductType
ProductType
อาจเป็น ProductType.INAPP
สำหรับผลิตภัณฑ์แบบเรียกเก็บเงินครั้งเดียว หรือ ProductType.SUBS
สำหรับการสมัครใช้บริการก็ได้
การค้นหาด้วยส่วนขยาย Kotlin
หากใช้ส่วนขยาย Kotlin คุณจะค้นหารายละเอียดไอเทมที่ซื้อในแอปได้โดยเรียกใช้ฟังก์ชันส่วนขยาย queryProductDetails()
queryProductDetails()
ใช้ประโยชน์จากโคโริวทีนของ Kotlin คุณจึงไม่ต้องกำหนด Listener แยกต่างหาก แต่ฟังก์ชันจะระงับไว้จนกว่าการค้นหาจะเสร็จสมบูรณ์ จากนั้นคุณจะประมวลผลผลลัพธ์ได้หลังจากนั้น
suspend fun processPurchases() {
val productList = listOf(
QueryProductDetailsParams.Product.newBuilder()
.setProductId("product_id_example")
.setProductType(BillingClient.ProductType.SUBS)
.build()
)
val params = QueryProductDetailsParams.newBuilder()
params.setProductList(productList)
// leverage queryProductDetails Kotlin extension function
val productDetailsResult = withContext(Dispatchers.IO) {
billingClient.queryProductDetails(params.build())
}
// Process the result.
}
ในบางกรณี อุปกรณ์บางรุ่นอาจไม่รองรับ ProductDetails
และ queryProductDetailsAsync()
ซึ่งมักเกิดจากบริการ Google Play เวอร์ชันเก่า โปรดดูวิธีใช้ฟีเจอร์ที่เข้ากันได้แบบย้อนหลังในคำแนะนำในการย้ายข้อมูล Play Billing Library 5 เพื่อให้มั่นใจว่าจะได้รับการสนับสนุนที่เหมาะสมสำหรับสถานการณ์นี้
ประมวลผลผลลัพธ์
Google Play Billing Library จะจัดเก็บผลการค้นหาไว้ในออบเจ็กต์ List
จาก ProductDetails
รายการ จากนั้นคุณสามารถเรียกใช้เมธอดต่างๆ ในออบเจ็กต์ ProductDetails
แต่ละรายการในรายการเพื่อดูข้อมูลที่เกี่ยวข้องกับไอเทมที่ซื้อในแอป เช่น ราคาหรือคำอธิบาย หากต้องการดูข้อมูลรายละเอียดผลิตภัณฑ์ที่มีอยู่ โปรดดูรายการเมธอดในคลาส ProductDetails
ก่อนที่จะเสนอขายสินค้า โปรดตรวจสอบว่าผู้ใช้ไม่ได้เป็นเจ้าของสินค้าดังกล่าวอยู่ หากผู้ใช้มีอุปกรณ์สิ้นเปลืองที่ยังอยู่ในคลังไอเทม ผู้ใช้ก็ต้องบริโภคไอเทมนั้นก่อนจึงจะซื้อได้อีกครั้ง
ก่อนที่จะเสนอการสมัครใช้บริการ ให้ตรวจสอบว่าผู้ใช้ไม่ได้สมัครใช้บริการแล้ว และโปรดทราบว่า
queryProductDetailsAsync()
จะแสดงรายละเอียดผลิตภัณฑ์ที่ต้องสมัครใช้บริการและข้อเสนอสูงสุด 50 รายการต่อการสมัครใช้บริการ 1 รายการqueryProductDetailsAsync()
จะแสดงเฉพาะข้อเสนอที่ผู้ใช้มีสิทธิ์ หากผู้ใช้พยายามซื้อข้อเสนอที่ไม่มีสิทธิ์ (เช่น แอปแสดงรายการข้อเสนอที่มีสิทธิ์ที่ล้าสมัย) Play จะแจ้งให้ผู้ใช้ทราบว่าไม่มีสิทธิ์ และผู้ใช้สามารถเลือกซื้อแพ็กเกจพื้นฐานแทนได้
เริ่มขั้นตอนการซื้อ
หากต้องการเริ่มคำขอซื้อจากแอป ให้เรียกใช้เมธอด launchBillingFlow()
จากเธรดหลักของแอป เมธอดนี้ใช้การอ้างอิงไปยังออบเจ็กต์ BillingFlowParams
ที่มีออบเจ็กต์ ProductDetails
ที่เกี่ยวข้องซึ่งได้จากการเรียกใช้ queryProductDetailsAsync()
หากต้องการสร้างออบเจ็กต์ BillingFlowParams
ให้ใช้คลาส BillingFlowParams.Builder
Kotlin
// An activity reference from which the billing flow will be launched. val activity : Activity = ...; val productDetailsParamsList = listOf( BillingFlowParams.ProductDetailsParams.newBuilder() // retrieve a value for "productDetails" by calling queryProductDetailsAsync() .setProductDetails(productDetails) // For One-time product, "setOfferToken" method shouldn't be called. // For subscriptions, to get an offer token, call ProductDetails.subscriptionOfferDetails() // for a list of offers that are available to the user .setOfferToken(selectedOfferToken) .build() ) val billingFlowParams = BillingFlowParams.newBuilder() .setProductDetailsParamsList(productDetailsParamsList) .build() // Launch the billing flow val billingResult = billingClient.launchBillingFlow(activity, billingFlowParams)
Java
// An activity reference from which the billing flow will be launched. Activity activity = ...; ImmutableList<ProductDetailsParams> productDetailsParamsList = ImmutableList.of( ProductDetailsParams.newBuilder() // retrieve a value for "productDetails" by calling queryProductDetailsAsync() .setProductDetails(productDetails) // For one-time products, "setOfferToken" method shouldn't be called. // For subscriptions, to get an offer token, call // ProductDetails.subscriptionOfferDetails() for a list of offers // that are available to the user. .setOfferToken(selectedOfferToken) .build() ); BillingFlowParams billingFlowParams = BillingFlowParams.newBuilder() .setProductDetailsParamsList(productDetailsParamsList) .build(); // Launch the billing flow BillingResult billingResult = billingClient.launchBillingFlow(activity, billingFlowParams);
เมธอด launchBillingFlow()
จะแสดงโค้ดตอบกลับรายการใดรายการหนึ่งที่ระบุไว้ใน BillingClient.BillingResponseCode
อย่าลืมตรวจสอบผลลัพธ์นี้ว่าไม่มีข้อผิดพลาดในการเปิดขั้นตอนการซื้อ BillingResponseCode
จาก OK
บ่งชี้ว่าการเปิดตัวสําเร็จ
เมื่อโทรหา launchBillingFlow()
สำเร็จ ระบบจะแสดงหน้าจอซื้อของ Google Play รูปที่ 1 แสดงหน้าจอการซื้อสำหรับการสมัครใช้บริการ
Google Play จะเรียก onPurchasesUpdated()
เพื่อส่งผลลัพธ์ของการดำเนินการซื้อให้กับ Listener ที่ใช้อินเทอร์เฟซ PurchasesUpdatedListener
ระบุตัวรับฟังโดยใช้เมธอด setListener()
เมื่อคุณเริ่มต้นไคลเอ็นต์
คุณต้องติดตั้งใช้งาน onPurchasesUpdated()
เพื่อจัดการกับโค้ดตอบกลับที่เป็นไปได้ ตัวอย่างต่อไปนี้แสดงวิธีลบล้าง onPurchasesUpdated()
Kotlin
override fun onPurchasesUpdated(billingResult: BillingResult, purchases: List<Purchase>?) { 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. } }
Java
@Override void onPurchasesUpdated(BillingResult billingResult, List<Purchase> 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. } }
การซื้อที่สำเร็จจะสร้างหน้าจอแสดงขั้นตอนสำเร็จในการซื้อใน Google Play ซึ่งคล้ายกับรูปที่ 2
การซื้อที่สำเร็จจะสร้างโทเค็นการซื้อด้วย ซึ่งเป็นตัวระบุที่ไม่ซ้ำกันซึ่งแสดงถึงผู้ใช้และรหัสผลิตภัณฑ์ของไอเทมที่ซื้อในแอป แอปของคุณจัดเก็บโทเค็นการซื้อไว้ในเครื่องได้ แต่เราขอแนะนำให้ส่งโทเค็นไปยังเซิร์ฟเวอร์แบ็กเอนด์ที่ปลอดภัย จากนั้นคุณจะยืนยันการซื้อและป้องกันการประพฤติมิชอบได้ กระบวนการนี้จะอธิบายเพิ่มเติมในส่วนต่อไปนี้
นอกจากนี้ ผู้ใช้จะได้รับอีเมลใบเสร็จของธุรกรรมที่มีรหัสคำสั่งซื้อหรือรหัสที่ไม่ซ้ำกันของธุรกรรมด้วย ผู้ใช้จะได้รับอีเมลที่มีรหัสคำสั่งซื้อที่ไม่ซ้ำกันสำหรับการซื้อผลิตภัณฑ์แบบครั้งเดียวแต่ละครั้ง รวมถึงการซื้อการสมัครใช้บริการครั้งแรกและการต่ออายุใหม่อัตโนมัติตามรอบในภายหลัง คุณใช้รหัสคำสั่งซื้อเพื่อจัดการการคืนเงินใน Google Play Console ได้
ระบุราคาสำหรับคุณโดยเฉพาะ
หากแอปของคุณเผยแพร่แก่ผู้ใช้ในสหภาพยุโรปได้ ให้ใช้วิธี setIsOfferPersonalized()
เพื่อเปิดเผยให้ผู้ใช้ทราบว่าราคาของสินค้าได้รับการปรับเปลี่ยนในแบบของคุณโดยใช้การตัดสินใจอัตโนมัติ
คุณต้องปรึกษา Art 6 (1) (ea) CRD ของคำสั่งว่าด้วยสิทธิของผู้บริโภค 2011/83/EU เพื่อตรวจสอบว่าราคาที่คุณเสนอให้นั้นมีการปรับเปลี่ยนตามโปรไฟล์ของผู้ใช้หรือไม่
setIsOfferPersonalized()
รับอินพุตบูลีน เมื่อ true
UI
ของ Play จะมีการเปิดเผย เมื่อเป็น false
ระบบ UI จะละเว้นการเปิดเผย ค่าเริ่มต้นคือ false
ดูข้อมูลเพิ่มเติมได้ที่ศูนย์ช่วยเหลือผู้บริโภค
กำลังดำเนินการซื้อ
เมื่อผู้ใช้ทำการซื้อเสร็จสมบูรณ์แล้ว แอปของคุณจะต้องประมวลผลการซื้อดังกล่าว
ในกรณีส่วนใหญ่ แอปจะได้รับการแจ้งเตือนการซื้อผ่านPurchasesUpdatedListener
อย่างไรก็ตาม อาจมีบางกรณีที่แอปจะรับรู้การซื้อโดยการเรียกใช้ BillingClient.queryPurchasesAsync()
ตามที่อธิบายไว้ในการเรียกข้อมูลการซื้อ
นอกจากนี้ หากคุณมีไคลเอ็นต์การแจ้งเตือนแบบเรียลไทม์สำหรับนักพัฒนาแอปในแบ็กเอนด์ที่ปลอดภัย คุณจะลงทะเบียนการซื้อใหม่ได้โดยรับ subscriptionNotification
หรือ oneTimeProductNotification
ที่แจ้งเตือนการซื้อใหม่ หลังจากได้รับการแจ้งเตือนเหล่านี้แล้ว ให้เรียกใช้ Google Play Developer API เพื่อดูสถานะทั้งหมดและอัปเดตสถานะแบ็กเอนด์ของคุณเอง
แอปของคุณควรประมวลผลการซื้อด้วยวิธีต่อไปนี้
- ยืนยันการซื้อ
- ส่งเนื้อหาให้ผู้ใช้และรับทราบการนำส่งเนื้อหา (ไม่บังคับ) ทำเครื่องหมายรายการว่าใช้แล้วเพื่อให้ผู้ใช้ซื้อรายการนั้นอีกครั้งได้
หากต้องการยืนยันการซื้อ ก่อนอื่นให้ตรวจสอบว่าสถานะการซื้อคือ PURCHASED
หากการซื้อเป็น PENDING
คุณควรดำเนินการซื้อตามที่อธิบายไว้ในการจัดการธุรกรรมที่รอดำเนินการ สำหรับการซื้อที่ได้รับจาก onPurchasesUpdated()
หรือ queryPurchasesAsync()
คุณควรยืนยันการซื้อเพิ่มเติมเพื่อให้แน่ใจว่าถูกต้องตามกฎหมายก่อนที่แอปจะให้สิทธิ์ ดูวิธียืนยันการซื้ออย่างถูกต้องได้ที่ยืนยันการซื้อก่อนให้สิทธิ์
เมื่อยืนยันการซื้อแล้ว แอปของคุณก็พร้อมที่จะให้สิทธิ์แก่ผู้ใช้ บัญชีผู้ใช้ที่เชื่อมโยงกับการซื้อจะระบุได้ด้วย ProductPurchase.obfuscatedExternalAccountId
ที่ Purchases.products:get
แสดงผลสําหรับการซื้อไอเทมที่ซื้อในแอป และ SubscriptionPurchase.obfuscatedExternalAccountId
ที่ Purchases.subscriptions:get
แสดงผลสําหรับการสมัครใช้บริการฝั่งเซิร์ฟเวอร์ หรือ obfuscatedAccountId
จาก Purchase.getAccountIdentifiers()
ฝั่งไคลเอ็นต์ หากมีการตั้งค่าไว้ด้วย setObfuscatedAccountId
เมื่อทำการซื้อ
หลังให้สิทธิ์แล้ว แอปของคุณต้องรับทราบการซื้อดังกล่าว การรับทราบนี้จะเป็นการสื่อสารไปยัง Google Play ว่าคุณได้ให้สิทธิ์การซื้อดังกล่าวแล้ว
กระบวนการให้สิทธิ์และรับทราบการซื้อจะขึ้นอยู่กับว่าการซื้อเป็นสินค้าที่บริโภคได้ สินค้าที่บริโภคไม่ได้ หรือการสมัครใช้บริการ
ผลิตภัณฑ์ที่ใช้แล้วหมด
สำหรับไอเทมที่บริโภคได้ หากแอปมีแบ็กเอนด์ที่ปลอดภัย เราขอแนะนำให้ใช้ Purchases.products:consume
เพื่อใช้ไอเทมที่ซื้ออย่างน่าเชื่อถือ ตรวจสอบว่ายังไม่มีการใช้งานการซื้อโดยตรวจสอบ consumptionState
จากผลลัพธ์ของการโทร Purchases.products:get
หากแอปของคุณเป็นไคลเอ็นต์เท่านั้นโดยไม่มีแบ็กเอนด์ ให้ใช้ consumeAsync()
จาก Google Play Billing Library ทั้ง 2 วิธีจะปฏิบัติตามข้อกำหนดในการรับทราบ และระบุว่าแอปได้ให้สิทธิแก่ผู้ใช้
นอกจากนี้ วิธีการเหล่านี้ยังช่วยให้แอปของคุณทำให้ผลิตภัณฑ์แบบครั้งเดียวที่สอดคล้องกับโทเค็นการซื้อที่ป้อนพร้อมสำหรับการซื้ออีกครั้งได้ เมื่อใช้ consumeAsync()
คุณยังต้องส่งออบเจ็กต์ที่ใช้อินเทอร์เฟซ ConsumeResponseListener
ด้วย ออบเจ็กต์นี้จะจัดการผลลัพธ์ของการดำเนินการบริโภค คุณสามารถลบล้างเมธอด onConsumeResponse()
ซึ่ง Google Play Billing Library จะเรียกใช้เมื่อการดำเนินการเสร็จสมบูรณ์
ตัวอย่างต่อไปนี้แสดงการใช้ผลิตภัณฑ์ด้วย Google Play Billing Library โดยใช้โทเค็นการซื้อที่เกี่ยวข้อง
Kotlin
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) } }
Java
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); }
ผลิตภัณฑ์ที่ใช้แล้วหมดไป
หากแอปมีแบ็กเอนด์ที่ปลอดภัย เราขอแนะนำให้ใช้ Purchases.products:acknowledge
เพื่อตอบรับการซื้ออย่างน่าเชื่อถือ หากต้องการตอบรับการซื้อที่บริโภคไม่ได้ ตรวจสอบว่ายังไม่มีการยอมรับการซื้อก่อนหน้านี้โดยดูที่ acknowledgementState
จากผลลัพธ์ของการเรียกใช้ Purchases.products:get
หากแอปของคุณเป็นไคลเอ็นต์เท่านั้น ให้ใช้ BillingClient.acknowledgePurchase()
จาก Google Play Billing Library ในแอปของคุณ ก่อนยอมรับการซื้อ แอปควรตรวจสอบว่ามีการยอมรับการซื้อแล้วหรือไม่โดยใช้เมธอด isAcknowledged()
ใน Google Play Billing Library
ตัวอย่างต่อไปนี้แสดงวิธีรับทราบการซื้อโดยใช้ Google Play Billing Library
Kotlin
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()) } } } }
Java
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); } } }
การสมัครใช้บริการ
ระบบจะจัดการการสมัครใช้บริการในลักษณะเดียวกับสินค้าที่บริโภคไม่ได้ หากเป็นไปได้ ให้ใช้ Purchases.subscriptions.acknowledge
จาก Google Play Developer API เพื่อตอบรับการซื้อจากแบ็กเอนด์ที่ปลอดภัย ตรวจสอบว่าไม่มีการตอบรับการซื้อก่อนหน้านี้โดยตรวจสอบ acknowledgementState
ในแหล่งข้อมูลการซื้อจาก Purchases.subscriptions:get
หรือจะรับการสมัครใช้บริการโดยใช้ BillingClient.acknowledgePurchase()
จากคลัง Google Play Billing หลังจากที่ตรวจสอบ isAcknowledged()
ก็ได้ คุณต้องรับทราบการซื้อการสมัครใช้บริการเริ่มต้นทั้งหมด การต่ออายุการสมัครใช้บริการไม่จำเป็นต้องได้รับการรับทราบ ดูข้อมูลเพิ่มเติมเกี่ยวกับช่วงเวลาที่ต้องรับทราบการสมัครใช้บริการในหัวข้อขายการสมัครใช้บริการ
กำลังดึงข้อมูลการซื้อ
การฟังการอัปเดตการซื้อโดยใช้ PurchasesUpdatedListener
นั้นไม่เพียงพอที่จะยืนยันว่าแอปของคุณประมวลผลการซื้อทั้งหมดแล้ว มีความเป็นไปได้ว่าแอปของคุณ
อาจไม่รู้จักการซื้อทั้งหมดที่ผู้ใช้ทำ ต่อไปนี้คือสถานการณ์ที่แอปอาจไม่ติดตามหรือไม่รู้เกี่ยวกับการซื้อ
- ปัญหาเกี่ยวกับเครือข่ายระหว่างการซื้อ: ผู้ใช้ทำการซื้อสำเร็จและได้รับการยืนยันจาก Google แต่อุปกรณ์ของผู้ใช้ขาดการเชื่อมต่อเครือข่ายก่อนที่อุปกรณ์จะได้รับการแจ้งเตือนการซื้อผ่าน
PurchasesUpdatedListener
- อุปกรณ์หลายเครื่อง: ผู้ใช้ซื้อสินค้าในอุปกรณ์เครื่องหนึ่ง แล้วคาดหวังว่าจะเห็นสินค้านั้นเมื่อเปลี่ยนอุปกรณ์
- การจัดการการซื้อนอกแอป: การซื้อบางอย่าง เช่น การแลกรับโปรโมชัน สามารถทำได้นอกแอป
หากต้องการจัดการสถานการณ์เหล่านี้ โปรดตรวจสอบว่าแอปของคุณเรียกใช้ BillingClient.queryPurchasesAsync()
ในเมธอด onResume()
เพื่อให้แน่ใจว่าระบบประมวลผลการซื้อทั้งหมดเรียบร้อยแล้วตามที่อธิบายไว้ในการประมวลผลการซื้อ
ตัวอย่างต่อไปนี้แสดงวิธีดึงข้อมูลการซื้อการสมัครใช้บริการของผู้ใช้
โปรดทราบว่า queryPurchasesAsync()
จะแสดงเฉพาะการสมัครใช้บริการที่ใช้งานอยู่และการซื้อแบบครั้งเดียวที่ไม่ใช้งานเท่านั้น
Kotlin
val params = QueryPurchasesParams.newBuilder() .setProductType(ProductType.SUBS) // uses queryPurchasesAsync Kotlin extension function val purchasesResult = billingClient.queryPurchasesAsync(params.build()) // check purchasesResult.billingResult // process returned purchasesResult.purchasesList, e.g. display the plans user owns
Java
billingClient.queryPurchasesAsync( QueryPurchasesParams.newBuilder() .setProductType(ProductType.SUBS) .build(), new PurchasesResponseListener() { public void onQueryPurchasesResponse(BillingResult billingResult, List<Purchase> purchases) { // check billingResult // process returned purchase list, e.g. display the plans user owns } } );
จัดการการซื้อนอกแอป
การซื้อบางอย่างอาจเกิดขึ้นนอกแอป เช่น การแลกรับโปรโมชันหรือการช่วยเตือนเกี่ยวกับการหยุดกลางคันในรถเข็นสำหรับการซื้อในแอปของ Google Play Games (IAP) เมื่อผู้ใช้ทำการซื้อนอกแอป ผู้ใช้จะคาดหวังว่าแอปจะแสดงข้อความในแอป หรือใช้กลไกการแจ้งเตือนบางอย่างเพื่อแจ้งให้ผู้ใช้ทราบว่าแอปได้รับและประมวลผลการซื้ออย่างถูกต้อง กลไกที่ยอมรับได้บางส่วน ได้แก่
- แสดงป๊อปอัปในแอป
- ส่งข้อความไปยังกล่องข้อความในแอป และระบุอย่างชัดเจนว่ามีข้อความใหม่ในกล่องข้อความในแอป
- ใช้ข้อความการแจ้งเตือนของระบบปฏิบัติการ
โปรดทราบว่าแอปของคุณอาจอยู่ในสถานะใดก็ได้เมื่อแอปจดจำการซื้อ แม้แต่แอปของคุณอาจยังไม่ได้ติดตั้งเมื่อทำการซื้อ ผู้ใช้คาดหวังว่าจะได้รับสิ่งที่ซื้อไปเมื่อกลับมาใช้งานแอปอีกครั้ง ไม่ว่าแอปจะอยู่ในสถานะใดก็ตาม
คุณต้องตรวจหาการซื้อโดยไม่คํานึงถึงสถานะของแอปเมื่อการซื้อเกิดขึ้น อย่างไรก็ตาม มีข้อยกเว้นบางประการที่อาจยอมรับได้หากไม่แจ้งผู้ใช้โดยทันทีว่าได้รับไอเทมแล้ว เช่น
- ในระหว่างส่วนที่แอ็กชันของเกม ซึ่งการแสดงข้อความอาจทำให้ผู้ใช้เสียสมาธิ ในกรณีนี้ คุณต้องแจ้งให้ผู้ใช้ทราบหลังจากการดำเนินการสิ้นสุดลง
- ในระหว่างฉากตัด ซึ่งการแสดงข้อความอาจทำให้ผู้ใช้เสียสมาธิ ในกรณีนี้ คุณต้องแจ้งให้ผู้ใช้ทราบหลังจากฉากตัดจบ
- ในระหว่างบทแนะนำเบื้องต้นและการตั้งค่าผู้ใช้ของเกม เราขอแนะนำให้แจ้งให้ผู้ใช้ใหม่ทราบเกี่ยวกับรางวัลทันทีหลังจากที่ผู้ใช้เปิดเกมหรือในระหว่างการตั้งค่าผู้ใช้ครั้งแรก อย่างไรก็ตาม คุณรอจนกว่าลำดับเกมหลักจะพร้อมใช้งานเพื่อแจ้งให้ผู้ใช้ทราบ
โปรดคํานึงถึงผู้ใช้เสมอเมื่อตัดสินใจว่าจะแจ้งเตือนผู้ใช้เกี่ยวกับการซื้อที่ดำเนินการนอกแอปของคุณเมื่อใดและอย่างไร เมื่อใดก็ตามที่ผู้ใช้ไม่ได้รับการแจ้งเตือนทันที ผู้ใช้อาจสับสน และอาจหยุดใช้แอป ติดต่อทีมสนับสนุนผู้ใช้ หรือร้องเรียนเกี่ยวกับเรื่องนี้บนโซเชียลมีเดีย
การช่วยเตือนการละทิ้งรถเข็นกลางคันในหน้าแรกของ Google Play Games (เปิดใช้โดยค่าเริ่มต้น)
สําหรับนักพัฒนาแอปเกมที่สร้างรายได้ผ่าน IAP วิธีหนึ่งในการขายหน่วยสินค้าคงคลัง (SKU) ที่ใช้งานอยู่ใน Google Play Console นอกแอปของคุณคือฟีเจอร์การช่วยเตือนการละทิ้งรถเข็นกลางคัน ซึ่งจะกระตุ้นให้ผู้ใช้ดำเนินการซื้อที่หยุดกลางคันก่อนหน้านี้ให้เสร็จสมบูรณ์ขณะเลือกดูใน Google Play Store การซื้อเหล่านี้เกิดขึ้นนอกแอปของคุณ จากหน้าแรกของ Google Play Games ใน Google Play Store
ฟีเจอร์นี้จะเปิดใช้โดยค่าเริ่มต้นเพื่อช่วยให้ผู้ใช้ได้กลับมาดูรายการที่เลือกไว้ก่อนหน้านี้ และเพื่อช่วยนักพัฒนาแอปเพิ่มยอดขายให้ได้สูงสุด อย่างไรก็ตาม คุณเลือกไม่ให้แอปใช้ฟีเจอร์นี้ได้โดยการส่งแบบฟอร์มเลือกไม่ใช้ฟีเจอร์การช่วยเตือนการละทิ้งรถเข็นกลางคัน ดูแนวทางปฏิบัติแนะนำในการจัดการ SKU ภายใน Google Play Console ได้ที่ สร้างไอเทมที่ซื้อในแอป
รูปภาพต่อไปนี้แสดงการช่วยเตือนการหยุดกลางคันในรถเข็นที่ปรากฏใน Google Play Store
การจัดการธุรกรรมที่รอดำเนินการ
Google Play รองรับธุรกรรมที่รอดำเนินการหรือธุรกรรมที่ต้องดำเนินการเพิ่มเติมอย่างน้อย 1 ขั้นตอนระหว่างที่ผู้ใช้เริ่มซื้อและเมื่อระบบประมวลผลวิธีการชำระเงินสำหรับการซื้อ แอปของคุณไม่ควรให้สิทธิ์ในการซื้อประเภทเหล่านี้จนกว่า Google จะแจ้งให้คุณทราบว่าเรียกเก็บเงินจากวิธีการชำระเงินของผู้ใช้เรียบร้อยแล้ว
ตัวอย่างเช่น ผู้ใช้สามารถเริ่มธุรกรรมโดยเลือกกิจการที่มีหน้าร้านจริง ซึ่งจะชำระเงินภายหลังด้วยเงินสดได้ ผู้ใช้จะได้รับรหัสทั้งทางอีเมลและการแจ้งเตือน เมื่อผู้ใช้มาถึงร้านค้า ผู้ใช้จะแลกรหัสกับแคชเชียร์และชำระเงินด้วยเงินสดได้ จากนั้น Google จะแจ้งให้คุณและผู้ใช้ทราบว่าได้รับการชำระเงินแล้ว จากนั้นแอปของคุณจะให้สิทธิ์แก่ผู้ใช้ได้
เรียกใช้ enablePendingPurchases()
ในขั้นตอนเริ่มต้น BillingClient
เพื่อเปิดใช้ธุรกรรมที่รอดำเนินการสำหรับแอป แอปของคุณต้องเปิดใช้และรองรับธุรกรรมที่รอดำเนินการสำหรับผลิตภัณฑ์แบบเรียกเก็บเงินครั้งเดียว ก่อนเพิ่มการสนับสนุน โปรดทำความเข้าใจวงจรการซื้อสำหรับธุรกรรมที่รอดำเนินการ
เมื่อแอปได้รับการซื้อใหม่ผ่าน PurchasesUpdatedListener
หรือจากการเรียกใช้ queryPurchasesAsync()
ให้ใช้เมธอด getPurchaseState()
เพื่อระบุว่าสถานะการซื้อคือ PURCHASED
หรือ PENDING
คุณควรให้สิทธิ์เฉพาะเมื่อสถานะเป็น PURCHASED
หากแอปทำงานอยู่เมื่อผู้ใช้ทำการซื้อเสร็จสมบูรณ์ ระบบจะเรียกใช้ PurchasesUpdatedListener
อีกครั้ง และ PurchaseState
เปลี่ยนเป็น PURCHASED
แล้ว ณ จุดนี้ แอปประมวลผลการซื้อได้โดยใช้วิธีการมาตรฐานสำหรับการประมวลผลการซื้อ แอปของคุณควรเรียกใช้ queryPurchasesAsync()
ในเมธอด onResume()
ของแอปเพื่อจัดการการซื้อที่เปลี่ยนเป็นสถานะ PURCHASED
ขณะที่แอปไม่ได้ทำงานอยู่
เมื่อการซื้อเปลี่ยนจาก PENDING
เป็น
PURCHASED
ลูกค้าการแจ้งเตือนแบบเรียลไทม์สำหรับนักพัฒนาแอปจะได้รับการแจ้งเตือน ONE_TIME_PRODUCT_PURCHASED
หรือ SUBSCRIPTION_PURCHASED
หากการซื้อถูกยกเลิก คุณจะได้รับการแจ้งเตือน ONE_TIME_PRODUCT_CANCELED
หรือ SUBSCRIPTION_PENDING_PURCHASE_CANCELED
กรณีนี้อาจเกิดขึ้นได้หากลูกค้าชำระเงินไม่เสร็จในกรอบเวลาที่กำหนด โปรดทราบว่าคุณใช้ Google Play Developer API เพื่อตรวจสอบสถานะปัจจุบันของการซื้อได้ทุกเมื่อ
การจัดการกับการซื้อแบบหลายจำนวน
ซึ่งรองรับใน Google Play Billing Library เวอร์ชัน 4.0 ขึ้นไป Google Play ช่วยให้ลูกค้าซื้อไอเทมที่ซื้อในแอปเดียวกันได้มากกว่า 1 รายการในธุรกรรมเดียว โดยระบุจำนวนจากรถเข็นที่ซื้อ แอปของคุณควรจัดการการซื้อหลายรายการและมอบสิทธิ์ตามจำนวนการซื้อที่ระบุ
ตรรกะการจัดสรรของแอปต้องตรวจสอบจำนวนสินค้าเพื่อรองรับการซื้อหลายรายการ คุณสามารถเข้าถึงฟิลด์ quantity
จาก API รายการใดรายการหนึ่งต่อไปนี้
getQuantity()
จาก Google Play Billing LibraryPurchases.products.quantity
จาก Google Play Developer API
เมื่อเพิ่มตรรกะเพื่อจัดการการซื้อหลายรายการแล้ว คุณจะต้องเปิดใช้ฟีเจอร์การซื้อหลายรายการสำหรับผลิตภัณฑ์ที่เกี่ยวข้องในหน้าการจัดการผลิตภัณฑ์ในแอปใน Google Play Developer Console
ค้นหาการกําหนดค่าการเรียกเก็บเงินของผู้ใช้
getBillingConfigAsync()
ระบุประเทศที่ผู้ใช้ใช้ Google Play
คุณสามารถค้นหาการกำหนดค่าการเรียกเก็บเงินของผู้ใช้หลังจากสร้าง BillingClient
ข้อมูลโค้ดต่อไปนี้อธิบายวิธีโทรหา getBillingConfigAsync()
จัดการการตอบกลับด้วยการติดตั้งใช้งาน BillingConfigResponseListener
โปรแกรมรับฟังนี้จะรับการอัปเดตสำหรับคำค้นหาการกําหนดค่าการเรียกเก็บเงินทั้งหมดที่เริ่มต้นจากแอปของคุณ
หาก BillingResult
ที่แสดงผลไม่มีข้อผิดพลาด คุณสามารถตรวจสอบช่อง countryCode
ในออบเจ็กต์ BillingConfig
เพื่อดูประเทศใน Play ของผู้ใช้
Kotlin
// Use the default GetBillingConfigParams.
val getBillingConfigParams = GetBillingConfigParams.newBuilder().build()
billingClient.getBillingConfigAsync(getBillingConfigParams,
object : BillingConfigResponseListener {
override fun onBillingConfigResponse(
billingResult: BillingResult,
billingConfig: BillingConfig?
) {
if (billingResult.responseCode == BillingResponseCode.OK
&& billingConfig != null) {
val countryCode = billingConfig.countryCode
...
} else {
// TODO: Handle errors
}
}
})
Java
// Use the default GetBillingConfigParams.
GetBillingConfigParams getBillingConfigParams = GetBillingConfigParams.newBuilder().build();
billingClient.getBillingConfigAsync(getBillingConfigParams,
new BillingConfigResponseListener() {
public void onBillingConfigResponse(
BillingResult billingResult, BillingConfig billingConfig) {
if (billingResult.getResponseCode() == BillingResponseCode.OK
&& billingConfig != null) {
String countryCode = billingConfig.getCountryCode();
...
} else {
// TODO: Handle errors
}
}
});