Achats intégrés Android : Guide d'implémentation

Achats intégrés Android : Guide d'implémentation

Bonjour ! Je suis zm soft, un développeur inscrit fin 2023 qui a commencé à publier des applications. Je prévois également de lancer une application pour développeurs pour aider les développeurs à traverser les tests fermés ensemble — consultez-la si vous êtes intéressé.

Avez-vous implémenté des achats intégrés dans votre application ? En tant que développeur, être payé pour quelque chose que les utilisateurs apprécient vraiment est l'une des parties les plus gratifiantes du processus. Cet article explique comment y parvenir.

Que sont les achats intégrés ?

Comme vous le savez probablement, les achats intégrés se divisent en deux catégories :

  • Articles consommables
  • Articles d'abonnement

Les deux fonctionnent en accédant à des articles préconfigurés dans le Play Store via la Google Play Billing Library, avec une partie des revenus allant à Google comme frais. L'implémentation est similaire pour les deux, mais les abonnements ont leurs propres pièges — que je couvrirai sur la base de ma propre expérience.

Configuration du Play Store

Enregistrement des articles

Avant de pouvoir afficher quoi que ce soit, vous devez enregistrer vos articles. Vous pouvez modifier les prix, les noms et d'autres détails plus tard, donc ils n'ont pas besoin d'être définitifs. La seule chose que vous ne pouvez pas changer est l'ID — donc si vous prévoyez de réutiliser des articles de test en production, enregistrez-les avec des ID réutilisables comme product_1, 2, 3... ou sub_1, 2, 3....

L'enregistrement se fait sous [Monétisation] — [Produits intégrés] est pour les consommables, et [Abonnements] est pour les articles d'abonnement. Utilisez le bouton [Créer xx] dans chaque section pour enregistrer les articles.

Section Monétisation de Play Console montrant les produits intégrés et abonnements

Le formulaire de saisie est généralement explicite, mais j'ai trouvé la configuration du prix pour les abonnements déroutante au début. Je n'étais pas sûr de comment définir des prix pour toutes les régions à la fois. L'astuce est : [Définir les prix] → [Pays/région] → [Définir le prix].

Formulaire de saisie du prix d'abonnement Play Console

Cliquer sur ce bouton affiche un dialogue qui vous permet de définir les prix en masse :

Dialogue de définition de prix en masse pour toutes les régions dans Play Console

Enregistrement d'un compte de test

Ensuite, enregistrez un compte de test. Sans cela, tout achat effectué pendant les tests sera un vrai débit — donc ne sautez pas cette étape. Enregistrez un compte de test en configurant une liste de diffusion sous [Paramètres] → [Tests de licence] dans la Play Console (l'écran principal du développeur après connexion).

Paramètres de test de licence Play Console pour l'enregistrement du compte de test

Une fois votre e-mail enregistré, passer par un flux d'achat avec ce compte affichera une "carte de test" dans l'écran de paiement, vous permettant de tester sans être vraiment facturé.

Implémentation

Du côté de l'application, vous devrez gérer :

  • Ajout de la bibliothèque
  • Connexion au store et récupération des détails des articles
  • Construction de l'interface d'achat
  • Déclenchement du flux d'achat
  • Gestion de la finalisation de l'achat

Ajout de la bibliothèque

Vous devrez mettre à jour deux fichiers :

  • build.gradle
  • AndroidManifest.xml

Exemple de mise à jour build.gradle :

dependencies {
    implementation "com.android.billingclient:6.0.0"
}

Exemple de mise à jour AndroidManifest.xml :

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">

    <uses-permission android:name="com.android.vending.BILLING" />

    <application

Consultez la documentation officielle pour les derniers numéros de version.

Connexion au store et récupération des articles

Initialisez un BillingClient et appelez startConnection pour commencer à communiquer avec le store. Utilisez queryProductDetailsAsync pour récupérer les détails des articles. Consultez la documentation officielle pour les détails.

Dans mon cas, récupérer des articles en masse ne fonctionnait pas pour une raison quelconque, donc j'ai d'abord récupéré la liste des articles puis utilisé queryProductDetailAsync pour obtenir les détails de chaque article individuellement. Si un article récupéré (SKU) est consommable ou un abonnement est déterminé par son type — inapp ou subs.

Construction de l'interface d'achat

Une fois que vous avez les détails des articles, affichez-les dans une liste afin que les utilisateurs puissent sélectionner ce qu'ils veulent acheter. Lors de la gestion des articles d'abonnement, vous devez vous conformer à la Politique des abonnements. Dans mon cas, l'application a été rejetée deux fois de suite pour :

  • Localisation incomplète du prix et des conditions
  • Descriptions de conditions d'offre manquantes

Sur le problème de localisation : le problème concernait la façon dont la période de facturation était affichée (ex. "$10/mois"). Quand l'application s'exécutait dans un paramètre régional pour une langue que je n'avais pas localisée, le mot "mois" n'était pas traduit. Le prix lui-même est correct — quand il est récupéré via BillingClient, vous obtenez formattedPrice comme une chaîne qui inclut les informations de devise, donc aucune traduction n'est nécessaire. Mais la période revient au format ISO 8601 (ex. P1M), et vous devez la traduire vous-même. J'ai géré cela avec une conversion par langue comme ceci :

fun formatBillingPeriod(billingPeriod: String, languageCode: String): String {
    return when(languageCode) {
        "en" -> {
            when (billingPeriod) {
                "P1W" -> "weekly"
                "P1M" -> "monthly"
                "P3M" -> "every 3 months"
                "P6M" -> "every 6 months"
                "P1Y" -> "annually"
                else -> "unknown"
            }
        }
        "ja" -> {
            when (billingPeriod) {
                "P1W" -> "週間"
                "P1M" -> "月額"
                "P3M" -> "3ヶ月ごと"
                "P6M" -> "6ヶ月ごと"
                "P1Y" -> "年額"
                else -> "不明"
            }
        }
        "fr" -> {
            when (billingPeriod) {
                "P1W" -> "hebdomadaire"
                "P1M" -> "mensuel"
                "P3M" -> "tous les 3 mois"
                "P6M" -> "tous les 6 mois"
                "P1Y" -> "annuel"
                else -> "inconnu"
            }
        }
        "es" -> {
            when (billingPeriod) {
                "P1W" -> "semanal"
                "P1M" -> "mensual"
                "P3M" -> "cada 3 meses"
                "P6M" -> "cada 6 meses"
                "P1Y" -> "anual"
                else -> "desconocido"
            }
        }
        "de" -> {
            when (billingPeriod) {
                "P1W" -> "wöchentlich"
                "P1M" -> "monatlich"
                "P3M" -> "alle 3 Monate"
                "P6M" -> "alle 6 Monate"
                "P1Y" -> "jährlich"
                else -> "unbekannt"
            }
        }
        else -> "unknown"
    }
}

Sur le problème des conditions d'offre :

Rejet d'abonnement montrant une violation des conditions d'offre Extrait de l'e-mail de rejet concernant la violation de la politique d'abonnement

Je comprenais le problème, mais je n'étais pas sûr des mots exacts à utiliser. Voici un extrait de l'e-mail de rejet réel :

Problème trouvé : Violation de la politique des abonnements

Votre application n'est pas conforme à la politique des abonnements.

  • Votre offre ne décrit pas clairement et précisément les conditions de votre offre d'essai ou tarif d'introduction, notamment quand un essai gratuit sera converti en abonnement payant, combien coûtera l'abonnement payant, et qu'un utilisateur peut annuler s'il ne veut pas passer à un abonnement payant.

Ma solution a été de regarder comment d'autres applications gèrent cela et d'emprunter leur formulation. Le langage est assez standard, donc suivre un précédent établi semblait plus intelligent que de le réinventer.

Déclenchement du flux d'achat

Une fois que les utilisateurs sélectionnent un article dans votre interface, lancez le flux d'achat pour cet article afin d'afficher l'écran d'achat réel.

Tests

Connectez-vous avec le compte de test que vous avez configuré précédemment pour effectuer des achats sans frais réels. Deux choses à garder à l'esprit :

  • Le flux d'achat doit s'exécuter sur le build d'application enregistré dans le store (pas un build de débogage)
  • Les intervalles de renouvellement des abonnements sont définis sur des durées courtes personnalisées pendant les tests

Les builds de débogage afficheront une erreur sur l'écran d'achat et ne compléteront pas le flux.

Pour les abonnements, quand vous procédez à l'écran d'achat, il affichera la carte de test. Mais l'intervalle de renouvellement affiché à l'écran ne correspondra pas à ce que vous avez réellement configuré — le mien affichait 5 minutes. Il semble que les abonnements soient toujours affichés avec un intervalle fixe extrêmement court à des fins de test. (J'ai passé un moment à croire que j'avais mal configuré quelque chose.)

Résumé

Les achats intégrés semblent intimidants au début, mais une fois que vous comprenez l'image globale, l'implémentation elle-même est étonnamment simple en utilisant la documentation officielle. Les abonnements ont des pièges cachés que vous ne connaîtrez pas avant de les rencontrer — j'espère que les problèmes que j'ai rencontrés vous feront gagner du temps.