راهنمایی‌های یکپارچه‌سازی درون‌برنامه برای انتخاب صورت‌حساب

این راهنما نحوه ادغام برنامه با «میاناهای برنامه‌سازی کاربردی کتابخانه خدمات صورت‌حساب Play» را شرح می‌دهد تا بتوانید به کاربران خود انتخاب صورت‌حساب ارائه دهید.

یکپارچه‌سازی با PBL

می‌توانید انتخاب صورت‌حساب را در چهار سناریو با PBL ادغام کنید. سناریوها براساس اینکه چه کسی صفحه انتخاب را ارائه می‌دهد و پرداخت کجا انجام می‌شود متفاوت است. جدول زیر سناریوهای ادغام را شرح می‌دهد:

کدام صفحه انتخاب صورت‌حساب را می‌خواهید پرداز کنید؟
‫Google Play خودتان (مطابق با دستورالعمل‌های تجربه کاربری)
پرداخت کجا انجام می‌شود؟ درون‌برنامه سناریو 1A

Google صفحه انتخاب را پردازش می‌کند و صورت‌حساب جایگزین در برنامه شما مدیریت می‌شود.

سناریو 1B

توسعه‌دهنده برنامه صفحه انتخاب را پردازش می‌کند و صورت‌حساب جایگزین در برنامه شما مدیریت می‌شود.

پیوند وب خارجی سناریو 2A

‫Google صفحه انتخاب را پرداز می‌کند و کاربر برای خرید به وب‌سایت‌های خودتان در خارج از برنامه پیوند داده می‌شود.

سناریو ۲-ب

توسعه‌دهنده برنامه صفحه انتخاب را پرداز می‌کند و کاربر برای خرید به وب‌سایت‌های خودتان در خارج از برنامه پیوند داده می‌شود.

تصویر زیر جریان انتخاب صورت‌حساب را برای هریک از این سناریوها توضیح می‌دهد:

جریان انتخاب صورت‌حساب که توالی فراخوانی‌های API و تعاملات کاربر را برای چهار سناریو ادغام نشان می‌دهد.
شکل ۱. سناریوهای ادغام انتخاب صورت‌حساب

جریان انتخاب صورت‌حساب که توالی فراخوانی‌های API و تعاملات کاربر را برای چهار سناریو ادغام نشان می‌دهد.

سناریوهای یکپارچه‌سازی PBL

بسته به سناریو یکپارچه‌سازی، مراحل این بخش را برای پیاده‌سازی انتخاب صورت‌حساب در برنامه‌تان دنبال کنید.

مدیریت سناریو 1A

Google صفحه انتخاب را پردازش می‌کند و صورت‌حساب جایگزین در برنامه شما مدیریت می‌شود برای فعال کردن انتخاب صورت‌حساب در این سناریو، مراحل زیر را انجام دهید:

  1. هنگام ساختن نمونه BillingClient، با EnableBillingProgramParams با enableBillingProgram تماس بگیرید، و سپس اتصال را شروع کنید. برای مثال:

    کاتلین

    // Build the parameters to enable the Billing Choice program and assign the listener
    // to handle user selection of the developer-provided billing option.
    val enableBillingProgramParams = EnableBillingProgramParams.newBuilder()
        .setBillingProgram(BillingProgram.BILLING_CHOICE)
        .setDeveloperProvidedBillingListener(developerProvidedBillingListener)
        .build()
    
    // Build the parameters to enable support for pending purchases.
    val pendingPurchasesParams = PendingPurchasesParams.newBuilder()
        .enableOneTimeProducts()
        .build()
    
    // Construct the BillingClient instance with the purchases updated listener,
    // pending purchases support, and the billing choice params.
    val billingClient = BillingClient.newBuilder(context)
        .setListener(purchasesUpdatedListener)
        .enablePendingPurchases(pendingPurchasesParams)
        .enableBillingProgram(enableBillingProgramParams)
        .build()
    
    // Establish a connection to Google Play
    val billingResult = suspendCancellableCoroutine<BillingResult> { continuation ->
        billingClient.startConnection(object : BillingClientStateListener {
            // Called when the connection setup process completes.
            override fun onBillingSetupFinished(billingResult: BillingResult) {
                // Resume the coroutine and pass back the BillingResult to the caller.
                if (continuation.isActive) {
                    continuation.resume(billingResult)
                }
            }
    
            // Called if the connection to the Play Store service is dropped.
            // This prevents the await or suspension point from hanging indefinitely.
            override fun onBillingServiceDisconnected() {
                if (continuation.isActive) {
                    continuation.resume(
                        BillingResult.newBuilder()
                            .setResponseCode(BillingResponseCode.SERVICE_DISCONNECTED)
                            .setDebugMessage("Billing service disconnected during connection setup")
                            .build()
                    )
                }
            }
        })
    }

    جاوا

    
    EnableBillingProgramParams params = EnableBillingProgramParams.newBuilder()
            .setBillingProgram(BillingProgram.BILLING_CHOICE)
            .setDeveloperProvidedBillingListener(developerProvidedBillingListener)
            .build();
    
    BillingClient billingClient = BillingClient.newBuilder(context)
            .setListener(purchasesUpdatedListener)
            .enablePendingPurchases(
                    PendingPurchasesParams.newBuilder()
                            .enableOneTimeProducts()
                            .build()
            )
            .enableBillingProgram(params)
            .build();
    
    
  2. تأیید کنید که انتخاب صورت‌حساب پردازش‌شده توسط Google برای کاربر دردسترس است.

    برای بررسی دردسترس بودن برنامه، با isBillingProgramAvailableAsync تماس بگیرید، و سپس برای نمایش محصولات دردسترس، با queryProductDetailsAsync تماس بگیرید. برای مثال:

    کاتلین

    val (billingResult, billingProgramAvailabilityDetails) = billingClient.isBillingProgramAvailable(BillingProgram.BILLING_CHOICE)
    
    if (billingResult.responseCode == BillingResponseCode.OK) {
        val billingChoiceAvailabilityDetails = billingProgramAvailabilityDetails.billingChoiceAvailabilityDetails
        if (billingChoiceAvailabilityDetails != null &&
            billingChoiceAvailabilityDetails.choiceScreenType == ChoiceScreenType.GOOGLE_RENDERED
        ) {
            // Billing choice is available. Query products and proceed.
        } else {
            // Fallback to other available programs.
        }
    } else {
        // Fallback to other available programs.
    }

    جاوا

    
    // ...
    billingClient.isBillingProgramAvailableAsync(
        BillingProgram.BILLING_CHOICE,
        (billingResult, billingProgramAvailabilityDetails) -> {
            if (billingResult.getResponseCode() == BillingResponseCode.OK) {
                BillingChoiceAvailabilityDetails billingChoiceAvailabilityDetails =
                    billingProgramAvailabilityDetails.getBillingChoiceAvailabilityDetails();
    
                if (billingChoiceAvailabilityDetails != null &&
                    billingChoiceAvailabilityDetails.getChoiceScreenType() == ChoiceScreenType.GOOGLE_RENDERED) {
                    // Billing choice is available. Query products and proceed.
                } else {
                    // Fallback to other available programs.
                }
            } else {
                // Fallback to other available programs.
            }
        }
    );
    
    

    توجه: billingProgramAvailabilityDetails به شما می‌گوید که صفحه انتخاب صورت‌حساب پردازش‌شده توسط Google یا صفحه انتخاب صورت‌حساب پردازش‌شده توسط «توسعه‌دهنده» دردسترس است یا نه.

  3. برای راه‌اندازی جریان خرید وقتی کاربر روی «خرید» کلیک می‌کند، launchBillingFlow را فراخوانی کنید. اگر انتخاب صورت‌حساب دردسترس است، DeveloperBillingOptionParams را به BillingFlowParams ارسال کنید. برای مثال:

    کاتلین

    val developerBillingOptionParams = DeveloperBillingOptionParams.newBuilder()
        .setBillingProgram(BillingProgram.BILLING_CHOICE)
        .build()
    
    val billingFlowParams = BillingFlowParams.newBuilder()
        .setProductDetailsParamsList(productDetailsParamsList)
        .enableDeveloperBillingOption(developerBillingOptionParams)
        .build()
    
    val billingResult = billingClient.launchBillingFlow(activity, billingFlowParams)

    جاوا

    
    DeveloperBillingOptionParams developerBillingOptionParams =
        DeveloperBillingOptionParams.newBuilder()
            .setBillingProgram(BillingProgram.BILLING_CHOICE)
            .build();
    BillingFlowParams billingFlowParams =
        BillingFlowParams.newBuilder()
            .setProductDetailsParamsList(productDetailsParamsList)
            .enableDeveloperBillingOption(developerBillingOptionParams)
            .build();
    
    BillingResult billingResult = billingClient.launchBillingFlow(activity, billingFlowParams);
    
    

    توجه: کنترل والدین برای کاربران تحت نظارت نمایش داده می‌شود.

  4. انتخاب نوع صورت‌حساب توسط کاربر را به این صورت مدیریت کنید:

    • اگر کاربر «خدمات صورت‌حساب Play» را انتخاب کند، نتیجه صورت‌حساب به PurchasesUpdatedListener ثبت‌شده در مرحله ۱ برگردانده می‌شود.
    • اگر کاربر صورت‌حساب جایگزین شما را انتخاب کند، نتیجه صورت‌حساب به DeveloperProvidedBillingListener ثبت‌شده در مرحله ۱ برگردانده می‌شود. DeveloperProvidedBillingDetails برگشتی در این مورد شامل externalTransactionToken است. از این کد برای گزارش تراکنش استفاده خواهد شد.

مدیریت سناریو 1B

توسعه‌دهنده صفحه انتخاب را ارائه می‌کند و صورت‌حساب جایگزین در درون برنامه شما مدیریت می‌شود. برای فعال کردن انتخاب صورت‌حساب در این سناریو، مراحل زیر را انجام دهید:

  1. بدون DeveloperProvidedBillingListener در EnableBillingProgramParams، enableBillingProgram را هنگام ساختن نمونه BillingClient فراخوانی کنید، و سپس اتصال را شروع کنید. برای مثال:

    کاتلین

    // Build the parameters to enable the Billing Choice program.
    val enableBillingProgramParams = EnableBillingProgramParams.newBuilder()
        .setBillingProgram(BillingProgram.BILLING_CHOICE)
        .build()
    
    // Build the parameters to enable support for pending purchases.
    val pendingPurchasesParams = PendingPurchasesParams.newBuilder()
        .enableOneTimeProducts()
        .build()
    
    // Construct the BillingClient instance with the purchases updated listener,
    // pending purchases support, and the billing choice params.
    val billingClient = BillingClient.newBuilder(context)
        .setListener(purchasesUpdatedListener)
        .enablePendingPurchases(pendingPurchasesParams)
        .enableBillingProgram(enableBillingProgramParams)
        .build()
    
    // Establish a connection to Google Play
    val billingResult = suspendCancellableCoroutine<BillingResult> { continuation ->
        billingClient.startConnection(object : BillingClientStateListener {
            // Called when the connection setup process completes.
            override fun onBillingSetupFinished(billingResult: BillingResult) {
                // Resume the coroutine and pass back the BillingResult to the caller.
                if (continuation.isActive) {
                    continuation.resume(billingResult)
                }
            }
    
            // Called if the connection to the Play Store service is dropped.
            // This prevents the await or suspension point from hanging indefinitely.
            override fun onBillingServiceDisconnected() {
                if (continuation.isActive) {
                    continuation.resume(
                        BillingResult.newBuilder()
                            .setResponseCode(BillingResponseCode.SERVICE_DISCONNECTED)
                            .setDebugMessage("Billing service disconnected during connection setup")
                            .build()
                    )
                }
            }
        })
    }

    جاوا

    
    EnableBillingProgramParams params = EnableBillingProgramParams.newBuilder()
            .setBillingProgram(BillingProgram.BILLING_CHOICE)
            .build();
    
    BillingClient billingClient = BillingClient.newBuilder(context)
            .setListener(purchasesUpdatedListener)
            .enablePendingPurchases()
            .enableBillingProgram(params)
            .build();
    
    
  2. تأیید کنید که انتخاب صورت‌حساب پردازش‌شده توسط توسعه‌دهنده برای کاربر دردسترس است.

    برای بررسی دردسترس بودن برنامه، با isBillingProgramAvailableAsync تماس بگیرید، و سپس برای نمایش محصولات دردسترس، با queryProductDetailsAsync تماس بگیرید. برای مثال:

    کاتلین

    val (billingResult, billingProgramAvailabilityDetails) =
        billingClient.isBillingProgramAvailable(BillingProgram.BILLING_CHOICE)
    
    if (billingResult.responseCode == BillingResponseCode.OK) {
        val billingChoiceAvailabilityDetails =
            billingProgramAvailabilityDetails.billingChoiceAvailabilityDetails
    
        if (billingChoiceAvailabilityDetails != null &&
            billingChoiceAvailabilityDetails.choiceScreenType == ChoiceScreenType.DEVELOPER_RENDERED
        ) {
            // Billing choice is available. Query products and proceed.
            // You can inspect details such as:
            // - billingChoiceAvailabilityDetails.choiceScreenType
            // - billingChoiceAvailabilityDetails.isExternalLinkAvailable
        } else {
            // Fallback to other available programs.
        }
    } else {
        // Fallback to other available programs.
    }

    جاوا

    
    // ...
    billingClient.isBillingProgramAvailableAsync(
        BillingProgram.BILLING_CHOICE,
        (billingResult, billingProgramAvailabilityDetails) -> {
            if (billingResult.getResponseCode() == BillingResponseCode.OK) {
                BillingChoiceAvailabilityDetails billingChoiceAvailabilityDetails =
                    billingProgramAvailabilityDetails.getBillingChoiceAvailabilityDetails();
    
                if (billingChoiceAvailabilityDetails != null
                        && billingChoiceAvailabilityDetails.getChoiceScreenType() == ChoiceScreenType.DEVELOPER_RENDERED) {
                    // Billing choice is available. Query products and proceed.
                    // You can inspect details such as:
                    // - billingChoiceAvailabilityDetails.getChoiceScreenType()
                    // - billingChoiceAvailabilityDetails.isExternalLinkAvailable()
                } else {
                    // Fallback to other available programs.
                }
            } else {
                // Fallback to other available programs.
            }
        }
    );
    
    

    توجه: billingProgramAvailabilityDetails به شما می‌گوید که صفحه انتخاب صورت‌حساب پردازش‌شده توسط Google یا صفحه انتخاب صورت‌حساب پردازش‌شده توسط «توسعه‌دهنده» دردسترس است یا نه.

  3. برای دریافت برنمای «خدمات صورت‌حساب Play» و اطلاعات وفاداری، روش getBillingChoiceInfoAsync را فراخوانی کنید. برای مثال:

    کاتلین

    // 1. Create the params required for the request
    val params = GetBillingChoiceInfoParams.newBuilder()
        .setBillingProgram(BillingProgram.BILLING_CHOICE)
        .setPlayBillingChoiceImageLayout(GetBillingChoiceInfoParams.ImageLayout.RECTANGULAR_FOUR_BY_ONE)
        .build()
    
    // 2. Call the suspend method on your billingClient instance
    val (billingResult, playBillingChoiceInfo) = billingClient.getBillingChoiceInfo(params)
    
    if (billingResult.responseCode == BillingResponseCode.OK && playBillingChoiceInfo != null) {
        // Access the URL of the image associated with the Play Billing Choice
        val imageUrl = playBillingChoiceInfo.playBillingChoiceImageUrl
    
        // Access the Play Loyalty string information, if available
        val loyaltyInfo = playBillingChoiceInfo.playBillingLoyaltyInfo
    
        // Populate your developer-rendered UI elements
        playBillingLoyaltyTextView.text = loyaltyInfo
        loadImage(imageUrl, playBillingImageView)
    } else {
        // Handle error scenarios
    }

    جاوا

    
    // 1. Create the params required for the request
    GetBillingChoiceInfoParams params = GetBillingChoiceInfoParams.newBuilder()
        .setBillingProgram(BillingClient.BillingProgram.BILLING_CHOICE)
        .setPlayBillingChoiceImageLayout(GetBillingChoiceInfoParams.ImageLayout.RECTANGULAR_FOUR_BY_ONE)
        .build();
    // 2. Call the method asynchronously on your billingClient instance
    billingClient.getBillingChoiceInfoAsync(params, (billingResult, playBillingChoiceInfo) -> {
        if (billingResult.getResponseCode() == BillingResponseCode.OK && playBillingChoiceInfo != null) {
          // Access the URL of the image associated with the Play Billing Choice
            String imageUrl = playBillingChoiceInfo.getPlayBillingChoiceImageUrl();
            // Access the Play Loyalty string information, if available
            String loyaltyInfo = playBillingChoiceInfo.getPlayBillingLoyaltyInfo();
    
            // Populate your developer-rendered UI elements
            playBillingLoyaltyTextView.setText(loyaltyInfo);
              loadImage(imageUrl, playBillingImageView);
          } else {
              // Handle error scenarios
          }
    });
    
    
  4. یک کد تراکنش خارجی با DeveloperBillingType تنظیم‌شده روی IN_APP ایجاد کنید. برای مثال:

    کاتلین

    // Build the parameters specifying the billing program and that the billing type is IN_APP.
    val params = BillingProgramReportingDetailsParams.newBuilder()
        .setBillingProgram(BillingProgram.BILLING_CHOICE)
        .setDeveloperBillingType(DeveloperBillingType.IN_APP)
        .build()
    
    // Call the suspending extension function to request the reporting details
    val (billingResult, billingProgramReportingDetails) =
        billingClient.createBillingProgramReportingDetails(params)
    
    if (billingResult.responseCode != BillingResponseCode.OK) {
        // Handle failures such as retrying due to network errors.
        return
    }
    
    // Extract the transaction token from the returned reporting details
    val transactionToken = billingProgramReportingDetails?.externalTransactionToken
    
    // Persist the external transaction token locally. Pass it to
    // DeveloperBillingOptionParams when launchBillingFlow is called.
    // It can also be used as part of your external website

    جاوا

    
    BillingProgramReportingDetailsParams params =
        BillingProgramReportingDetailsParams.newBuilder()
            .setBillingProgram(BillingProgram.BILLING_CHOICE)
            .setDeveloperBillingType(DeveloperBillingType.IN_APP)
            .build();
    
    billingClient.createBillingProgramReportingDetailsAsync(
        params,
        new BillingProgramReportingDetailsListener() {
            @Override
            public void onCreateBillingProgramReportingDetailsResponse(
                BillingResult billingResult,
                @Nullable BillingProgramReportingDetails billingProgramReportingDetails
            ) {
                if (billingResult.getResponseCode() != BillingResponseCode.OK) {
                    // Handle failures such as retrying due to network errors.
                    return;
                }
    
                String transactionToken =
                    billingProgramReportingDetails.getExternalTransactionToken();
    
                // Persist the external transaction token locally. Pass it to
                // DeveloperBillingOptionParams when launchBillingFlow is called.
                // It can also be used as part of your external website
            }
        }
    );
    
    
    
  5. وقتی کاربر روی «خرید» کلیک می‌کند، با showBillingProgramInformationDialog تماس بگیرید تا کادر گفتگوی اطلاعات نشان دهید. برای مثال، کادر گفتگوی اطلاعات برای کاربران را ببینید. BillingProgram و transactionToken از مرحله ۴ باید در درخواست تنظیم شود.

    توجه: کنترل والدین برای کاربران تحت نظارت نمایش داده می‌شود.

  6. اگر نتیجه مرحله قبلی OK است، صفحه انتخاب صورت‌حساب جایگزین را راه‌اندازی کنید.

  7. انتخاب نوع صورت‌حساب توسط کاربر را به این صورت مدیریت کنید:

    • اگر کاربر «خدمات صورت‌حساب Play» را انتخاب کرد، launchBillingFlow را طبق رهنمودهای استاندارد «خدمات صورت‌حساب Play» فراخوانی کنید. نتیجه صورت‌حساب به PurchasesUpdatedListener ثبت‌شده در مرحله ۱ برگردانده می‌شود.
    • اگر کاربر صورت‌حساب جایگزین شما را انتخاب کند، باید تراکنش را خودتان انجام دهید و آن را بااستفاده از کد شناسایی تولیدشده در مرحله ۴ به Play گزارش کنید.

مدیریت سناریو 2A

Google صفحه انتخاب را پردازش می‌کند و صورت‌حساب جایگزین در خارج برنامه شما مدیریت می‌شود. برای فعال کردن انتخاب صورت‌حساب در این سناریو، مراحل زیر را انجام دهید:

  1. هنگام ساختن نمونه BillingClient، با EnableBillingProgramParams با enableBillingProgram تماس بگیرید، و سپس اتصال را شروع کنید. برای مثال:

    کاتلین

    // Build the parameters to enable the Billing Choice program and assign the listener
    // to handle user selection of the developer-provided billing option.
    val enableBillingProgramParams = EnableBillingProgramParams.newBuilder()
        .setBillingProgram(BillingProgram.BILLING_CHOICE)
        .setDeveloperProvidedBillingListener(developerProvidedBillingListener)
        .build()
    
    // Build the parameters to enable support for pending purchases.
    val pendingPurchasesParams = PendingPurchasesParams.newBuilder()
        .enableOneTimeProducts()
        .build()
    
    // Construct the BillingClient instance with the purchases updated listener,
    // pending purchases support, and the billing choice params.
    val billingClient = BillingClient.newBuilder(context)
        .setListener(purchasesUpdatedListener)
        .enablePendingPurchases(pendingPurchasesParams)
        .enableBillingProgram(enableBillingProgramParams)
        .build()
    
    // Establish a connection to Google Play
    val billingResult = suspendCancellableCoroutine<BillingResult> { continuation ->
        billingClient.startConnection(object : BillingClientStateListener {
            // Called when the connection setup process completes.
            override fun onBillingSetupFinished(billingResult: BillingResult) {
                // Resume the coroutine and pass back the BillingResult to the caller.
                if (continuation.isActive) {
                    continuation.resume(billingResult)
                }
            }
    
            // Called if the connection to the Play Store service is dropped.
            // This prevents the await or suspension point from hanging indefinitely.
            override fun onBillingServiceDisconnected() {
                if (continuation.isActive) {
                    continuation.resume(
                        BillingResult.newBuilder()
                            .setResponseCode(BillingResponseCode.SERVICE_DISCONNECTED)
                            .setDebugMessage("Billing service disconnected during connection setup")
                            .build()
                    )
                }
            }
        })
    }

    جاوا

    
    EnableBillingProgramParams params = EnableBillingProgramParams.newBuilder()
            .setBillingProgram(BillingProgram.BILLING_CHOICE)
            .setDeveloperProvidedBillingListener(developerProvidedBillingListener)
            .build();
    
    BillingClient billingClient = BillingClient.newBuilder(context)
            .setListener(purchasesUpdatedListener)
            .enablePendingPurchases(
                    PendingPurchasesParams.newBuilder()
                            .enableOneTimeProducts()
                            .build()
            )
            .enableBillingProgram(params)
            .build();
    
    
  2. دردسترس بودن موارد زیر را درستی‌سنجی کنید:

    • انتخاب روش صدور صورت‌حساب ارائه‌شده توسط Google
    • پیوند وب خارجی

    برای بررسی دردسترس بودن برنامه، با isBillingProgramAvailableAsync تماس بگیرید، و سپس برای نمایش محصولات دردسترس، با queryProductDetailsAsync تماس بگیرید. برای مثال:

    کاتلین

    جاوا

    
    // ...
    billingClient.isBillingProgramAvailableAsync(
        BillingProgram.BILLING_CHOICE,
        (billingResult, billingProgramAvailabilityDetails) -> {
            if (billingResult.getResponseCode() == BillingResponseCode.OK) {
                BillingChoiceAvailabilityDetails billingChoiceAvailabilityDetails =
                    billingProgramAvailabilityDetails.getBillingChoiceAvailabilityDetails();
    
                if (billingChoiceAvailabilityDetails != null
                        && billingChoiceAvailabilityDetails.getChoiceScreenType() == ChoiceScreenType.GOOGLE_RENDERED
                        && billingChoiceAvailabilityDetails.isExternalLinkAvailable()) {
                    // Billing choice is available and external transaction links are supported.
                    // Query products and proceed.
                } else {
                    // Fallback to other available programs.
                }
            } else {
                // Fallback to other available programs.
            }
        }
    );
    
    
    
  3. وقتی کاربر قصد خرید را نشان می‌دهد، با createBillingProgramReportingDetailsAsync تماس بگیرید تا رمز تراکنش خارجی ایجاد کنید. برای مثال:

    کاتلین

    جاوا

    
    BillingProgramReportingDetailsParams params =
        BillingProgramReportingDetailsParams.newBuilder()
            .setBillingProgram(BillingProgram.BILLING_CHOICE)
            .setDeveloperBillingType(DeveloperBillingType.EXTERNAL_LINK)
            .build();
    
    billingClient.createBillingProgramReportingDetailsAsync(
        params,
        new BillingProgramReportingDetailsListener() {
            @Override
            public void onCreateBillingProgramReportingDetailsResponse(
                BillingResult billingResult,
                @Nullable BillingProgramReportingDetails billingProgramReportingDetails
            ) {
                if (billingResult.getResponseCode() != BillingResponseCode.OK) {
                    // Handle failures such as retrying due to network errors.
                    return;
                }
    
                String transactionToken =
                    billingProgramReportingDetails.getExternalTransactionToken();
    
                // Persist the external transaction token locally. Pass it to
                // DeveloperBillingOptionParams when launchBillingFlow is called.
                // It can also be used as part of your external website.
            }
        }
    );
    
    
  4. برای راه‌اندازی جریان خرید وقتی کاربر روی «خرید» کلیک می‌کند، launchBillingFlow را فراخوانی کنید. اگر انتخاب صورت‌حساب برای کاربر دردسترس است، موارد زیر را انجام دهید:

    1. از DeveloperBillingOptionParams به BillingFlowParams بروید.
    2. رمز تراکنش خارجی را از مرحله ۳ به DeveloperBillingOptionParams ارسال کنید.

    برای مثال:

    کاتلین

    جاوا

    
    DeveloperBillingOptionParams developerBillingOptionParams =
        DeveloperBillingOptionParams.newBuilder()
            .setBillingProgram(BillingProgram.BILLING_CHOICE)
            .setLinkUri(Uri.parse("https://www.example.com/external/purchase"))
            .setExternalTransactionToken(transactionToken)
            .setLaunchMode(
              DeveloperBillingOptionParams.LaunchMode.LAUNCH_IN_EXTERNAL_BROWSER_OR_APP)
            .build();
    
    

    توجه: کنترل والدین برای کاربران تحت نظارت نمایش داده می‌شود.

  5. انتخاب نوع صورت‌حساب توسط کاربر را به این صورت مدیریت کنید:

پرداختن به سناریو 2B

توسعه‌دهنده صفحه انتخاب را ارائه می‌کند و صورت‌حساب جایگزین در خارج برنامه مدیریت می‌شود. برای فعال کردن انتخاب صورت‌حساب در این سناریو، مراحل زیر را انجام دهید:

  1. تماس با enableBillingProgram بدون DeveloperProvidedBillingListener در EnableBillingProgramParams هنگام ساختن نمونه BillingClient ، و سپس اتصال را شروع کنید. برای مثال:

    کاتلین

    // Build the parameters to enable the Billing Choice program.
    val enableBillingProgramParams = EnableBillingProgramParams.newBuilder()
        .setBillingProgram(BillingProgram.BILLING_CHOICE)
        .build()
    
    // Build the parameters to enable support for pending purchases.
    val pendingPurchasesParams = PendingPurchasesParams.newBuilder()
        .enableOneTimeProducts()
        .build()
    
    // Construct the BillingClient instance with the purchases updated listener,
    // pending purchases support, and the billing choice params.
    val billingClient = BillingClient.newBuilder(context)
        .setListener(purchasesUpdatedListener)
        .enablePendingPurchases(pendingPurchasesParams)
        .enableBillingProgram(enableBillingProgramParams)
        .build()
    
    // Establish a connection to Google Play
    val billingResult = suspendCancellableCoroutine<BillingResult> { continuation ->
        billingClient.startConnection(object : BillingClientStateListener {
            // Called when the connection setup process completes.
            override fun onBillingSetupFinished(billingResult: BillingResult) {
                // Resume the coroutine and pass back the BillingResult to the caller.
                if (continuation.isActive) {
                    continuation.resume(billingResult)
                }
            }
    
            // Called if the connection to the Play Store service is dropped.
            // This prevents the await or suspension point from hanging indefinitely.
            override fun onBillingServiceDisconnected() {
                if (continuation.isActive) {
                    continuation.resume(
                        BillingResult.newBuilder()
                            .setResponseCode(BillingResponseCode.SERVICE_DISCONNECTED)
                            .setDebugMessage("Billing service disconnected during connection setup")
                            .build()
                    )
                }
            }
        })
    }

    جاوا

    
    EnableBillingProgramParams params = EnableBillingProgramParams.newBuilder()
            .setBillingProgram(BillingProgram.BILLING_CHOICE)
            .build();
    
    BillingClient billingClient = BillingClient.newBuilder(context)
            .setListener(purchasesUpdatedListener)
            .enablePendingPurchases()
            .enableBillingProgram(params)
            .build();
    
    
  2. دردسترس بودن موارد زیر را درستی‌سنجی کنید:

    • انتخاب روش صدور صورت‌حساب ارائه‌شده توسط Google
    • پیوند وب خارجی

    برای بررسی دردسترس بودن برنامه، با isBillingProgramAvailableAsync تماس بگیرید، و سپس برای نمایش محصولات دردسترس، با queryProductDetailsAsync تماس بگیرید. برای مثال:

    کاتلین

    جاوا

    
    // ...
    
    billingClient.isBillingProgramAvailableAsync(
        BillingProgram.BILLING_CHOICE,
        (billingResult, billingProgramAvailabilityDetails) -> {
            if (billingResult.getResponseCode() == BillingResponseCode.OK) {
                BillingChoiceAvailabilityDetails billingChoiceAvailabilityDetails =
                    billingProgramAvailabilityDetails.getBillingChoiceAvailabilityDetails();
                if (billingChoiceAvailabilityDetails != null &&
                    billingChoiceAvailabilityDetails.getChoiceScreenType() == ChoiceScreenType.DEVELOPER_RENDERED &&
                    billingChoiceAvailabilityDetails.isExternalLinkAvailable()) {
                    // Billing choice is available and external transaction links are supported. Query products and proceed.
                } else {
                    // Fallback to other available programs.
                }
            } else {
                // Fallback to other available programs.
            }
        }
    );
    
    
  3. برای دریافت برنمای «خدمات صورت‌حساب Play» و اطلاعات وفاداری، روش getBillingChoiceInfoAsync را فراخوانی کنید.

    کاتلین

    // 1. Create the params required for the request
    val params = GetBillingChoiceInfoParams.newBuilder()
        .setBillingProgram(BillingProgram.BILLING_CHOICE)
        .setPlayBillingChoiceImageLayout(GetBillingChoiceInfoParams.ImageLayout.RECTANGULAR_FOUR_BY_ONE)
        .build()
    
    // 2. Call the suspend method on your billingClient instance
    val (billingResult, playBillingChoiceInfo) = billingClient.getBillingChoiceInfo(params)
    
    if (billingResult.responseCode == BillingResponseCode.OK && playBillingChoiceInfo != null) {
        // Access the URL of the image associated with the Play Billing Choice
        val imageUrl = playBillingChoiceInfo.playBillingChoiceImageUrl
    
        // Access the Play Loyalty string information, if available
        val loyaltyInfo = playBillingChoiceInfo.playBillingLoyaltyInfo
    
        // Populate your developer-rendered UI elements
        playBillingLoyaltyTextView.text = loyaltyInfo
        loadImage(imageUrl, playBillingImageView)
    } else {
        // Handle error scenarios
    }

    جاوا

    
    // 1. Create the params required for the request
    GetBillingChoiceInfoParams params = GetBillingChoiceInfoParams.newBuilder()
        .setBillingProgram(BillingClient.BillingProgram.BILLING_CHOICE)
        .setPlayBillingChoiceImageLayout(GetBillingChoiceInfoParams.ImageLayout.RECTANGULAR_FOUR_BY_ONE)
        .build();
    // 2. Call the method asynchronously on your billingClient instance
    billingClient.getBillingChoiceInfoAsync(params, (billingResult, playBillingChoiceInfo) -> {
        if (billingResult.getResponseCode() == BillingResponseCode.OK && playBillingChoiceInfo != null) {
          // Access the URL of the image associated with the Play Billing Choice
            String imageUrl = playBillingChoiceInfo.getPlayBillingChoiceImageUrl();
            // Access the Play Loyalty string information, if available
            String loyaltyInfo = playBillingChoiceInfo.getPlayBillingLoyaltyInfo();
    
            // Populate your developer-rendered UI elements
            playBillingLoyaltyTextView.setText(loyaltyInfo);
              loadImage(imageUrl, playBillingImageView);
          } else {
              // Handle error scenarios
          }
    });
    
    
  4. وقتی کاربر قصد خرید را نشان می‌دهد، با createBillingProgramReportingDetailsAsync تماس بگیرید تا رمز تراکنش خارجی ایجاد کنید. برای مثال:

    کاتلین

    جاوا

    
    BillingProgramReportingDetailsParams params =
        BillingProgramReportingDetailsParams.newBuilder()
            .setBillingProgram(BillingProgram.BILLING_CHOICE)
            .setDeveloperBillingType(DeveloperBillingType.EXTERNAL_LINK)
            .build();
    
    billingClient.createBillingProgramReportingDetailsAsync(
        params,
        new BillingProgramReportingDetailsListener() {
            @Override
            public void onCreateBillingProgramReportingDetailsResponse(
                BillingResult billingResult,
                @Nullable BillingProgramReportingDetails billingProgramReportingDetails
            ) {
                if (billingResult.getResponseCode() != BillingResponseCode.OK) {
                    // Handle failures such as retrying due to network errors.
                    return;
                }
    
                String transactionToken =
                    billingProgramReportingDetails.getExternalTransactionToken();
    
                // Persist the external transaction token locally. Pass it to
                // DeveloperBillingOptionParams when launchBillingFlow is called.
                // It can also be used as part of your external website.
            }
        }
    );
    
    
  5. وقتی کاربر روی «خرید» کلیک می‌کند، صفحه انتخاب جایگزین خود را راه‌اندازی کنید.

  6. انتخاب نوع صورت‌حساب توسط کاربر را به این صورت مدیریت کنید:

    • اگر کاربر «خدمات صورت‌حساب Play» را انتخاب کرد، launchBillingFlow را طبق رهنمودهای استاندارد «خدمات صورت‌حساب Play» فراخوانی کنید. نتیجه صورت‌حساب به PurchasesUpdatedListener ثبت‌شده در مرحله ۱ برگردانده می‌شود.

      کنترل والدین برای کاربران تحت نظارت نمایش داده می‌شود.

    • اگر کاربر صورت‌حساب جایگزین شما را انتخاب کرد، launchExternalLink را فراخوانی کنید. برای مثال:

      کاتلین

      جاوا

      
      // An activity reference from which the purchase flow will be launched.
      Activity activity = ...;
      
      LaunchExternalLinkParams params = LaunchExternalLinkParams.newBuilder()
          .setBillingProgram(BillingProgram.BILLING_CHOICE)
          // You can pass along the external transaction token from
          // BillingProgramReportingDetails as a URL parameter in the URI
          .setLinkUri(yourLinkUri)
          .setLinkType(LaunchExternalLinkParams.LinkType.LINK_TO_DIGITAL_CONTENT_OFFER)
          .setLaunchMode(
              LaunchExternalLinkParams.LaunchMode.LAUNCH_IN_EXTERNAL_BROWSER_OR_APP)
          .setExternalTransactionToken(transactionToken)
          .build();
      
      LaunchExternalLinkResponseListener listener =
          new LaunchExternalLinkResponseListener() {
            @Override
            public void onLaunchExternalLinkResponse(BillingResult billingResult) {
              if (billingResult.getResponseCode() == BillingResponseCode.OK) {
                // Proceed with the rest of the purchase flow. If the user
                // purchases an item, be sure to report the transaction to Google
                // Play.
              } else {
                // Handle failures such as retrying due to network errors.
              }
            }
          };
      
      billingClient.launchExternalLink(activity, params, listener);
      
      
    • رمز تراکنش خارجی را از مرحله ۴ به LaunchExternalLinkParams ارسال کنید. اگر OK برگرداند، تراکنش را ادامه دهید و تراکنش را به Google Play گزارش دهید.

      کنترل والدین برای کاربران تحت نظارت نمایش داده می‌شود.

انتخاب روش صدور صورت‌حساب درطول جایگزینی اشتراک

برای جایگزینی اشتراک، صفحه انتخاب کاربر نباید نمایش داده شود زیرا انتخاب کاربر برای خرید اصلی برای ارتقا و تنزل حفظ می‌شود.

اگر خرید اصلی ازطریق «خدمات صورت‌حساب Google Play» پردازش شده است، باید با launchBillingFlow تماس بگیرید و اطلاعات استاندارد جایگزینی اشتراک «خدمات صورت‌حساب Google Play» را ارائه دهید.

بااین‌حال، اگر خرید اصلی ازطریق سیستم صورت‌حساب جایگزین پردازش شده باشد، رسیدگی به جایگزینی اشتراک‌ها براساس سناریوها کمی متفاوت است.

جایگزینی اشتراک در «سناریو ۱ الف»

کاربرانی که درخواست ارتقا یا تنزل دارند باید بدون اینکه دوباره تجربه انتخاب کاربر را طی کنند، ازطریق سیستم صورت‌حساب جایگزین توسعه‌دهنده اقدام کنند.

برای انجام این کار، وقتی کاربر درخواست ارتقا یا تنزل می‌دهد، با launchBillingFlow تماس بگیرید. از setOriginalExternalTransactionId در داخل شیء SubscriptionUpdateParams در پارامترها برای ارائه شناسه تراکنش خارجی برای خرید اصلی استفاده کنید. این کار صفحه انتخاب کاربر را نمایش نمی‌دهد، زیرا انتخاب کاربر برای خرید اصلی برای ارتقا و تنزل حفظ می‌شود. تماس با launchBillingFlow در این مورد نشان تراکنش خارجی جدیدی برای تراکنشی که می‌توانید از برگشت تماس بازیابی کنید تولید می‌کند.

کاتلین

// The external transaction ID from the current
// alternative billing subscription.
val externalTransactionId = "external_transaction_id"

val developerBillingOptionParams = DeveloperBillingOptionParams.newBuilder()
    .setBillingProgram(BillingProgram.BILLING_CHOICE)
    .build()

val billingFlowParams = BillingFlowParams.newBuilder()
    .setProductDetailsParamsList(
        listOf(
            BillingFlowParams.ProductDetailsParams.newBuilder()
                // Fetched using queryProductDetailsAsync.
                .setProductDetails(productDetailsNewPlan)
                // offerIdToken can be found in
                // ProductDetails=>SubscriptionOfferDetails.
                .setOfferToken(offerTokenNewPlan)
                .build()
        )
    )
    .setSubscriptionUpdateParams(
        SubscriptionUpdateParams.newBuilder()
            .setOriginalExternalTransactionId(externalTransactionId)
            .build()
    )
    .enableDeveloperBillingOption(developerBillingOptionParams)
    .build()

val billingResult = billingClient.launchBillingFlow(activity, billingFlowParams)

// When the user selects the alternative billing flow,
// the DeveloperProvidedBillingListener is triggered.

جاوا


// The external transaction ID from the current
// alternative billing subscription.
String externalTransactionId = //... ;

DeveloperBillingOptionParams developerBillingOptionParams =
    DeveloperBillingOptionParams.newBuilder()
        .setBillingProgram(BillingProgram.BILLING_CHOICE)
        .build();

List<ProductDetailsParams> productDetailsParamsList = new ArrayList<>();
productDetailsParamsList.add(
    ProductDetailsParams.newBuilder()
        // Fetched using queryProductDetailsAsync.
        .setProductDetails(productDetailsNewPlan)
        // offerIdToken can be found in
        // ProductDetails=>SubscriptionOfferDetails
        .setOfferToken(offerTokenNewPlan)
        .build());

BillingFlowParams billingFlowParams =
    BillingFlowParams.newBuilder()
        .setProductDetailsParamsList(productDetailsParamsList)
        .setSubscriptionUpdateParams(
            SubscriptionUpdateParams.newBuilder()
                .setOriginalExternalTransactionId(externalTransactionId)
                .build())
        .enableDeveloperBillingOption(developerBillingOptionParams)
        .build();

BillingResult billingResult = billingClient.launchBillingFlow(activity, billingFlowParams);

// When the user selects the alternative billing flow,
// the DeveloperProvidedBillingListener is triggered.


وقتی ارتقا یا تنزل تکمیل شد، باید بااستفاده از کد تراکنش خارجی که ازطریق تماس قبلی برای خرید اشتراک جدید دریافت کرده‌اید، تراکنش جدیدی را گزارش کنید.

جایگزینی اشتراک در «سناریو ۱ب»

در این سناریو، باید یک کد تراکنش خارجی جدید تولید شود. تنها تفاوت با خرید عادی این است که در این سناریو، انتخاب کاربر حفظ می‌شود و لازم نیست صفحه انتخاب را برای ارتقا یا تنزل نمایش دهید. بااین‌حال، باید کادر گفتگوی اطلاعات یک‌بارمصرف و تأییدیه ولی را نشان دهید.

برای نمونه کد یکپارچه‌سازی، به مرحله ۴ در «سناریو ۱-ب: توسعه‌دهنده صفحه انتخاب را ارائه می‌کند و صورت‌حساب جایگزین در برنامه شما مدیریت می‌شود» مراجعه کنید.

وقتی ارتقا یا تنزل تکمیل شد، باید بااستفاده از کد تراکنش خارجی که ازطریق تماس قبلی برای خرید اشتراک جدید دریافت کرده‌اید، تراکنش جدیدی را گزارش کنید.

جایگزینی اشتراک در «سناریو ۲A»

برای اشتراک‌هایی که در ابتدا ازطریق وب‌سایت توسعه‌دهنده یا برنامه پرداخت پس‌از انتخاب کاربر خریداری شده‌اند، کاربرانی که درخواست ارتقا یا تنزل می‌دهند باید ازطریق وب‌سایت توسعه‌دهنده یا برنامه پرداخت اقدام کنند و دوباره تجربه انتخاب کاربر را طی نکنند.

برای انجام این کار، وقتی کاربر درخواست ارتقا یا تنزل می‌دهد، با launchBillingFlow تماس بگیرید. به‌جای مشخص کردن پارامترهای دیگر در شیء SubscriptionUpdateParams، از setOriginalExternalTransactionId استفاده کنید و شناسه تراکنش خارجی را برای خرید اصلی ارائه دهید. ‫DeveloperBillingOptionParams نیز باید در این تماس ارائه شود. این کار صفحه انتخاب کاربر را نمایش نمی‌دهد، زیرا انتخاب کاربر برای خرید اصلی برای ارتقا و تنزل حفظ می‌شود. برای مثال:

کاتلین

val externalTransactionId = "external_transaction_id"

// 1. Construct DeveloperBillingOptionParams indicating the billing program
val developerBillingOptionParams = DeveloperBillingOptionParams.newBuilder()
    .setBillingProgram(BillingProgram.BILLING_CHOICE)
    .build()

// 2. Build BillingFlowParams combining DeveloperBillingOptionParams and SubscriptionUpdateParams
val billingFlowParams = BillingFlowParams.newBuilder()
    .setProductDetailsParamsList(
        listOf(
            BillingFlowParams.ProductDetailsParams.newBuilder()
                // Fetched using queryProductDetailsAsync.
                .setProductDetails(productDetailsNewPlan)
                // offerIdToken can be found in ProductDetails=>SubscriptionOfferDetails.
                .setOfferToken(offerTokenNewPlan)
                .build()
        )
    )
    .setSubscriptionUpdateParams(
        SubscriptionUpdateParams.newBuilder()
            .setOriginalExternalTransactionId(externalTransactionId)
            .build()
    )
    .enableDeveloperBillingOption(developerBillingOptionParams)
    .build()

جاوا


String externalTransactionId = //... ;

// 1. Construct DeveloperBillingOptionParams indicating the billing program
DeveloperBillingOptionParams developerBillingOptionParams =
    DeveloperBillingOptionParams.newBuilder()
        .setBillingProgram(BillingClient.BillingProgram.BILLING_CHOICE)
        .build();

// 2. Add ProductDetailsParams
List productDetailsParamsList = new ArrayList<>();
productDetailsParamsList.add(
    ProductDetailsParams.newBuilder()
        // Fetched using queryProductDetailsAsync.
        .setProductDetails(productDetailsNewPlan)
        // offerIdToken can be found in ProductDetails=>SubscriptionOfferDetails
        .setOfferToken(offerTokenNewPlan)
        .build());

// 3. Build BillingFlowParams combining DeveloperBillingOptionParams and SubscriptionUpdateParams
BillingFlowParams billingFlowParams =
    BillingFlowParams.newBuilder()
        .setProductDetailsParamsList(productDetailsParamsList)
        .setSubscriptionUpdateParams(
            SubscriptionUpdateParams.newBuilder()
                .setOriginalExternalTransactionId(externalTransactionId)
                .build())
        .enableDeveloperBillingOption(developerBillingOptionParams)
        .build();


همچنین باید کد تراکنش خارجی جدیدی تولید کنید. برای مثال:

کاتلین

val params =
    BillingProgramReportingDetailsParams.newBuilder()
        .setBillingProgram(BillingProgram.BILLING_CHOICE)
        .setDeveloperBillingType(DeveloperBillingType.EXTERNAL_LINK)
        .build()

val (billingResult, billingProgramReportingDetails) =
    billingClient.createBillingProgramReportingDetails(params)

if (billingResult.responseCode != BillingResponseCode.OK) {
    // Handle failures such as retrying due to network errors.
    return
}

val externalTransactionToken =
    billingProgramReportingDetails?.externalTransactionToken
// Persist the external transaction token locally. Pass it to
// the external website using DeveloperBillingOptionParams when
// launchBillingFlow is called.

جاوا


BillingProgramReportingDetailsParams params =
    BillingProgramReportingDetailsParams.newBuilder()
        .setBillingProgram(BillingProgram.BILLING_CHOICE)
        .setDeveloperBillingType(DeveloperBillingType.EXTERNAL_LINK)
        .build();

billingClient.createBillingProgramReportingDetailsAsync(
    params,
    new BillingProgramReportingDetailsListener() {
      @Override
      public void onCreateBillingProgramReportingDetailsResponse(
          BillingResult billingResult,
          @Nullable BillingProgramReportingDetails billingProgramReportingDetails) {
        if (billingResult.getResponseCode() != BillingResponseCode.OK) {
          // Handle failures such as retrying due to network errors.
          return;
        }
        String transactionToken =
            billingProgramReportingDetails.getExternalTransactionToken();
        // Persist the external transaction token locally. Pass it to
        // the external website using DeveloperBillingOptionParams when
        // launchBillingFlow is called.
      }
    });

پس‌از تولید کردن کد جدید، باید روش launchBillingFlow را برای راه‌اندازی جریان خرید فراخوانی کنید.

وقتی ارتقا یا تنزل تکمیل شد، باید بااستفاده از کد تراکنش خارجی که ازطریق تماس قبلی برای خرید اشتراک جدید دریافت کرده‌اید، تراکنش جدیدی را گزارش کنید.

جایگزینی اشتراک در «سناریو ۲B»

مراحل مدیریت جایگزینی اشتراک در این سناریو مشابه مراحل توضیح‌داده‌شده در جایگزینی اشتراک در سناریو 2A است. تنها تفاوت این است که پس‌از تولید کردن کد تراکنش، به‌جای فراخوانی روش launchBillingFlow، باید launchExternalLink را فراخوانی کنید تا کادر گفتگوی سلب مسئولیت پیوند خروجی نشان داده شود. در این سناریو، انتخاب کاربر حفظ می‌شود و لازم نیست صفحه انتخاب را برای ارتقا یا تنزل نشان دهید.

برای نمونه کد یکپارچه‌سازی، مرحله ۶ در «سناریو ۲-ب: توسعه‌دهنده صفحه انتخاب را ارائه می‌کند و صورت‌حساب جایگزین در برنامه شما مدیریت می‌شود» را ببینید.

وقتی ارتقا یا تنزل تکمیل شد، باید بااستفاده از کد تراکنش خارجی که ازطریق تماس قبلی برای خرید اشتراک جدید دریافت کرده‌اید، تراکنش جدیدی را گزارش کنید.