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

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

التكامل مع PBL

يمكنك دمج خيار الفوترة مع PBL في أربعة سيناريوهات. تختلف هذه السيناريوهات استنادًا إلى الجهة التي تعرض شاشة الخيار والمكان الذي ستتم فيه عملية الدفع. يوضّح الجدول التالي سيناريوهات التكامل:

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

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

السيناريو 1ب

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

رابط ويب خارجي السيناريو 2أ

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

السيناريو 2ب

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

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

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

سيناريوهات التكامل مع PBL

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

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

تعرض 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. سيتم استخدام الرمز لإعداد تقارير المعاملات.

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

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

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

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

تعرض 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 في السيناريو 1ب: يعرض المطوّر شاشة الخيار و تتم معالجة نظام الفوترة البديل داخل تطبيقك.

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

استبدال الاشتراك في السيناريو 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 لبدء مسار الشراء.

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

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

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

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

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