ผสานรวม Google Play Billing Library ไว้ในแอปของคุณ

หัวข้อนี้จะอธิบายวิธีผสานรวม Google Play Billing Library ไว้ใน แอปของคุณเพื่อเริ่มขายผลิตภัณฑ์

ตลอดอายุการซื้อ

ขั้นตอนการซื้อโดยทั่วไปสำหรับการซื้อครั้งเดียวหรือการสมัครใช้บริการมีดังนี้

  1. แสดงให้ผู้ใช้เห็นสิ่งที่ซื้อได้
  2. เปิดขั้นตอนการซื้อเพื่อให้ผู้ใช้ยอมรับการซื้อ
  3. ยืนยันการซื้อบนเซิร์ฟเวอร์ของคุณ
  4. ให้เนื้อหาแก่ผู้ใช้
  5. รับทราบการนำส่งเนื้อหา สำหรับผลิตภัณฑ์เพื่อการบริโภค ให้ใช้ เพื่อให้ผู้ใช้ซื้อได้อีกครั้ง

การสมัครใช้บริการจะต่ออายุโดยอัตโนมัติจนกว่าจะมีการยกเลิก การสมัครใช้บริการสามารถทำได้ ผ่านสถานะต่อไปนี้

  • ใช้งานอยู่: ผู้ใช้อยู่ในสถานะดีและมีสิทธิ์เข้าถึงการสมัครใช้บริการ
  • ยกเลิกแล้ว: ผู้ใช้ยกเลิกแล้ว แต่ยังมีสิทธิ์เข้าถึงจนกว่าจะหมดอายุ
  • ในระยะเวลาผ่อนผัน: ผู้ใช้ประสบปัญหาการชําระเงินแต่ยังคงเข้าถึงได้ ขณะที่ Google กำลังลองใช้วิธีการชำระเงินอีกครั้ง
  • ถูกระงับ: ผู้ใช้ประสบปัญหาการชำระเงิน และไม่มีสิทธิ์เข้าถึงอีกต่อไป Google กำลังลองใช้วิธีการชำระเงินอีกครั้ง
  • หยุดชั่วคราว: ผู้ใช้หยุดสิทธิ์เข้าถึงชั่วคราวและจะไม่มีสิทธิ์เข้าถึงจนกว่าผู้ใช้ ให้กลับมาเริ่มอีกครั้ง
  • หมดอายุแล้ว: ผู้ใช้ยกเลิกและสูญเสียสิทธิ์เข้าถึงการสมัครใช้บริการ ถือว่าผู้ใช้เลิกใช้งานเมื่อหมดอายุ

เริ่มต้นการเชื่อมต่อกับ Google Play

ขั้นตอนแรกในการผสานรวมกับระบบการเรียกเก็บเงินของ Google Play คือการเพิ่ม Google Play Billing Library ไปยังแอปของคุณและเริ่มการเชื่อมต่อ

เพิ่มทรัพยากร Dependency ของ Google Play Billing Library

เพิ่มทรัพยากร Dependency ของ 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 หากต้องการรวมรายการเหล่านี้ ส่วนขยายในโปรเจ็กต์ของคุณ ให้เพิ่มทรัพยากร Dependency ต่อไปนี้ในส่วน 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 Listener นี้ได้รับการอัปเดตสำหรับ การซื้อในแอป

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() Callback และตรวจสอบว่า 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() เพื่อขอรายละเอียดไอเทมที่ซื้อในแอป

ในการจัดการผลของการดำเนินการแบบอะซิงโครนัส คุณจะต้องระบุ Listener ซึ่งใช้อินเทอร์เฟซ 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 ข้อเสนอต่อการสมัครใช้บริการ
  • 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 แสดงการสมัครใช้บริการ
            พร้อมจำหน่าย
รูปที่ 1 หน้าจอการซื้อของ Google Play แสดง การสมัครใช้บริการที่ซื้อได้

Google Play โทรหา onPurchasesUpdated() เพื่อแจ้งผลการซื้อ ไปยัง Listener ที่ใช้ PurchasesUpdatedListener ของ Google ระบบจะระบุ Listener โดยใช้เมธอด 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 ที่สำเร็จ
รูปที่ 2 ความสำเร็จในการซื้อของ Google Play

การซื้อที่สำเร็จจะสร้างโทเค็นการซื้อด้วย ซึ่งเป็นโทเค็นที่ไม่ซ้ำ ตัวระบุที่แสดงถึงผู้ใช้และรหัสผลิตภัณฑ์สําหรับไอเทมที่ซื้อในแอป ที่พวกเขาซื้อ แอปของคุณสามารถจัดเก็บโทเค็นการซื้อไว้ในเครื่องได้ แต่เรา ขอแนะนำให้ส่งโทเค็นไปยังเซิร์ฟเวอร์แบ็กเอนด์ที่ปลอดภัย ซึ่งคุณจะ ยืนยันการซื้อและป้องกันการประพฤติมิชอบ กระบวนการนี้มีการอธิบายเพิ่มเติม ในส่วนต่อไปนี้

และผู้ใช้จะได้รับอีเมลใบเสร็จของธุรกรรมที่มีรหัสคำสั่งซื้อ หรือ รหัสธุรกรรมที่ไม่ซ้ำกัน ผู้ใช้จะได้รับอีเมลพร้อมรหัสคำสั่งซื้อที่ไม่ซ้ำกัน สำหรับการซื้อผลิตภัณฑ์แบบครั้งเดียวแต่ละครั้ง และสำหรับการสมัครใช้บริการครั้งแรก การซื้อและการต่ออายุอัตโนมัติตามรอบที่ตามมา คุณสามารถใช้รหัสคำสั่งซื้อ เพื่อจัดการการคืนเงินใน Google Play Console

ระบุราคาสำหรับคุณโดยเฉพาะ

หากสามารถจัดจำหน่ายแอปให้แก่ผู้ใช้ในสหภาพยุโรปได้ ให้ใช้ setIsOfferPersonalized() วิธีในการเปิดเผยให้ผู้ใช้ทราบว่าราคาของสินค้าหนึ่งๆ ที่ปรับให้เหมาะกับแต่ละบุคคลโดยใช้ การตัดสินใจอัตโนมัติ

วันที่ หน้าจอการซื้อใน Google Play ที่ระบุว่ามีการปรับราคาให้เหมาะกับผู้ใช้
รูปที่ 3 หน้าจอการซื้อของ Google Play ระบุว่า ที่มีการตั้งราคาให้เหมาะกับผู้ใช้

คุณต้องปรึกษา Art 6 (1) (ea) CRD ของคำสั่งว่าด้วยสิทธิของผู้บริโภค 2011/83/EU เพื่อพิจารณาว่าราคาที่คุณเสนอแก่ผู้ใช้คือ ที่ปรับเปลี่ยนในแบบของคุณ

setIsOfferPersonalized() รับอินพุตบูลีน เมื่อ true UI ของ Play มีการเปิดเผยข้อมูลด้วย โดย UI จะละเว้นการเปิดเผยข้อมูลเมื่อ false ค่าเริ่มต้น ค่าคือ false

ดูข้อมูลเพิ่มเติมที่ศูนย์ช่วยเหลือผู้บริโภค

กำลังดำเนินการซื้อ

เมื่อผู้ใช้ทำการซื้อเสร็จสมบูรณ์ แอปของคุณจะต้องประมวลผลการซื้อนั้น ในกรณีส่วนใหญ่ แอปของคุณจะได้รับการแจ้งเตือนเกี่ยวกับการซื้อผ่านทาง PurchasesUpdatedListener แต่ก็มีบางกรณีที่แอป ทราบเกี่ยวกับการซื้อด้วยการโทรไปที่ BillingClient.queryPurchasesAsync() ตามที่อธิบายไว้ในการดึงข้อมูลการซื้อ

นอกจากนี้ หากคุณมีไคลเอ็นต์การแจ้งเตือนแบบเรียลไทม์สำหรับนักพัฒนาซอฟต์แวร์ใน แบ็กเอนด์ที่ปลอดภัยแล้ว คุณสามารถลงทะเบียนการซื้อใหม่ได้โดยรับ subscriptionNotification หรือoneTimeProductNotification ซึ่งแจ้งเตือนเกี่ยวกับ การซื้อใหม่ เมื่อได้รับการแจ้งเตือนเหล่านี้แล้ว ให้โทรติดต่อ Google Play API สำหรับนักพัฒนาซอฟต์แวร์ เพื่อรับสถานะที่สมบูรณ์และอัปเดตสถานะแบ็กเอนด์ของคุณเอง

แอปของคุณควรประมวลผลการซื้อในลักษณะต่อไปนี้

  1. ยืนยันการซื้อ
  2. มอบเนื้อหาให้แก่ผู้ใช้และรับทราบการส่งมอบเนื้อหา (ไม่บังคับ) ทำเครื่องหมายรายการว่าใช้แล้วเพื่อให้ผู้ใช้ซื้อไอเทมได้ อีกครั้ง

หากต้องการยืนยันการซื้อ ก่อนอื่นให้ตรวจสอบว่าสถานะการซื้อคือ 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 ด้วย ของ Google ออบเจ็กต์นี้จัดการผลลัพธ์ของการดำเนินการบริโภค คุณสามารถ ลบล้างเมธอด 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 จาก API สำหรับนักพัฒนาแอปของ Google Play เพื่อตอบรับการซื้อจาก แบ็กเอนด์ที่ปลอดภัย ตรวจสอบว่าการซื้อดังกล่าวยังไม่เคยมีการยอมรับโดย กำลังตรวจสอบ acknowledgementState ในแหล่งข้อมูลการซื้อจาก Purchases.subscriptions:get มิฉะนั้น คุณสามารถรับทราบ การสมัครใช้บริการที่ใช้ BillingClient.acknowledgePurchase() จาก Google Play Billing Library หลังจากที่ตรวจสอบ 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

      }
    }
);

การจัดการกับการซื้อที่ดำเนินการนอกแอปของคุณ

การซื้อบางอย่าง เช่น การแลกรับโปรโมชัน อาจเกิดขึ้นได้นอกแอป เมื่อผู้ใช้ทำการซื้อนอกแอป พวกเขาคาดหวังว่าแอปจะแสดง ข้อความในแอป หรือใช้กลไกการแจ้งเตือนบางอย่างเพื่อให้ผู้ใช้ ทำให้ทราบว่าแอปได้รับและประมวลผลการซื้ออย่างถูกต้อง ยอมรับได้บางส่วน ได้แก่

  • แสดงป๊อปอัปในแอป
  • ส่งข้อความไปยังกล่องข้อความในแอป และระบุอย่างชัดเจนว่า เป็นข้อความใหม่ในกล่องข้อความในแอป
  • ใช้ข้อความแจ้งเตือนของระบบปฏิบัติการ

โปรดทราบว่าแอปของคุณอาจอยู่ในสถานะใดก็ได้เมื่อแอป จดจำการซื้อนั้นได้ แม้กระทั่งแอปของคุณอาจ ติดตั้งเมื่อทำการซื้อ ผู้ใช้คาดหวังว่าจะได้รับสิ่งที่ซื้อ เมื่อผู้ใช้กลับมาใช้แอปอีกครั้ง ไม่ว่าแอปจะอยู่ในสถานะใดก็ตาม

คุณต้องตรวจหาการซื้อโดยไม่คํานึงถึงสถานะของแอปเมื่อ ได้ทำการซื้อแล้ว แต่มีข้อยกเว้นบางประการที่สามารถยอมรับได้ ไม่แจ้งให้ผู้ใช้ทราบทันทีว่าได้รับสินค้าแล้ว เช่น

  • ระหว่างการดำเนินการในเกม ซึ่งการแสดงข้อความอาจทำให้ ผู้ใช้ ในกรณีนี้ คุณต้องแจ้งให้ผู้ใช้ทราบหลังสิ้นสุดส่วนการดำเนินการ
  • ระหว่างที่ใช้คัตซีน ซึ่งการแสดงข้อความอาจเบี่ยงเบนความสนใจของผู้ใช้ ด้วยวิธีนี้ คุณต้องแจ้งให้ผู้ใช้ทราบหลังจากที่คัตซีนสิ้นสุดลง
  • ระหว่างบทแนะนำเริ่มต้นและส่วนต่างๆ ที่ผู้ใช้ตั้งค่าในเกม คำแนะนำจากเรา คุณแจ้งให้ผู้ใช้ใหม่ทราบเกี่ยวกับรางวัลทันทีหลังจากที่เปิดเกม หรือ ระหว่างการตั้งค่าผู้ใช้ครั้งแรก อย่างไรก็ตาม คุณสามารถรอจนกว่า ลำดับเกมพร้อมให้แจ้งเตือนผู้ใช้

คำนึงถึงผู้ใช้เสมอเมื่อตัดสินใจว่าจะแจ้งให้ผู้ใช้ทราบเมื่อใดและอย่างไร การซื้อที่ดำเนินการนอกแอปของคุณ เมื่อใดก็ตามที่ผู้ใช้ไม่ได้รับ การแจ้งเตือน ผู้ใช้อาจสับสน และอาจหยุดใช้แอปของคุณ ติดต่อผู้ใช้ หรือบ่นเกี่ยวกับเรื่องนี้บนโซเชียลมีเดีย หมายเหตุ: PurchasesUpdatedListener ลงทะเบียนกับใบสมัครของคุณแล้ว บริบทในการจัดการการอัปเดตการซื้อ รวมถึงการซื้อที่เริ่มต้นภายนอก ของแอปของคุณ ซึ่งหมายความว่าหากไม่มีขั้นตอนการสมัคร PurchasesUpdatedListener จะไม่ได้รับการแจ้งเตือน แอปของคุณจึงควร เรียก BillingClient.queryPurchasesAsync() ในเมธอด onResume() เป็น ที่ระบุไว้ในดึงข้อมูลการซื้อ

การจัดการธุรกรรมที่รอดำเนินการ

Google Play รองรับธุรกรรมที่รอดำเนินการหรือธุรกรรมที่ต้องมีธุรกรรมที่ต้องมีหรือ ขั้นตอนเพิ่มเติมระหว่างเวลาที่ผู้ใช้เริ่มซื้อและเมื่อ วิธีการชำระเงินสำหรับการซื้อได้รับการประมวลผลแล้ว แอปของคุณไม่ควรให้สิทธิ์ ได้รับสิทธิ์ในการซื้อประเภทเหล่านี้จนกว่า 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 รายการ เหตุการณ์นี้อาจเกิดขึ้นได้หาก ลูกค้าไม่ชำระเงินให้เสร็จสมบูรณ์ภายในระยะเวลาที่กำหนด โปรดทราบว่า สามารถใช้ API สำหรับนักพัฒนาซอฟต์แวร์ Google Play เพื่อตรวจสอบสถานะปัจจุบันของ การซื้อ

การจัดการกับการซื้อแบบหลายจำนวน

รองรับใน Google Play Billing Library เวอร์ชัน 4.0 ขึ้นไป Google Play ช่วยให้ลูกค้าสามารถซื้อของในแอปเดียวกันได้มากกว่า 1 รายการ ผลิตภัณฑ์ในธุรกรรมเดียวโดยระบุจำนวนจากรถเข็นที่ซื้อ บัญชี จะต้องรองรับการซื้อแบบหลายจำนวนและให้สิทธิ์ สำหรับจำนวนการซื้อที่ระบุ

หากต้องการใช้การซื้อแบบหลายจำนวน ตรรกะการจัดสรรของแอปจะต้องตรวจสอบ สำหรับจำนวนสินค้า คุณสามารถเข้าถึงช่อง quantity ได้จาก 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
        }
      }
    });