إرشادات حول الدمج داخل التطبيق لخيارات الفوترة

يوضّح هذا الدليل كيفية دمج تطبيقك مع واجهات برمجة التطبيقات الخاصة بـ Play Billing Library لتتمكّن من توفير خيار الفوترة للمستخدمين.

التكامل مع PBL

يمكنك دمج ميزة اختيار نظام الفوترة مع ميزة "الفوترة داخل التطبيق" في أربع سيناريوهات. تختلف السيناريوهات حسب الجهة التي تعرض شاشة الاختيار والمكان الذي سيتم فيه الدفع. يوضّح الجدول التالي سيناريوهات الدمج:

أين تتم عملية الدفع؟
داخل التطبيق رابط ويب خارجي
ما هي شاشة اختيار نظام الفوترة التي تريد عرضها؟ ‫Google Play السيناريو 1(أ)

يعرض Google شاشة الاختيار وتتم معالجة نظام الفوترة البديل داخل تطبيقك.

السيناريو 1(ب)

يعرض مطوّر التطبيق شاشة الاختيار وتتم معالجة نظام الفوترة البديل داخل تطبيقك.

الخاصة بك (وفقًا لإرشادات تجربة المستخدم) السيناريو 2(أ)

تعرض Google شاشة الاختيار ويتم توجيه المستخدم إلى خارج تطبيقك إلى مواقعك الإلكترونية لإجراء عمليات الشراء.

السيناريو 2B

يعرض مطوّر التطبيق شاشة الاختيار ويتم توجيه المستخدم إلى خارج تطبيقك إلى مواقعك الإلكترونية لإجراء عمليات الشراء.

يوضّح الرسم التوضيحي التالي مسار اختيار نظام الفوترة لكل من هذه السيناريوهات:

مسار اختيار نظام الفوترة الذي يعرض تسلسل طلبات البيانات من واجهة برمجة التطبيقات وتفاعلات المستخدمين في سيناريوهات التكامل الأربعة
الشكل 1. سيناريوهات دمج ميزة "الفوترة حسب اختيار المستخدم"

سيناريوهات دمج PBL

استنادًا إلى سيناريو الدمج، اتّبِع الخطوات الواردة في هذا القسم لتنفيذ ميزة "اختيار نظام الفوترة" في تطبيقك.

التعامل مع السيناريو 1A

تعرض Google شاشة الاختيار، ويتم التعامل مع نظام الفوترة البديل داخل تطبيقك. اتّبِع الخطوات التالية لتفعيل خيار نظام الفوترة في هذه الحالة:

  1. استخدِم enableBillingProgram مع EnableBillingProgramParams عند إنشاء مثيل BillingClient، ثم ابدأ عملية الربط. على سبيل المثال:

    Kotlin

    
    // Build the parameters to enable the Billing Choice program and assign the listener
    // to handle user selection of the developer-provided billing option.
    val params = 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(params)
        .build()
    
    // Establish a connection to Google Play
    val billingResult = suspendCancellableCoroutine { 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.
                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() {
                continuation.resume(
                    BillingResult.newBuilder()
                        .setResponseCode(BillingClient.BillingResponseCode.SERVICE_DISCONNECTED)
                        .setDebugMessage("Billing service disconnected during connection setup")
                        .build()
                )
            }
        })
    }
    
    

    Java

    
    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 لعرض المنتجات المتاحة. على سبيل المثال:

    Kotlin

    
    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.
    }
    
    
    

    Java

    
    // ...
    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. على سبيل المثال:

    Kotlin

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

    Java

    
    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 المسجَّل في الخطوة 1.
    • إذا اختار المستخدم نظام الفوترة البديل، سيتم عرض نتيجة الفوترة في DeveloperProvidedBillingListener المسجَّل في الخطوة 1. يحتوي DeveloperProvidedBillingDetails الذي تم عرضه على externalTransactionToken في هذه الحالة. سيتم استخدام الرمز المميّز في إعداد تقارير المعاملات.

التعامل مع السيناريو 1B

يعرض المطوِّر شاشة اختيار نظام الفوترة، ويتم التعامل مع نظام الفوترة البديل داخل تطبيقك. اتّبِع الخطوات التالية لتفعيل خيار نظام الفوترة في هذه الحالة:

  1. اتّصِل بـ enableBillingProgram بدون DeveloperProvidedBillingListener في EnableBillingProgramParams عند إنشاء مثيل BillingClient، ثم ابدأ الاتصال. على سبيل المثال:

    Kotlin

    
    // Build the parameters to enable the Billing Choice program.
    val params = EnableBillingProgramParams.newBuilder()
        .setBillingProgram(BillingProgram.BILLING_CHOICE)
        .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()
        .enableBillingProgram(params)
        .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.
                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() {
                continuation.resume(
                    BillingResult.newBuilder()
                        .setResponseCode(BillingClient.BillingResponseCode.SERVICE_DISCONNECTED)
                        .setDebugMessage("Billing service disconnected during connection setup")
                        .build()
                )
            }
        })
    }
    
    

    Java

    
    EnableBillingProgramParams params = EnableBillingProgramParams.newBuilder()
            .setBillingProgram(BillingProgram.BILLING_CHOICE)
            .build();
    
    BillingClient billingClient = BillingClient.newBuilder(context)
            .setListener(purchasesUpdatedListener)
            .enablePendingPurchases()
            .enableBillingProgram(params)
            .build();
    
    
  2. تأكَّد من أنّ خيار الفوترة الذي يوفّره المطوّر متاح للمستخدم.

    اتّصِل بالرقم isBillingProgramAvailableAsync للتحقّق من توفّر البرنامج، ثم اتّصِل بالرقم queryProductDetailsAsync لعرض المنتجات المتاحة. على سبيل المثال:

    Kotlin

    
    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.
    }
    
    

    Java

    
    // ...
    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. استدعِ طريقة getBillingChoiceInfoAsync للحصول على بانر "الفوترة في Play" ومعلومات برنامج الولاء. على سبيل المثال:

    Kotlin

    
    // 1. Create the params required for the request
    val params = GetBillingChoiceInfoParams.newBuilder()
        .setBillingProgram(BillingClient.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
    }
    
    

    Java

    
    // 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. على سبيل المثال:

    Kotlin

    
    // 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
    
    

    Java

    
    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 من الخطوة 4 في الطلب.

    ملاحظة: يتم عرض أدوات رقابة الأهل للمستخدمين الخاضعين للإشراف.

  6. اعرض شاشة اختيار نظام الفوترة البديل إذا كانت النتيجة من الخطوة السابقة هي OK.

  7. تعامَل مع اختيار المستخدم لنوع الفوترة على النحو التالي:

    • إذا اختار المستخدم خدمة "الفوترة في Play"، عليك استدعاء launchBillingFlow باتّباع إرشادات خدمة "الفوترة في Play" العادية. يتم عرض نتيجة الفوترة في PurchasesUpdatedListener المسجَّل في الخطوة 1.
    • إذا اختار المستخدم نظام الفوترة البديل، عليك معالجة المعاملة بنفسك وإبلاغ Play بها باستخدام الرمز المميّز الذي تم إنشاؤه في الخطوة 4.

التعامل مع السيناريو 2A

تعرض Google شاشة الاختيار ويتم التعامل مع نظام الفوترة البديل خارج تطبيقك. اتّبِع الخطوات التالية لتفعيل خيار الفوترة في هذه الحالة:

  1. استخدِم enableBillingProgram مع EnableBillingProgramParams عند إنشاء مثيل BillingClient، ثم ابدأ عملية الربط. على سبيل المثال:

    Kotlin

    
    // Build the parameters to enable the Billing Choice program and assign the listener
    // to handle user selection of the developer-provided billing option.
    val params = 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(params)
        .build()
    
    // Establish a connection to Google Play
    val billingResult = suspendCancellableCoroutine { 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.
                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() {
                continuation.resume(
                    BillingResult.newBuilder()
                        .setResponseCode(BillingClient.BillingResponseCode.SERVICE_DISCONNECTED)
                        .setDebugMessage("Billing service disconnected during connection setup")
                        .build()
                )
            }
        })
    }
    
    

    Java

    
    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 لعرض المنتجات المتاحة. على سبيل المثال:

    Kotlin

    
    // Check the availability of the billing choice program asynchronously using coroutines
    val (billingResult, billingProgramAvailabilityDetails) =
        billingClient.isBillingProgramAvailable(BillingProgram.BILLING_CHOICE)
    
    // Ensure the billing program query succeeded
    if (billingResult.responseCode == BillingResponseCode.OK) {
        // Retrieve the availability details specific to the billing choice program
        val billingChoiceAvailabilityDetails =
            billingProgramAvailabilityDetails.billingChoiceAvailabilityDetails
    
        // Check if billing choice is available, renders via Google Play, and external link is supported
        if (billingChoiceAvailabilityDetails != null &&
            billingChoiceAvailabilityDetails.choiceScreenType == 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.
    }
    
    
    

    Java

    
    // ...
    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 لإنشاء رمز معاملة خارجية عندما يُبدي المستخدم نيّته في الشراء. على سبيل المثال:

    Kotlin

    
    // Build the parameters for creating reporting details
    val params =
        BillingProgramReportingDetailsParams.newBuilder()
            .setBillingProgram(BillingProgram.BILLING_CHOICE)
            .setDeveloperBillingType(DeveloperBillingType.EXTERNAL_LINK)
            .build()
    
    // Call the suspend function to create billing program reporting details
    val (billingResult, billingProgramReportingDetails) =
        billingClient.createBillingProgramReportingDetails(params)
    
    // Handle response failure cases
    if (billingResult.responseCode != BillingResponseCode.OK) {
        // Handle failures such as retrying due to network errors.
        return
    }
    
    // Retrieve the external transaction token
    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
    
    

    Java

    
    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. مرِّر الرمز المميّز للمعاملة الخارجية من الخطوة 3 إلى DeveloperBillingOptionParams.

    على سبيل المثال:

    Kotlin

    
    // Build the developer billing option parameters with the external link URI,
    // the transaction token, and browser/app launch mode.
    val 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()
    
    

    Java

    
    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. تعامَل مع اختيار المستخدم لنوع الفوترة على النحو التالي:

التعامل مع السيناريو 2 (ب)

يعرض المطوِّر شاشة الخيار ويتم التعامل مع نظام الفوترة البديل خارج التطبيق. اتّبِع الخطوات التالية لتفعيل خيار الفوترة في هذه الحالة:

  1. استدعِ الدالة enableBillingProgram بدون DeveloperProvidedBillingListener في EnableBillingProgramParams عند إنشاء مثيل BillingClient، ثم ابدأ عملية الربط. على سبيل المثال:

    Kotlin

    
    // Build the parameters to enable the Billing Choice program.
    val params = EnableBillingProgramParams.newBuilder()
        .setBillingProgram(BillingProgram.BILLING_CHOICE)
        .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()
        .enableBillingProgram(params)
        .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.
                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() {
                continuation.resume(
                    BillingResult.newBuilder()
                        .setResponseCode(BillingClient.BillingResponseCode.SERVICE_DISCONNECTED)
                        .setDebugMessage("Billing service disconnected during connection setup")
                        .build()
                )
            }
        })
    }
    
    

    Java

    
    EnableBillingProgramParams params = EnableBillingProgramParams.newBuilder()
            .setBillingProgram(BillingProgram.BILLING_CHOICE)
            .build();
    
    BillingClient billingClient = BillingClient.newBuilder(context)
            .setListener(purchasesUpdatedListener)
            .enablePendingPurchases()
            .enableBillingProgram(params)
            .build();
    
    
  2. تأكَّد من توفّر ما يلي:

    • خيار الفوترة الذي تقدّمه Google
    • رابط ويب خارجي

    اتّصِل بالرقم isBillingProgramAvailableAsync للتحقّق من توفّر البرنامج، ثم اتّصِل بالرقم queryProductDetailsAsync لعرض المنتجات المتاحة. على سبيل المثال:

    Kotlin

    
    // Check the availability of the billing choice program asynchronously using a coroutine
    val (billingResult, billingProgramAvailabilityDetails) =
        billingClient.isBillingProgramAvailable(BillingProgram.BILLING_CHOICE)
    
    // Ensure the response code is OK
    if (billingResult.responseCode == BillingResponseCode.OK) {
        // Retrieve the billing choice availability details
        val billingChoiceAvailabilityDetails =
            billingProgramAvailabilityDetails.billingChoiceAvailabilityDetails
    
        // Check if billing choice details are available, choice screen is developer-rendered,
        // and external transaction links are supported.
        if (billingChoiceAvailabilityDetails != null &&
            billingChoiceAvailabilityDetails.choiceScreenType == 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.
    }
    
    

    Java

    
    // ...
    
    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. استدعِ طريقة getBillingChoiceInfoAsync للحصول على بانر "الفوترة في Play" ومعلومات برنامج الولاء.

    Kotlin

    
    // 1. Create the params required for the request
    val params = GetBillingChoiceInfoParams.newBuilder()
        .setBillingProgram(BillingClient.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
    }
    
    

    Java

    
    // 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 لإنشاء رمز معاملة خارجية عندما يُبدي المستخدم نيّته في الشراء. على سبيل المثال:

    Kotlin

    
    // Build the parameters for creating reporting details
    val params =
        BillingProgramReportingDetailsParams.newBuilder()
            .setBillingProgram(BillingProgram.BILLING_CHOICE)
            .setDeveloperBillingType(DeveloperBillingType.EXTERNAL_LINK)
            .build()
    
    // Call the suspend function to create billing program reporting details
    val (billingResult, billingProgramReportingDetails) =
        billingClient.createBillingProgramReportingDetails(params)
    
    // Handle response failure cases
    if (billingResult.responseCode != BillingResponseCode.OK) {
        // Handle failures such as retrying due to network errors.
        return
    }
    
    // Retrieve the external transaction token
    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
    
    

    Java

    
    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 المسجَّل في الخطوة 1.

      تظهر أدوات رقابة الأهل للمستخدمين تحت الإشراف.

    • إذا اختار المستخدم نظام الفوترة البديل، استدعِ الدالة launchExternalLink. على سبيل المثال:

      Kotlin

      
      // An activity reference from which the purchase flow will be launched.
      val activity: Activity = ...
      
      val 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
          )
          .build()
      
      // Call launchExternalLink with a callback
      billingClient.launchExternalLink(activity, params) { billingResult ->
          if (billingResult.responseCode == 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.
          }
      }
      
      

      Java

      
      // 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);
      
      
    • مرِّر الرمز المميّز للمعاملة الخارجية من الخطوة 4 إلى LaunchExternalLinkParams. إذا تم عرض OK، يمكنك المتابعة وإجراء المعاملة وإبلاغ Google Play بها.

      تظهر أدوات رقابة الأهل للمستخدمين الخاضعين للإشراف.

اختيار طريقة الفوترة أثناء استبدال الاشتراك

عند استبدال الاشتراك، يجب عدم عرض شاشة خيارات المستخدمين لأنّ خيار المستخدم الذي تم تحديده عند إجراء عملية الشراء الأصلية يتم الاحتفاظ به عند الترقية أو الرجوع إلى إصدار أقدم.

إذا تم إجراء عملية الشراء الأصلية من خلال خدمة "الفوترة في Google Play"، عليك استدعاء launchBillingFlow مع معلومات استبدال الاشتراك في خدمة "الفوترة في Google Play" العادية.

ومع ذلك، إذا تمت معالجة عملية الشراء الأصلية من خلال نظام فوترة بديل، سيختلف التعامل مع عمليات استبدال الاشتراكات قليلاً حسب السيناريوهات.

استبدال الاشتراك في السيناريو 1(أ)

على المستخدمين الذين يطلبون الترقية أو الرجوع إلى إصدار أقدم مواصلة العملية من خلال نظام الفوترة البديل الخاص بالمطوّر بدون المرور بتجربة برنامج "الفوترة حسب اختيار المستخدم" مرة أخرى.

لإجراء ذلك، استدعِ الدالة launchBillingFlow عندما يطلب المستخدم ترقية أو الرجوع إلى إصدار سابق. استخدِم setOriginalExternalTransactionId داخل عنصر SubscriptionUpdateParams في المَعلمات لتوفير رقم تعريف المعاملة الخارجية لعملية الشراء الأصلية. لا تعرض هذه السمة شاشة اختيار المستخدم، لأنّ اختيار المستخدم للشراء الأصلي يتم الاحتفاظ به عند الترقية إلى إصدار أعلى أو الرجوع إلى إصدار أدنى. يؤدي طلب launchBillingFlow في هذه الحالة إلى إنشاء رمز مميز جديد لمعاملة خارجية للمعاملة، ويمكنك استرداده من دالة الرجوع.

Kotlin


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

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(
        BillingFlowParams.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.

Java


// 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.


عند اكتمال عملية الترقية أو الرجوع إلى إصدار سابق، عليك الإبلاغ عن معاملة جديدة باستخدام رمز المعاملة الخارجية الذي تم الحصول عليه من خلال طلب الشراء السابق للاشتراك الجديد.

استبدال الاشتراك في السيناريو 1(ب)

في هذا السيناريو، يجب إنشاء رمز مميز جديد للمعاملات الخارجية. والفرق الوحيد بين هذا السيناريو وعملية الشراء العادية هو أنّه يتم الاحتفاظ بخيار المستخدم في هذا السيناريو، ولن تحتاج إلى عرض شاشة الخيار للترقية أو الرجوع إلى إصدار أقدم. ومع ذلك، يجب عرض مربّع حوار المعلومات الذي يظهر لمرة واحدة وإقرار الوالدَين.

للاطّلاع على نموذج لرمز الدمج، يُرجى الانتقال إلى الخطوة 4 في السيناريو 1B: يعرض المطوّر شاشة اختيار نظام الفوترة البديل ويتم التعامل مع نظام الفوترة البديل داخل تطبيقك.

عند اكتمال عملية الترقية أو الرجوع إلى إصدار سابق، عليك الإبلاغ عن معاملة جديدة باستخدام رمز المعاملة الخارجية الذي تم الحصول عليه من خلال طلب الشراء السابق للاشتراك الجديد.

استبدال الاشتراك في السيناريو 2أ

بالنسبة إلى الاشتراكات التي تم شراؤها في الأصل من خلال الموقع الإلكتروني للمطوّر أو تطبيق دفع بعد اختيار المستخدم، على المستخدمين الذين يطلبون الترقية أو الرجوع إلى إصدار أقدم الانتقال إلى الموقع الإلكتروني للمطوّر أو تطبيق دفع بدون المرور بتجربة اختيار المستخدم مرة أخرى.

لإجراء ذلك، استدعِ الدالة launchBillingFlow عندما يطلب المستخدم ترقية أو الرجوع إلى إصدار سابق. بدلاً من تحديد مَعلمات أخرى ضمن العنصر SubscriptionUpdateParams، استخدِم setOriginalExternalTransactionId، مع توفير معرّف المعاملة الخارجية لعملية الشراء الأصلية. يجب أيضًا تقديم DeveloperBillingOptionParams في هذه المكالمة. لا تعرض هذه الطريقة شاشة اختيار المستخدم، لأنّ خيار المستخدم للشراء الأصلي يتم الاحتفاظ به عند الترقية أو الرجوع إلى إصدار أقدم. على سبيل المثال:

Kotlin


val externalTransactionId = //... ;

// 1. Construct DeveloperBillingOptionParams indicating the billing program
val developerBillingOptionParams = DeveloperBillingOptionParams.newBuilder()
    .setBillingProgram(BillingClient.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()

Java


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();


يجب أيضًا إنشاء رمز مميّز جديد للمعاملات الخارجية. على سبيل المثال:

Kotlin


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

billingClient.createBillingProgramReportingDetailsAsync(
    params,
    object : BillingProgramReportingDetailsListener {
        override fun onCreateBillingProgramReportingDetailsResponse(
            billingResult: BillingResult,
            billingProgramReportingDetails: BillingProgramReportingDetails?
        ) {
            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.
        }
    }
)

Java


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 لتشغيل مسار الشراء.

عند اكتمال عملية الترقية أو الرجوع إلى إصدار سابق، عليك الإبلاغ عن معاملة جديدة باستخدام رمز المعاملة الخارجية الذي تم الحصول عليه من خلال طلب الشراء السابق للاشتراك الجديد.

استبدال الاشتراك في السيناريو 2B

تتشابه خطوات استبدال الاشتراك في هذا السيناريو مع الخطوات الموضّحة في استبدال الاشتراك في السيناريو 2أ. الفرق الوحيد هو أنّه بعد إنشاء الرمز المميّز للمعاملة، عليك استدعاء طريقة launchExternalLink لعرض مربّع الحوار الخاص بإخلاء المسؤولية عن الانتقال إلى موقع إلكتروني خارجي، بدلاً من استدعاء طريقة launchBillingFlow. في هذه الحالة، يتم الحفاظ على اختيار المستخدم، وليس عليك عرض شاشة الاختيار للترقية أو الرجوع إلى إصدار أقدم.

للاطّلاع على نموذج لرمز الدمج، يُرجى الانتقال إلى الخطوة 6 في السيناريو 2B: يعرض المطوّر شاشة اختيار نظام الفوترة البديل ويتم التعامل مع نظام الفوترة البديل داخل تطبيقك.

عند اكتمال عملية الترقية أو الرجوع إلى إصدار سابق، عليك الإبلاغ عن معاملة جديدة باستخدام رمز المعاملة الخارجية الذي تم الحصول عليه من خلال طلب الشراء السابق للاشتراك الجديد.