Conseils sur l'intégration dans l'application pour le choix de la facturation

Ce guide explique comment intégrer votre application aux API de la bibliothèque Play Billing afin de proposer un choix de facturation à vos utilisateurs.

Intégration à la bibliothèque Play Billing

Vous pouvez intégrer le choix de facturation à la bibliothèque Play Billing dans quatre scénarios. Ils diffèrent selon qui affiche l'écran de choix et où le paiement aura lieu. Le tableau suivant présente les scénarios d'intégration :

Où le paiement a-t-il lieu ?
Dans l'application Lien Web externe
Quel écran de choix de facturation souhaitez-vous afficher ? Celui de Google Play Scénario 1A

Google affiche l'écran de choix et la facturation alternative est gérée dans votre application.

Scénario 1B

Le développeur d'applications affiche l'écran de choix et la facturation alternative est gérée dans votre application.

Le vôtre (conformément aux consignes relatives à l'expérience utilisateur) Scénario 2A

Google affiche l'écran de choix et l'utilisateur est redirigé en dehors de votre application vers vos propres sites Web pour effectuer des achats.

Scénario 2B

Le développeur d'applications affiche l'écran de choix et l'utilisateur est redirigé en dehors de votre application vers vos propres sites Web pour effectuer des achats.

L'illustration suivante détaille le parcours de choix de facturation pour chacun de ces scénarios :

Flux de choix de la facturation montrant la séquence des appels d'API et des interactions utilisateur pour les quatre scénarios d'intégration.
Figure 1. Scénarios d'intégration du choix de facturation

Scénarios d'intégration de la bibliothèque Play Billing

En fonction de votre scénario d'intégration, suivez les étapes de cette section pour implémenter le choix de facturation dans votre application.

Gérer le scénario 1A

Google affiche l'écran de choix et la facturation alternative est gérée dans votre application. Pour activer le choix de facturation dans ce scénario, procédez comme suit :

  1. Appelez enableBillingProgram avec EnableBillingProgramParams lorsque vous créez votre instance BillingClient, puis démarrez la connexion. Exemple :

    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. Vérifiez que le choix de facturation affiché par Google est disponible pour l'utilisateur.

    Appelez isBillingProgramAvailableAsync pour vérifier la disponibilité du programme, puis appelez queryProductDetailsAsync pour afficher les produits disponibles. Exemple :

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

    Remarque : billingProgramAvailabilityDetails vous indique si l'écran de choix de facturation affiché par Google ou par le développeur est disponible.

  3. Appelez launchBillingFlow pour déclencher le parcours d'achat lorsque l'utilisateur clique sur "Acheter". Si le choix de facturation est disponible, transmettez DeveloperBillingOptionParams à BillingFlowParams. Exemple :

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

    Remarque : Le contrôle parental s'affiche pour les utilisateurs supervisés.

  4. Gérez la sélection du type de facturation par l'utilisateur comme suit :

    • Si l'utilisateur sélectionne la facturation Play, le résultat de la facturation est renvoyé au PurchasesUpdatedListener enregistré à l'étape 1.
    • Si l'utilisateur sélectionne votre facturation alternative, le résultat de la facturation est renvoyé au DeveloperProvidedBillingListener enregistré à l'étape 1. Dans ce cas, le DeveloperProvidedBillingDetails renvoyé contient un externalTransactionToken. Le jeton sera utilisé pour le reporting des transactions.

Gérer le scénario 1B

Le développeur affiche l'écran de choix et la facturation alternative est gérée dans votre application. Pour activer le choix de facturation dans ce scénario, procédez comme suit :

  1. Appelez enableBillingProgram sans le DeveloperProvidedBillingListener dans EnableBillingProgramParams lorsque vous créez une BillingClient instance, puis démarrez la connexion. Exemple :

    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. Vérifiez que le choix de facturation affiché par le développeur est disponible pour l'utilisateur.

    Appelez isBillingProgramAvailableAsync pour vérifier la disponibilité du programme, puis appelez queryProductDetailsAsync pour afficher les produits disponibles. Exemple :

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

    Remarque : billingProgramAvailabilityDetails vous indique si l'écran de choix de facturation affiché par Google ou par le développeur est disponible.

  3. Appelez la méthode getBillingChoiceInfoAsync pour obtenir la bannière de facturation Play et les informations sur la fidélité. Exemple :

    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. Créez un jeton de transaction externe avec DeveloperBillingType défini sur IN_APP. Exemple :

    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. Lorsque l'utilisateur clique sur "Acheter", appelez showBillingProgramInformationDialog pour afficher une boîte de dialogue d'informations. Pour obtenir un exemple, consultez Boîte de dialogue d'informations pour les utilisateurs. BillingProgram et transactionToken de l'étape 4 doivent être définis dans la requête.

    Remarque : Le contrôle parental s'affiche pour les utilisateurs supervisés.

  6. Lancez votre écran de choix de facturation alternative si le résultat de l'étape précédente est OK.

  7. Gérez la sélection du type de facturation par l'utilisateur comme suit :

    • Si l'utilisateur sélectionne Play Billing, appelez launchBillingFlow en suivant les consignes standards de Play Billing. Le résultat de la facturation est renvoyé au PurchasesUpdatedListener enregistré à l'étape 1.
    • Si l'utilisateur sélectionne votre système de facturation alternatif, vous devez gérer vous-même la transaction et la signaler à Google Play à l'aide du jeton généré à l'étape 4.

Gérer le scénario 2A

Google affiche l'écran de choix et la facturation alternative est gérée en dehors de votre application. Pour activer le choix de facturation dans ce scénario, procédez comme suit :

  1. Appelez enableBillingProgram avec EnableBillingProgramParams lorsque vous créez votre instance BillingClient, puis démarrez la connexion. Exemple :

    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. Vérifiez la disponibilité des éléments suivants :

    • Choix de facturation affiché par Google
    • Lien Web externe

    Appelez isBillingProgramAvailableAsync pour vérifier la disponibilité du programme, puis appelez queryProductDetailsAsync pour afficher les produits disponibles. Exemple :

    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. Appelez createBillingProgramReportingDetailsAsync pour créer un jeton de transaction externe lorsque l'utilisateur indique son intention d'acheter. Exemple :

    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. Appelez launchBillingFlow pour déclencher le parcours d'achat lorsque l'utilisateur clique sur "Acheter". Si le choix de facturation est disponible pour l'utilisateur, procédez comme suit :

    1. Transmettez DeveloperBillingOptionParams à BillingFlowParams.
    2. Transmettez le jeton de transaction externe de l'étape 3 à DeveloperBillingOptionParams.

    Exemple :

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

    Remarque : Le contrôle parental s'affiche pour les utilisateurs supervisés.

  5. Gérez la sélection du type de facturation par l'utilisateur comme suit :

Gérer le scénario 2B

Le développeur affiche l'écran de choix et la facturation alternative est gérée en dehors de l'application. Pour activer le choix de facturation dans ce scénario, procédez comme suit :

  1. Appelez enableBillingProgram sans le DeveloperProvidedBillingListener dans EnableBillingProgramParams lorsque vous créez une instance BillingClient, puis démarrez la connexion. Exemple :

    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. Vérifiez la disponibilité des éléments suivants :

    • Choix de facturation affiché par Google
    • Lien Web externe

    Appelez isBillingProgramAvailableAsync pour vérifier la disponibilité du programme, puis appelez queryProductDetailsAsync pour afficher les produits disponibles. Exemple :

    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. Appelez la méthode getBillingChoiceInfoAsync pour obtenir la bannière de facturation Play et les informations sur la fidélité.

    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. Appelez createBillingProgramReportingDetailsAsync pour créer un jeton de transaction externe lorsque l'utilisateur indique son intention d'acheter. Exemple :

    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. Lancez votre écran de choix alternatif lorsque l'utilisateur clique sur "Acheter".

  6. Gérez la sélection du type de facturation par l'utilisateur comme suit :

    • Si l'utilisateur sélectionne Play Billing, appelez launchBillingFlow en suivant les consignes standards de Play Billing. Le résultat de la facturation est renvoyé au PurchasesUpdatedListener enregistré à l'étape 1.

      Le contrôle parental s'affiche pour les utilisateurs supervisés.

    • Si l'utilisateur sélectionne votre système de facturation alternatif, appelez launchExternalLink. Exemple :

      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);
      
      
    • Transmettez le jeton de transaction externe de l'étape 4 à LaunchExternalLinkParams. S'il renvoie OK, poursuivez la transaction et signalez-la à Google Play.

      Le contrôle parental s'affiche pour les utilisateurs supervisés.

Choix de facturation lors du remplacement d'un abonnement

Pour le remplacement d'un abonnement, l'écran de choix utilisateur ne doit pas s'afficher, car le choix utilisateur pour l'achat d'origine est conservé pour les mises à niveau et les rétrogradations.

Si l'achat d'origine a été traité via Google Play Billing, vous devez appeler launchBillingFlow avec les informations standards de remplacement d'abonnement de la facturation Google Play.

Toutefois, si l'achat d'origine a été traité via une facturation alternative, la gestion des remplacements d'abonnement diffère légèrement selon les scénarios.

Remplacement d'abonnement dans le scénario 1A

Les utilisateurs qui demandent une mise à niveau ou une rétrogradation doivent passer par le système de facturation alternatif du développeur. Ils n'ont pas à repasser par le parcours de choix utilisateur.

Pour ce faire, appelez launchBillingFlow lorsque l'utilisateur demande une mise à niveau ou une rétrogradation. Utilisez setOriginalExternalTransactionId dans l'objet SubscriptionUpdateParams des paramètres pour fournir l'ID de transaction externe de l'achat d'origine. Cela n'affichera pas l'écran de choix utilisateur, car le choix utilisateur pour l'achat d'origine est conservé pour les mises à niveau et les rétrogradations. Dans ce cas, l'appel de launchBillingFlow génère un nouveau jeton de transaction externe que vous pouvez récupérer à partir du rappel.

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.


Une fois la mise à niveau ou la rétrogradation effectuée, vous devez enregistrer une nouvelle transaction à l’aide du jeton de transaction externe obtenu via l’ appel précédent pour l’achat du nouvel abonnement.

Remplacement d'abonnement dans le scénario 1B

Dans ce scénario, un nouveau jeton de transaction externe doit être généré. La seule différence par rapport à un achat normal est que, dans ce scénario, le choix utilisateur est conservé, et vous n'avez pas à afficher l'écran de choix pour la mise à niveau ou la rétrogradation. Toutefois, vous devez afficher la boîte de dialogue d'informations unique et l'accusé de réception du contrôle parental.

Pour obtenir un exemple de code d'intégration, consultez l'étape 4 du scénario 1B : Le développeur affiche l' écran de choix et la facturation alternative est gérée dans votre application.

Une fois la mise à niveau ou la rétrogradation effectuée, vous devez enregistrer une nouvelle transaction à l’aide du jeton de transaction externe obtenu via l’ appel précédent pour l’achat du nouvel abonnement.

Remplacement d'abonnement dans le scénario 2A

Pour les abonnements initialement souscrits via le site Web du développeur ou une application de paiement après le choix de l'utilisateur, les personnes qui demandent une mise à niveau ou une rétrogradation doivent passer par le site Web du développeur ou une application de paiement. Elles n'ont pas à repasser par le parcours de facturation au choix de l'utilisateur.

Pour ce faire, appelez launchBillingFlow lorsque l'utilisateur demande une mise à niveau ou une rétrogradation. Au lieu de spécifier d'autres paramètres sous l' SubscriptionUpdateParams objet, utilisez setOriginalExternalTransactionId, en fournissant l'ID de transaction externe pour l'achat d'origine. DeveloperBillingOptionParams doit également être fourni dans cet appel. Cela n'affichera pas l'écran de choix utilisateur, car le choix utilisateur pour l'achat d'origine est conservé pour les mises à niveau et les rétrogradations. Exemple :

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


Vous devez également générer un nouveau jeton de transaction externe. Exemple :

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

Après avoir généré le nouveau jeton, vous devez appeler la launchBillingFlow méthode pour lancer le parcours d'achat.

Une fois la mise à niveau ou la rétrogradation effectuée, vous devez enregistrer une nouvelle transaction à l’aide du jeton de transaction externe obtenu via l’ appel précédent pour l’achat du nouvel abonnement.

Remplacement d'abonnement dans le scénario 2B

Les étapes à suivre pour gérer le remplacement d'abonnement dans ce scénario sont semblables à celles décrites dans Remplacement d'abonnement dans le scénario 2A. La seule différence est qu'après avoir généré le jeton de transaction, au lieu d'appeler la launchBillingFlow méthode, vous devez appeler launchExternalLink pour afficher la boîte de dialogue d'exclusion de responsabilité du lien. Dans ce scénario, le choix utilisateur est conservé, et vous n'avez pas à afficher l'écran de choix pour la mise à niveau ou la rétrogradation.

Pour obtenir un exemple de code d'intégration, consultez l'étape 6 du scénario 2B : Le développeur affiche l' écran de choix et la facturation alternative est gérée dans votre application.

Une fois la mise à niveau ou la rétrogradation effectuée, vous devez enregistrer une nouvelle transaction à l’aide du jeton de transaction externe obtenu via l’ appel précédent pour l’achat du nouvel abonnement.