เอกสารนี้อธิบายวิธีผสานรวม Google Play Billing Library เข้ากับแอปเพื่อเริ่มขายผลิตภัณฑ์
อายุการใช้งานของการซื้อ
ขั้นตอนการซื้อโดยทั่วไปสำหรับการซื้อครั้งเดียวหรือการสมัครใช้บริการมีดังนี้
- แสดงให้ผู้ใช้เห็นว่าสามารถซื้ออะไรได้บ้าง
- เปิดขั้นตอนการซื้อเพื่อให้ผู้ใช้ยอมรับการซื้อ
- ยืนยันการซื้อในเซิร์ฟเวอร์
- แสดงเนื้อหาให้ผู้ใช้เห็น
- รับทราบการนำส่งเนื้อหา สำหรับไอเทมที่ใช้แล้วหมดไป ให้ใช้การซื้อเพื่อให้ผู้ใช้ซื้อไอเทมนั้นได้อีกครั้ง
การสมัครใช้บริการจะต่ออายุโดยอัตโนมัติจนกว่าจะมีการยกเลิก การสมัครใช้บริการอาจมีสถานะต่อไปนี้
- ใช้งานอยู่: ผู้ใช้มีสถานะดีและมีสิทธิ์เข้าถึงการสมัครใช้บริการ
- ยกเลิกแล้ว: ผู้ใช้ยกเลิกแล้วแต่ยังคงมีสิทธิ์เข้าถึงจนกว่าจะหมดอายุ
- อยู่ในระยะเวลาผ่อนผัน: ผู้ใช้พบปัญหาในการชำระเงิน แต่ยังคงมีสิทธิ์เข้าถึงในขณะที่ Google กำลังลองเรียกเก็บเงินจากวิธีการชำระเงินอีกครั้ง
- ถูกระงับ: ผู้ใช้พบปัญหาเกี่ยวกับการชำระเงินและไม่มีสิทธิ์เข้าถึงอีกต่อไปขณะที่ Google กำลังลองใช้วิธีการชำระเงินอีกครั้ง
- หยุดชั่วคราว: ผู้ใช้หยุดการเข้าถึงชั่วคราวและจะไม่มีสิทธิ์เข้าถึงจนกว่าจะ กลับมาใช้ต่อ
- หมดอายุ: ผู้ใช้ยกเลิกและเสียสิทธิ์เข้าถึงการสมัครใช้บริการ ระบบจะถือว่าผู้ใช้เลิกใช้งานเมื่อการสมัครใช้บริการหมดอายุ
เริ่มต้นการเชื่อมต่อกับ Google Play
ขั้นตอนแรกในการผสานรวมกับระบบการเรียกเก็บเงินของ Google Play คือการเพิ่ม Google Play Billing Library ลงในแอปและเริ่มต้นการเชื่อมต่อ
เพิ่มการอ้างอิง Google Play Billing Library
เพิ่มทรัพยากร Dependency ของ Google Play Billing Library ลงในไฟล์ build.gradle ของแอปดังที่แสดงด้านล่าง
ดึงดูด
dependencies { def billing_version = "9.1.0" implementation "com.android.billingclient:billing:$billing_version" }
Kotlin
dependencies { val billing_version = "9.1.0" implementation("com.android.billingclient:billing:$billing_version") }
หากคุณใช้ Kotlin โมดูล KTX ของ Google Play Billing Library จะมีส่วนขยาย Kotlin และการรองรับโครูทีนที่ช่วยให้คุณเขียน Kotlin ตามสำนวนได้เมื่อใช้ Google Play Billing Library หากต้องการรวมส่วนขยายเหล่านี้ไว้ในโปรเจ็กต์ ให้เพิ่มทรัพยากร Dependency ต่อไปนี้ลงในไฟล์ build.gradle ของแอปตามที่แสดง
ดึงดูด
dependencies { def billing_version = "9.1.0" implementation "com.android.billingclient:billing-ktx:$billing_version" }
Kotlin
dependencies { val billing_version = "9.1.0" implementation("com.android.billingclient:billing-ktx:$billing_version") }
เริ่มต้น BillingClient
เมื่อเพิ่มการอ้างอิงใน Google Play Billing Library แล้ว คุณจะต้อง
เริ่มต้นอินสแตนซ์ BillingClient BillingClient เป็นอินเทอร์เฟซหลักสำหรับการสื่อสารระหว่าง Google Play Billing Library กับส่วนที่เหลือของแอป BillingClient มีเมธอดที่อำนวยความสะดวกทั้งแบบซิงโครนัสและอะซิงโครนัสสำหรับการดำเนินการเรียกเก็บเงินทั่วไปหลายรายการ โปรดทราบข้อมูลต่อไปนี้
- เราขอแนะนำให้คุณเปิดการเชื่อมต่อ
BillingClientที่ใช้งานอยู่เพียง 1 รายการในแต่ละครั้งเพื่อหลีกเลี่ยงการเรียกกลับPurchasesUpdatedListenerหลายครั้งสำหรับเหตุการณ์เดียว - เราขอแนะนำให้เริ่มการเชื่อมต่อสำหรับ BillingClient เมื่อแอปของคุณเปิดขึ้นหรือมาที่เบื้องหน้า เพื่อให้แอปประมวลผลการซื้อได้อย่างทันท่วงที ซึ่งทำได้โดยใช้
ActivityLifecycleCallbacksที่ลงทะเบียนโดยregisterActivityLifecycleCallbacksและฟัง onActivityResumed เพื่อเริ่มต้นการเชื่อมต่อเมื่อตรวจพบกิจกรรมที่กลับมาทำงานอีกครั้งเป็นครั้งแรก ดูรายละเอียดเพิ่มเติมเกี่ยวกับเหตุผลที่ควรปฏิบัติตามแนวทางปฏิบัติแนะนำนี้ได้ที่ส่วนการประมวลผลการซื้อ และอย่าลืมสิ้นสุดการเชื่อมต่อเมื่อปิดแอป
หากต้องการสร้าง 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 เพื่อรับ Callback เมื่อการตั้งค่าไคลเอ็นต์เสร็จสมบูรณ์และพร้อมที่จะส่งคำขอเพิ่มเติม
หากยังไม่ได้เปิดใช้การเชื่อมต่อบริการอีกครั้งโดยอัตโนมัติ คุณต้องใช้ตรรกะการลองใหม่เพื่อจัดการกับการเชื่อมต่อที่ขาดหายไปกับ Google Play ด้วย หากต้องการใช้ตรรกะการลองใหม่ ให้ ลบล้างเมธอด Callback 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() { // If automatic service reconnection is enabled, this can be left empty (no-op) // because the library handles retries. You can still use this for non-retry // tasks like logging or updating the UI to reflect a disconnected state. // Otherwise, 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. // It's a good practice to query products after the connection is established. queryProductDetails(); } } @Override public void onBillingServiceDisconnected() { // Try to restart the connection on the next request to // Google Play by calling the startConnection() method. // This is automatically handled by the library when you call a method that requires a connection. } });
สร้างการเชื่อมต่อใหม่โดยอัตโนมัติ
เมื่อมีการเปิดตัวเมธอด enableAutoServiceReconnection() ใน BillingClient.Builder เวอร์ชัน 8.0.0 ตอนนี้ Play Billing Library สามารถสร้างการเชื่อมต่อบริการอีกครั้งโดยอัตโนมัติหากมีการเรียก API ขณะที่บริการถูกตัดการเชื่อมต่อ ซึ่งอาจส่งผลให้การตอบกลับของ SERVICE_DISCONNECTED ลดลงเนื่องจากระบบจะจัดการการเชื่อมต่อใหม่ภายในก่อนที่จะเรียกใช้ API
วิธีเปิดใช้การเชื่อมต่อใหม่โดยอัตโนมัติ
เมื่อสร้างอินสแตนซ์ BillingClient ให้ใช้วิธี enableAutoServiceReconnection() ใน BillingClient.Builder เพื่อ
เปิดใช้การเชื่อมต่อใหม่โดยอัตโนมัติ
Kotlin
val billingClient = BillingClient.newBuilder(context) .setListener(listener) .enablePendingPurchases(PendingPurchasesParams.newBuilder().enableOneTimeProducts().build()) .enableAutoServiceReconnection() // Add this line to enable reconnection .build()
Java
BillingClient billingClient = BillingClient.newBuilder(context)
.setListener(listener)
.enablePendingPurchases()
.enableAutoServiceReconnection() // Add this line to enable reconnection
.build();
แสดงผลิตภัณฑ์ที่พร้อมจำหน่าย
หลังจากสร้างการเชื่อมต่อกับ Google Play แล้ว คุณก็พร้อมที่จะค้นหาผลิตภัณฑ์ที่พร้อมจำหน่ายและแสดงต่อผู้ใช้
การค้นหารายละเอียดสินค้าเป็นขั้นตอนสำคัญก่อนแสดงสินค้าต่อผู้ใช้ เนื่องจากจะแสดงข้อมูลสินค้าที่แปลแล้ว สำหรับการสมัครใช้บริการ ให้ตรวจสอบว่าการแสดงผลิตภัณฑ์เป็นไปตามนโยบายทั้งหมดของ Play
หากต้องการค้นหารายละเอียดไอเทมแบบเรียกเก็บเงินครั้งเดียว ให้เรียกใช้เมธอด queryProductDetailsAsync
เมธอดนี้สามารถแสดงข้อเสนอหลายรายการตามการกำหนดค่าผลิตภัณฑ์แบบเรียกเก็บเงินครั้งเดียว ดูข้อมูลเพิ่มเติมได้ที่ตัวเลือกและข้อเสนอการซื้อหลายรายการสำหรับผลิตภัณฑ์แบบเรียกเก็บเงินครั้งเดียว
หากต้องการจัดการผลลัพธ์ของการดำเนินการแบบอะซิงโครนัส คุณต้องระบุ Listener ที่ใช้อินเทอร์เฟซ ProductDetailsResponseListener ด้วย
จากนั้นคุณสามารถลบล้าง onProductDetailsResponse ซึ่งจะแจ้งให้ Listener ทราบเมื่อการค้นหาเสร็จสิ้น ดังที่แสดงในตัวอย่างต่อไปนี้
Kotlin
val queryProductDetailsParams = QueryProductDetailsParams.newBuilder() .setProductList( listOf( Product.newBuilder() .setProductId("product_id_example") .setProductType(ProductType.SUBS) .build() ) ) .build() billingClient.queryProductDetailsAsync(queryProductDetailsParams) { billingResult, queryProductDetailsResult -> if (billingResult.responseCode == BillingResponseCode.OK) { for (productDetails in queryProductDetailsResult.productDetailsList) { // Process successfully retrieved product details here. } for (unfetchedProduct in queryProductDetailsResult.unfetchedProductList) { // Handle any unfetched products as appropriate. } } }
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,
QueryProductDetailsResult queryProductDetailsResult) {
if (billingResult.getResponseCode() == BillingResponseCode.OK) {
for (ProductDetails productDetails : queryProductDetailsResult.getProductDetailsList()) {
// Process successfully retrieved product details here.
}
for (UnfetchedProduct unfetchedProduct : queryProductDetailsResult.getUnfetchedProductList()) {
// Handle any unfetched products as appropriate.
}
}
}
}
)
เมื่อค้นหารายละเอียดสินค้า ให้ส่งอินสแตนซ์ของ 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 7 เพื่อให้การรองรับที่เหมาะสมสำหรับสถานการณ์นี้
ประมวลผลผลลัพธ์
Google Play Billing Library จะจัดเก็บผลการค้นหาในออบเจ็กต์
QueryProductDetailsResult QueryProductDetailsResult มี List ของออบเจ็กต์ ProductDetails จากนั้นคุณจะเรียกใช้เมธอดต่างๆ ในออบเจ็กต์ ProductDetails แต่ละรายการในลิสต์เพื่อดูข้อมูลที่เกี่ยวข้องเกี่ยวกับผลิตภัณฑ์แบบเรียกเก็บเงินครั้งเดียวที่ดึงข้อมูลสำเร็จ เช่น ราคาหรือคำอธิบาย หากต้องการดูข้อมูลรายละเอียดสินค้าที่พร้อมใช้งาน โปรดดูรายการเมธอดในคลาส ProductDetails
QueryProductDetailsResult ยังมี List ของออบเจ็กต์ UnfetchedProduct ด้วย จากนั้นคุณสามารถค้นหา UnfetchedProduct แต่ละรายการเพื่อรับรหัสสถานะที่สอดคล้องกับสาเหตุที่ดึงข้อมูลไม่สำเร็จ
หากต้องการดูข้อมูลสินค้าที่ยังไม่ได้ดึงข้อมูลซึ่งพร้อมใช้งาน ให้ดูรายการเมธอดในคลาส UnfetchedProduct
ก่อนที่จะเสนอขายไอเทม ให้ตรวจสอบว่าผู้ใช้ยังไม่ได้เป็นเจ้าของไอเทมนั้น หากผู้ใช้มีไอเทมที่ใช้แล้วหมดไปซึ่งยังอยู่ในคลังไอเทม ผู้ใช้ต้องใช้ไอเทมนั้นก่อนจึงจะซื้อได้อีกครั้ง
ก่อนเสนอการสมัครใช้บริการ ให้ตรวจสอบว่าผู้ใช้ไม่ได้สมัครใช้บริการอยู่แล้ว และโปรดทราบสิ่งต่อไปนี้
สำหรับการสมัครใช้บริการ เมธอด
queryProductDetailsAsync()จะแสดงรายละเอียดผลิตภัณฑ์ที่ต้องสมัครใช้บริการและข้อเสนอที่ผู้ใช้มีสิทธิ์รับสูงสุด 50 รายการต่อการสมัครใช้บริการ หากผู้ใช้พยายามซื้อข้อเสนอที่ไม่มีสิทธิ์ (เช่น หากแอปแสดงรายการข้อเสนอที่มีสิทธิ์ซึ่งล้าสมัย) Play จะแจ้งให้ผู้ใช้ทราบว่าไม่มีสิทธิ์ และผู้ใช้สามารถเลือกซื้อแพ็กเกจเริ่มต้นแทนได้สำหรับผลิตภัณฑ์แบบเรียกเก็บเงินครั้งเดียว เมธอด
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) // Get the offer token: // a. For one-time products, call ProductDetails.getOneTimePurchaseOfferDetailsList() // for a list of offers that are available to the user. // b. For subscriptions, call ProductDetails.getSubscriptionOfferDetails() // 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<BillingFlowParams.ProductDetailsParams> productDetailsParamsList = ImmutableList.of( BillingFlowParams.ProductDetailsParams.newBuilder() // retrieve a value for "productDetails" by calling queryProductDetailsAsync() .setProductDetails(productDetails) // Get the offer token: // a. For one-time products, call ProductDetails.getOneTimePurchaseOfferDetailsList() // for a list of offers that are available to the user. // b. For subscriptions, call ProductDetails.getSubscriptionOfferDetails() // 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
อินเทอร์เฟซ โดยจะระบุ Listener โดยใช้เมธอด setListener() เมื่อคุณเริ่มต้นไคลเอ็นต์
คุณต้องใช้ onPurchasesUpdated() เพื่อจัดการโค้ดตอบกลับที่อาจเกิดขึ้น ตัวอย่างต่อไปนี้แสดงวิธีลบล้าง onPurchasesUpdated()
Kotlin
override fun onPurchasesUpdated(billingResult: BillingResult, purchases: List<Purchase>?) { if (billingResult.responseCode == BillingResponseCode.OK && purchases != null) { for (purchase in purchases) { // Process the purchase as described in the next section. } } else if (billingResult.responseCode == BillingResponseCode.USER_CANCELED) { // Handle an error caused by a user canceling 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) {
// Process the purchase as described in the next section.
}
} else if (billingResult.getResponseCode() == BillingResponseCode.USER_CANCELED) {
// Handle an error caused by a user canceling the purchase flow.
} else {
// Handle any other error codes.
}
}
การซื้อที่สำเร็จจะสร้างหน้าจอการซื้อใน Google Play ที่สำเร็จซึ่งคล้ายกับ รูปที่ 2
การซื้อที่สำเร็จจะสร้างโทเค็นการซื้อด้วย ซึ่งเป็นตัวระบุที่ไม่ซ้ำกัน ที่แสดงถึงผู้ใช้และรหัสสินค้าสำหรับผลิตภัณฑ์แบบเรียกเก็บเงินครั้งเดียว ที่ผู้ใช้ซื้อ แอปของคุณสามารถจัดเก็บโทเค็นการซื้อไว้ในเครื่องได้ แต่เราขอแนะนำอย่างยิ่งให้ส่งโทเค็นไปยังเซิร์ฟเวอร์แบ็กเอนด์ที่ปลอดภัย ซึ่งคุณสามารถยืนยันการซื้อและป้องกันการประพฤติมิชอบได้ กระบวนการนี้จะอธิบายเพิ่มเติมในการตรวจจับและการประมวลผลการซื้อ
นอกจากนี้ ผู้ใช้จะได้รับอีเมลใบเสร็จของธุรกรรมที่มีรหัสคำสั่งซื้อหรือรหัสที่ไม่ซ้ำกันของธุรกรรมด้วย ผู้ใช้จะได้รับอีเมลที่มีรหัสคำสั่งซื้อที่ไม่ซ้ำกันสำหรับการซื้อผลิตภัณฑ์แบบเรียกเก็บเงินครั้งเดียวแต่ละรายการ รวมถึงสำหรับการซื้อการสมัครใช้บริการครั้งแรกและการต่ออายุใหม่อัตโนมัติแบบตามรอบในครั้งต่อๆ ไป คุณใช้รหัสคำสั่งซื้อเพื่อจัดการการคืนเงินใน Google Play Console ได้
ระบุราคาที่ปรับเปลี่ยนในแบบของคุณ
หากแอปของคุณสามารถจัดจำหน่ายให้แก่ผู้ใช้ในสหภาพยุโรปได้ ให้ใช้เมธอด setIsOfferPersonalized() เมื่อเรียกใช้ launchBillingFlow เพื่อเปิดเผยต่อผู้ใช้ว่าราคาของรายการได้รับการปรับเปลี่ยนให้เหมาะกับแต่ละบุคคลโดยใช้การตัดสินใจอัตโนมัติ
คุณต้องปรึกษา Art 6 (1) (ea) CRD ของคำสั่งว่าด้วยสิทธิของผู้บริโภค 2011/83/EU เพื่อตรวจสอบว่าราคาที่คุณเสนอให้นั้นมีการปรับเปลี่ยนตามโปรไฟล์ของผู้ใช้หรือไม่
setIsOfferPersonalized() รับอินพุตบูลีน เมื่อtrue UI ของ Play จะรวมการเปิดเผยข้อมูล เมื่อ false UI จะไม่แสดงการเปิดเผยข้อมูล ค่าเริ่มต้นคือ false
ดูข้อมูลเพิ่มเติมได้ที่ศูนย์ช่วยเหลือสำหรับผู้บริโภค
แนบตัวระบุผู้ใช้
เมื่อเปิดขั้นตอนการซื้อ แอปจะแนบตัวระบุผู้ใช้ที่คุณมีสำหรับผู้ใช้ที่ทำการซื้อโดยใช้ obfuscatedAccountId หรือ obfuscatedProfileId ได้ ตัวอย่างตัวระบุอาจเป็นเวอร์ชันที่ผ่านการปกปิด ของการเข้าสู่ระบบของผู้ใช้ในระบบของคุณ การตั้งค่าพารามิเตอร์เหล่านี้จะช่วยให้ Google ตรวจจับการประพฤติมิชอบได้ นอกจากนี้ ยังช่วยให้คุณมั่นใจได้ว่าการซื้อจะได้รับการระบุแหล่งที่มาให้กับผู้ใช้ที่ถูกต้องตามที่กล่าวถึงในการให้สิทธิ์แก่ผู้ใช้
ตรวจจับและประมวลผลการซื้อ
การตรวจหาและการประมวลผลการซื้อที่อธิบายไว้ในส่วนนี้ ใช้ได้กับการซื้อทุกประเภท รวมถึงการซื้อนอกแอป เช่น การแลกรับโปรโมชัน
แอปจะตรวจหาการซื้อใหม่และการซื้อที่รอดำเนินการที่เสร็จสมบูรณ์ด้วยวิธีใดวิธีหนึ่งต่อไปนี้
- เมื่อมีการเรียกใช้
onPurchasesUpdatedอันเป็นผลมาจากการที่แอปของคุณเรียกใช้launchBillingFlow(ตามที่กล่าวถึงในส่วนก่อนหน้า) หรือหากแอปของคุณทำงานโดยมีการเชื่อมต่อ Billing Library ที่ใช้งานอยู่เมื่อมีการซื้อนอกแอปหรือการซื้อที่รอดำเนินการเสร็จสมบูรณ์ เช่น สมาชิกในครอบครัวอนุมัติการซื้อที่รอดำเนินการในอุปกรณ์อื่น - เมื่อแอปเรียกใช้ queryPurchasesAsync เพื่อค้นหาการซื้อของผู้ใช้
สำหรับข้อ 1 ระบบจะเรียกใช้ onPurchasesUpdated โดยอัตโนมัติสำหรับการซื้อใหม่หรือการซื้อที่เสร็จสมบูรณ์ ตราบใดที่แอปของคุณทำงานอยู่และมีการเชื่อมต่อ Google Play Billing Library ที่ใช้งานอยู่ หากแอปพลิเคชันไม่ทำงานหรือแอปไม่มีการเชื่อมต่อ Google Play Billing Library ที่ใช้งานอยู่ ระบบจะไม่เรียกใช้ onPurchasesUpdated โปรดทราบว่าเราขอแนะนำให้แอปของคุณพยายามรักษาการเชื่อมต่อที่ใช้งานอยู่ตราบใดที่แอปยังทำงานอยู่เบื้องหน้า เพื่อให้แอปได้รับการอัปเดตการซื้ออย่างทันท่วงที
สำหรับข้อ 2 คุณต้องเรียกใช้ BillingClient.queryPurchasesAsync() เพื่อให้แน่ใจว่าแอปจะประมวลผลการซื้อทั้งหมด เราขอแนะนำให้คุณทำเช่นนี้เมื่อแอป สร้างการเชื่อมต่อกับ Google Play Billing Library ได้สำเร็จ (ซึ่งขอแนะนำเมื่อแอปเปิดตัวหรือมาที่เบื้องหน้าตามที่อธิบายไว้ในเริ่มต้น BillingClient ซึ่งทำได้โดยการเรียกใช้ queryPurchasesAsync เมื่อได้รับผลลัพธ์ที่สำเร็จไปยัง onServiceConnected การปฏิบัติตามคำแนะนำนี้เป็นสิ่งสำคัญในการจัดการเหตุการณ์และสถานการณ์ต่างๆ เช่น
- ปัญหาเกี่ยวกับเครือข่ายระหว่างการซื้อ: ผู้ใช้สามารถทำการซื้อได้สำเร็จและได้รับการยืนยันจาก Google แต่อุปกรณ์ขาดการเชื่อมต่อเครือข่ายก่อนที่อุปกรณ์และแอปจะได้รับการแจ้งเตือนการซื้อผ่าน
PurchasesUpdatedListener - อุปกรณ์หลายเครื่อง: ผู้ใช้อาจซื้อไอเทมในอุปกรณ์เครื่องหนึ่งและคาดหวังว่าจะเห็นไอเทมดังกล่าวเมื่อเปลี่ยนไปใช้อุปกรณ์เครื่องอื่น
- การจัดการการซื้อที่ดำเนินการนอกแอป: การซื้อบางรายการ เช่น การแลกสิทธิ์โปรโมชัน สามารถดำเนินการนอกแอปได้
- การจัดการการเปลี่ยนสถานะการซื้อ: ผู้ใช้อาจชำระเงินสำหรับการซื้อที่ รอดำเนินการในขณะที่แอปพลิเคชันของคุณไม่ได้ทำงาน และคาดหวังที่จะได้รับการ ยืนยันว่าได้ทำการซื้อเสร็จสมบูรณ์แล้วเมื่อเปิดแอป
- การสมัครใช้บริการที่ถูกระงับ: การสมัครใช้บริการอาจถูกระงับในระหว่างวงจรการสมัครใช้บริการ BillingClient.queryPurchasesAsync() จะแสดงผลการสมัครใช้บริการที่ถูกระงับก็ต่อเมื่อมีการตั้งค่าพารามิเตอร์
includeSuspendedSubscriptionsในQueryPurchasesParams.Builderเท่านั้น การสมัครใช้บริการที่ถูกระงับ จะไม่แสดงในPurchasesUpdatedListener
เมื่อแอปตรวจพบการซื้อใหม่หรือการซื้อที่เสร็จสมบูรณ์แล้ว แอปควรดำเนินการดังนี้
- ยืนยันการซื้อ
- ให้สิทธิ์เข้าถึงเนื้อหาแก่ผู้ใช้สำหรับการซื้อที่เสร็จสมบูรณ์
- แจ้งให้ผู้ใช้ทราบ
- แจ้งให้ Google ทราบว่าแอปของคุณประมวลผลการซื้อที่เสร็จสมบูรณ์แล้ว
เราจะอธิบายขั้นตอนเหล่านี้อย่างละเอียดในส่วนต่อไปนี้ และตามด้วยส่วนสรุปขั้นตอนทั้งหมด
ยืนยันการซื้อ
แอปของคุณควรยืนยันความถูกต้องของการซื้อก่อนให้สิทธิประโยชน์แก่ผู้ใช้เสมอ ซึ่งทำได้โดยทำตามหลักเกณฑ์ที่อธิบายไว้ในยืนยันการซื้อก่อนให้สิทธิ์ หลังจากยืนยันการซื้อแล้วเท่านั้น แอปของคุณจึงควรดำเนินการซื้อต่อและให้สิทธิ์แก่ผู้ใช้ ซึ่งจะอธิบายในส่วนถัดไป หากการซื้อไม่ผ่านการยืนยัน การตรวจสอบสิทธิ์ หรือการตรวจสอบการละเมิด โปรดดูหัวข้อจัดการการซื้อที่ถูกปฏิเสธหรือดำเนินการไม่สำเร็จ
ให้สิทธิ์แก่ผู้ใช้
เมื่อแอปยืนยันการซื้อแล้ว แอปจะให้สิทธิ์แก่ผู้ใช้ต่อไปและแจ้งให้ผู้ใช้ทราบได้
ก่อนให้สิทธิ์ โปรดตรวจสอบว่าแอปของคุณตรวจสอบว่าสถานะการซื้อเป็น PURCHASED หากการซื้ออยู่ในสถานะ "รอดำเนินการ" แอปควรแจ้งให้ผู้ใช้ทราบว่ายังต้องดำเนินการให้เสร็จสิ้นเพื่อทำการซื้อให้เสร็จสมบูรณ์ก่อนที่จะได้รับสิทธิ์
ให้สิทธิ์เฉพาะเมื่อการซื้อเปลี่ยนจาก "รอดำเนินการ" เป็น "ซื้อแล้ว" เท่านั้น
ดูข้อมูลเพิ่มเติมได้ในการจัดการธุรกรรมที่รอดำเนินการ
หากคุณแนบตัวระบุผู้ใช้กับการซื้อตามที่อธิบายไว้ในการแนบตัวระบุผู้ใช้ คุณจะดึงข้อมูลและใช้ตัวระบุเพื่อระบุแหล่งที่มาของผู้ใช้ที่ถูกต้องในระบบได้ เทคนิคนี้มีประโยชน์เมื่อต้องกระทบยอดการซื้อ ในกรณีที่แอปอาจสูญเสียบริบทเกี่ยวกับผู้ใช้ที่ทำการซื้อ Google Play ขอแนะนำให้คุณยืนยันตัวระบุเหล่านี้ในแบ็กเอนด์ที่ปลอดภัยก่อนให้สิทธิ์ เพื่อป้องกันการละเมิด ดูข้อมูลเพิ่มเติมได้ที่ยืนยันการซื้อก่อนให้สิทธิ์ โปรดทราบว่าการซื้อที่ทำนอกแอปจะไม่มีการตั้งค่าตัวระบุเหล่านี้ ในกรณีนี้ แอปของคุณสามารถให้สิทธิ์แก่ผู้ใช้ที่เข้าสู่ระบบ หรือแจ้งให้ผู้ใช้เลือกบัญชีที่ต้องการก็ได้
สำหรับการสั่งล่วงหน้า การซื้อจะอยู่ในสถานะรอดำเนินการก่อนถึงเวลาวางจำหน่าย การซื้อแบบสั่งล่วงหน้าจะเสร็จสมบูรณ์เมื่อถึงเวลาวางจำหน่ายและเปลี่ยนสถานะเป็น "ซื้อแล้ว" โดยไม่ต้องดำเนินการใดๆ เพิ่มเติม
แจ้งให้ผู้ใช้ทราบ
หลังจากให้สิทธิ์แก่ผู้ใช้แล้ว แอปของคุณควรแสดงการแจ้งเตือนเพื่อ รับทราบว่าการซื้อสำเร็จแล้ว การแจ้งเตือนนี้จะช่วยให้ผู้ใช้ไม่สับสนว่าการซื้อเสร็จสมบูรณ์หรือไม่ ซึ่งอาจส่งผลให้ผู้ใช้หยุดใช้แอป ติดต่อทีมสนับสนุนผู้ใช้ หรือร้องเรียนเกี่ยวกับเรื่องนี้บนโซเชียลมีเดีย โปรดทราบว่าแอปของคุณอาจตรวจพบการอัปเดตการซื้อได้ทุกเมื่อในระหว่างวงจรการใช้งานแอปพลิเคชัน ตัวอย่างเช่น ผู้ปกครองอนุมัติการซื้อที่รอดำเนินการในอุปกรณ์อื่น ซึ่งในกรณีนี้แอปของคุณอาจต้องการเลื่อนการแจ้งเตือนผู้ใช้ไปยังเวลาที่เหมาะสม ตัวอย่างบางกรณีที่การหน่วงเวลา เหมาะสม ได้แก่
- ในระหว่างส่วนที่เป็นแอ็กชันของเกมหรือคัตซีน การแสดงข้อความอาจทำให้ผู้ใช้เสียสมาธิ ในกรณีนี้ คุณต้องแจ้งให้ผู้ใช้ทราบหลังจากที่ส่วนการดำเนินการ สิ้นสุดลง
- ในระหว่างบทแนะนำเบื้องต้นและส่วนการตั้งค่าผู้ใช้ของเกม เช่น ผู้ใช้อาจทำการซื้อนอกแอปก่อนที่จะติดตั้งแอป เราขอแนะนำให้คุณแจ้งให้ผู้ใช้ใหม่ทราบเกี่ยวกับรางวัลทันทีหลังจากที่ผู้ใช้เปิดเกมหรือในระหว่างการตั้งค่าผู้ใช้ครั้งแรก หากแอปของคุณกำหนดให้ผู้ใช้สร้างบัญชีหรือเข้าสู่ระบบก่อนให้สิทธิ์แก่ผู้ใช้ เราขอแนะนำให้แจ้งให้ผู้ใช้ทราบถึงขั้นตอนที่ต้องดำเนินการเพื่อรับสิทธิ์ในการซื้อ ขั้นตอนนี้สำคัญมากเนื่องจากระบบจะคืนเงินสำหรับการซื้อหลังจากผ่านไป 3 วันหากแอปของคุณไม่ได้ประมวลผลการซื้อ
เมื่อแจ้งให้ผู้ใช้ทราบเกี่ยวกับการซื้อ Google Play ขอแนะนำให้ใช้กลไกต่อไปนี้
- แสดงกล่องโต้ตอบในแอป
- ส่งข้อความไปยังกล่องข้อความในแอป และระบุอย่างชัดเจนว่ามีข้อความใหม่ในกล่องข้อความในแอป
- ใช้ข้อความแจ้งเตือนของระบบปฏิบัติการ
การแจ้งเตือนควรแจ้งให้ผู้ใช้ทราบถึงสิทธิประโยชน์ที่ได้รับ เช่น "คุณซื้อเหรียญทอง 100 เหรียญ" นอกจากนี้ หากการซื้อเป็นผลมาจากสิทธิประโยชน์ของโปรแกรม เช่น Play Pass แอปของคุณจะสื่อสารเรื่องนี้กับผู้ใช้ เช่น "ได้รับไอเทมแล้ว คุณเพิ่งได้รับ 100 Gem ด้วย Play Pass ต่อไป" แต่ละโปรแกรมอาจมีคำแนะนำเกี่ยวกับข้อความที่แนะนำให้แสดงต่อผู้ใช้เพื่อสื่อสารประโยชน์
แจ้ง Google ว่าประมวลผลการซื้อแล้ว
หลังจากแอปให้สิทธิ์แก่ผู้ใช้และแจ้งให้ผู้ใช้ทราบเกี่ยวกับธุรกรรมที่สำเร็จแล้ว แอปจะต้องแจ้งให้ Google ทราบว่าการซื้อได้รับการประมวลผลเรียบร้อยแล้ว ซึ่งทำได้โดยการรับทราบการซื้อและต้องดำเนินการภายใน 3 วัน เพื่อไม่ให้ระบบคืนเงินโดยอัตโนมัติและเพิกถอนสิทธิ์ กระบวนการรับทราบการซื้อประเภทต่างๆ มีอธิบายไว้ในส่วนต่อไปนี้
ผลิตภัณฑ์ที่ใช้แล้วหมดไป
สำหรับสินค้าที่ใช้สิ้นเปลือง หากแอปมีแบ็กเอนด์ที่ปลอดภัย เราขอแนะนำให้ใช้ 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
val consumeParams = ConsumeParams.newBuilder() .setPurchaseToken(purchase.getPurchaseToken()) .build() val consumeResult = withContext(Dispatchers.IO) { client.consumePurchase(consumeParams) }
Java
ConsumeParams consumeParams = ConsumeParams.newBuilder().setPurchaseToken(purchase.getPurchaseToken()).build(); ConsumeResponseListener listener = (billingResult, 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 = billingClient val acknowledgePurchaseParams = AcknowledgePurchaseParams.newBuilder() .setPurchaseToken(purchase.purchaseToken) val ackPurchaseResult = withContext(Dispatchers.IO) { client.acknowledgePurchase(acknowledgePurchaseParams.build()) }
Java
if (purchase.getPurchaseState() == Purchase.PurchaseState.PURCHASED) { if (!purchase.isAcknowledged()) { AcknowledgePurchaseParams acknowledgePurchaseParams = AcknowledgePurchaseParams.newBuilder() .setPurchaseToken(purchase.getPurchaseToken()) .build(); billingClient.acknowledgePurchase(acknowledgePurchaseParams, (billingResult) -> { // Acknowledgment handled. }); } }
การติดตาม
การสมัครใช้บริการจะได้รับการจัดการในลักษณะเดียวกับไอเทมที่ใช้ไม่ได้ หากเป็นไปได้ ให้ใช้
Purchases.subscriptions.acknowledge จาก
Google Play Developer API เพื่อตอบรับการซื้อจากแบ็กเอนด์ที่ปลอดภัย
ได้อย่างน่าเชื่อถือ ตรวจสอบว่าก่อนหน้านี้
Purchases.subscriptions:get ไม่ได้ยืนยันการซื้อแล้วโดยดูacknowledgementStateในแหล่งข้อมูลการซื้อ
หรือคุณจะรับทราบการสมัครใช้บริการโดยใช้ BillingClient.acknowledgePurchase() จาก Google Play Billing Library หลังจากตรวจสอบ isAcknowledged() ก็ได้ การสมัครใช้บริการครั้งแรกทั้งหมดต้องได้รับการรับทราบ การต่ออายุการสมัครใช้บริการไม่จำเป็นต้องได้รับการรับทราบ ดูข้อมูลเพิ่มเติมเกี่ยวกับเวลาที่ต้องรับทราบการสมัครใช้บริการได้ที่หัวข้อขายการสมัครใช้บริการ
จัดการการซื้อที่ถูกปฏิเสธหรือไม่สำเร็จ
หากการซื้อไม่ผ่านการตรวจสอบแบ็กเอนด์ การตรวจสอบสิทธิ์ของผู้ใช้ การตรวจสอบการประพฤติมิชอบและการละเมิด หรือหากระบบไม่สามารถให้สิทธิ์ได้ โปรดอย่าให้สิทธิ์และอย่ารับทราบหรือใช้การซื้อนั้น
แม้ว่าการซื้อที่ไม่ได้รับการรับทราบจะได้รับเงินคืนและถูกเพิกถอนโดยอัตโนมัติหลังจาก ช่วงเวลาการรับทราบหมดอายุเพื่อเป็นมาตรการด้านความปลอดภัยสำหรับผู้บริโภค แต่คุณไม่ควรอาศัย ช่วงเวลาการหมดอายุนี้ในการปฏิเสธการซื้อ การปล่อยให้กรอบเวลารับทราบหมดอายุจะทำให้คำสั่งซื้ออยู่ในสถานะไม่ได้รับการรับทราบและไม่ชัดเจนสำหรับ Google Play ซึ่งไม่สามารถแยกความแตกต่างระหว่างการปฏิเสธโดยเจตนาของนักพัฒนาแอปกับการหมดเวลาการประมวลผลแบ็กเอนด์
แต่ให้เพิกถอนและคืนเงินสำหรับการซื้อที่ถูกปฏิเสธจากแบ็กเอนด์ทันทีโดยใช้ Google Play Developer API ดังนี้
- การสมัครใช้บริการ: เรียกใช้
purchases.subscriptionsv2.revokeโดยมี"fullRefund": {}ในrevocationContextการดำเนินการนี้จะสิ้นสุดการสมัครใช้บริการ เพิกถอนสิทธิ์เข้าถึง และเริ่มการคืนเงินเต็มจำนวนทันที - ผลิตภัณฑ์แบบเรียกเก็บเงินครั้งเดียว: เรียกใช้
orders.refundโดยตั้งค่าพารามิเตอร์revokeเป็นtrueเพื่อคืนเงินคำสั่งซื้อทันทีและเพิกถอนสิทธิ์ ของคำสั่งซื้อ เมื่อเรียกใช้เมธอดนี้ คุณต้องส่งรหัสคำสั่งซื้อของการซื้อ ซึ่งสามารถเรียกข้อมูลผ่านPurchase.getOrderId()หรือpurchases.productsv2.getproductpurchasev2ห้ามเรียกใช้consumeAsync(),acknowledgePurchase(),Purchases.products:consumeหรือPurchases.products:acknowledgeกับการซื้อที่ถูกปฏิเสธ - ลักษณะการทำงานของ RTDN และการซื้อที่เป็นโมฆะ: การเพิกถอนและการคืนเงินที่นักพัฒนาแอปเป็นผู้เริ่ม (
purchases.subscriptionsv2.revokeและorders.refundโดยตั้งค่าrevokeเป็นtrue) จะทริกเกอร์การแจ้งเตือนแบบเรียลไทม์สำหรับนักพัฒนาแอปและบันทึกไว้ใน Voided Purchases API (purchases.voidedpurchases.listโดยตั้งค่าช่องการตอบกลับvoidedSourceเป็น1สำหรับนักพัฒนาแอป):- การสมัครใช้บริการ: ส่งทั้งการแจ้งเตือน
SUBSCRIPTION_REVOKEDและVoidedPurchaseNotification - ผลิตภัณฑ์แบบเรียกเก็บเงินครั้งเดียว: ส่ง
VoidedPurchaseNotification(และONE_TIME_PRODUCT_CANCELEDการแจ้งเตือนหากคุณกำหนดค่าแอปใน Play Console เพื่อรับการแจ้งเตือนเกี่ยวกับผลิตภัณฑ์แบบเรียกเก็บเงินครั้งเดียวทั้งหมด) - การเรียกใช้
orders.refundโดยไม่ได้ตั้งค่าrevokeเป็นtrueจะคืนเงิน คำสั่งซื้อโดยไม่เพิกถอนสิทธิ์และไม่ทริกเกอร์การเพิกถอนหรือ การแจ้งเตือนการซื้อที่ถูกยกเลิก ดูรายละเอียดเพิ่มเติมได้ที่หัวข้อจัดการการสมัครใช้บริการและการซื้อครั้งเดียว
- การสมัครใช้บริการ: ส่งทั้งการแจ้งเตือน
สรุป
ต่อไปนี้คือสรุปขั้นตอนเหล่านี้
ส่งการซื้อไปยังแบ็กเอนด์ที่ปลอดภัยเพื่อยืนยันการซื้อก่อนให้สิทธิ์
อัปเดตพื้นที่เก็บข้อมูลการให้สิทธิ์ด้วยการซื้อ หากการซื้ออยู่ในสถานะรอดำเนินการ ให้ตรวจสอบว่าสิทธิ์ได้รับการทำเครื่องหมายเป็นรอดำเนินการและผู้ใช้ยังไม่ได้รับสิทธิประโยชน์ เราขอแนะนำให้ทำขั้นตอนนี้ในแบ็กเอนด์ที่ปลอดภัย และสามารถรวมไว้ในการเรียก API ไปยังแบ็กเอนด์ในขั้นตอนที่ 1 ได้
แจ้งให้ผู้ใช้ทราบโดยใช้ข้อความที่เหมาะสม (เลื่อนการแจ้งเตือนออกไปหากจำเป็นตามที่ได้อธิบายไว้ก่อนหน้านี้)
แจ้งให้ Google ทราบว่ามีการประมวลผลการซื้อแล้วโดยทำตามขั้นตอน ที่อธิบายไว้ในส่วนการประมวลผลการซื้อ
หากต้องการยืนยันว่าแอปได้ติดตั้งใช้งานขั้นตอนเหล่านี้อย่างถูกต้องแล้ว ให้ทำตามคู่มือการทดสอบ
จัดการธุรกรรมที่รอดำเนินการ
Google Play รองรับธุรกรรมที่รอดำเนินการหรือธุรกรรมที่ต้องมีขั้นตอนเพิ่มเติมอย่างน้อย 1 ขั้นตอนระหว่างที่ผู้ใช้เริ่มการซื้อกับเมื่อระบบประมวลผลวิธีการชำระเงินสำหรับการซื้อ แอปของคุณไม่ควรให้สิทธิ์ การซื้อประเภทนี้จนกว่า Google จะแจ้งให้คุณทราบว่าระบบเรียกเก็บเงินจากวิธีการชำระเงินของผู้ใช้ ได้สำเร็จแล้ว
เช่น ผู้ใช้สามารถเริ่มธุรกรรมโดยเลือกกิจการที่มีหน้าร้านจริงที่ตนจะชำระเงินด้วยเงินสดในภายหลัง ผู้ใช้จะได้รับรหัสผ่านทั้งการแจ้งเตือนและอีเมล เมื่อผู้ใช้มาถึงร้านค้าจริงแล้ว ก็สามารถ แลกรหัสกับแคชเชียร์และชำระเงินด้วยเงินสดได้ จากนั้น Google จะแจ้งให้ทั้งคุณและผู้ใช้ทราบว่าได้รับการชำระเงินแล้ว จากนั้นแอปของคุณจะให้สิทธิ์แก่ผู้ใช้ได้
เรียกใช้ enablePendingPurchases() เป็นส่วนหนึ่งของการเริ่มต้น BillingClient เพื่อเปิดใช้ธุรกรรมที่รอดำเนินการสำหรับแอปของคุณ แอปต้องเปิดใช้และรองรับธุรกรรมที่รอดำเนินการสำหรับผลิตภัณฑ์แบบเรียกเก็บเงินครั้งเดียว ก่อนเพิ่มการรองรับ โปรดทำความเข้าใจวงจรการซื้อสำหรับธุรกรรมที่รอดำเนินการ
เมื่อแอปได้รับการซื้อใหม่ ไม่ว่าจะผ่าน PurchasesUpdatedListener หรือเป็นผลจากการเรียกใช้ queryPurchasesAsync ให้ใช้เมธอด getPurchaseState() เพื่อ
พิจารณาว่าสถานะการซื้อเป็น PURCHASED หรือ PENDING คุณควรให้สิทธิ์ก็ต่อเมื่อสถานะเป็น PURCHASED
หากแอปของคุณทำงานอยู่และมีการเชื่อมต่อ Play Billing Library ที่ใช้งานอยู่
เมื่อผู้ใช้ทำการซื้อเสร็จสมบูรณ์ ระบบจะเรียกใช้ PurchasesUpdatedListener อีกครั้ง และตอนนี้ PurchaseState จะเป็น PURCHASED ณ จุดนี้ แอปของคุณจะประมวลผลการซื้อได้โดยใช้วิธีมาตรฐานสำหรับการตรวจหาและการประมวลผลการซื้อ แอปของคุณควรเรียกใช้ queryPurchasesAsync() ในเมธอด onResume() ของแอปเพื่อจัดการการซื้อที่เปลี่ยนเป็นสถานะPURCHASEDขณะที่แอปไม่ได้ทำงานอยู่
เมื่อการซื้อเปลี่ยนจาก PENDING เป็น PURCHASED ไคลเอ็นต์ real_time_developer_notifications จะได้รับการแจ้งเตือน ONE_TIME_PRODUCT_PURCHASED หรือ SUBSCRIPTION_PURCHASED หากมีการยกเลิกการซื้อ คุณจะได้รับการแจ้งเตือน ONE_TIME_PRODUCT_CANCELED หรือ SUBSCRIPTION_PENDING_PURCHASE_CANCELED ซึ่งอาจเกิดขึ้นได้หากลูกค้าไม่ชำระเงินให้เสร็จสมบูรณ์ภายในกรอบเวลาที่กำหนด โปรดทราบว่าคุณสามารถใช้ Google Play Developer API เพื่อตรวจสอบสถานะปัจจุบันของการซื้อได้เสมอ
จัดการการซื้อหลายรายการ
Google Play Billing Library เวอร์ชัน 4.0 ขึ้นไปรองรับการอนุญาตให้ลูกค้าซื้อผลิตภัณฑ์แบบเรียกเก็บเงินครั้งเดียวรายการเดียวกันมากกว่า 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 { // Handle errors } } } )
Java
GetBillingConfigParams getBillingConfigParams = GetBillingConfigParams.newBuilder().build(); billingClient.getBillingConfigAsync( getBillingConfigParams, (billingResult, billingConfig) -> { if (billingResult.getResponseCode() == BillingResponseCode.OK && billingConfig != null) { String countryCode = billingConfig.getCountryCode(); } else { // TODO: Handle errors } });