Retour au Blog

Godot Android Build Environment (GABE) : compiler et exporter des jeux sans PC

Publié le 3 juin 2026
Godot Android Build Environment (GABE) : compiler et exporter des jeux sans PC

En bref

Cet article présente GABE (Godot Android Build Environment), un outil permettant de compiler et d'exporter des jeux mobiles directement sur les appareils Android et les casques XR sans recourir à un PC. Il explique le fonctionnement technique de ce compilateur sandboxé, les défis matériels liés au thermal throttling et à la gestion de la mémoire sous ARM, ainsi que l'intérêt d'utiliser un backend cloud managé comme horizOn pour le développement multiplayer. Enfin, un guide pas à pas et un exemple de script GDScript illustrent la mise en place d'un pipeline de build autonome de bout en bout.

Chaque développeur indépendant connaît la frustration liée au développement d'un jeu mobile pour s'apercevoir que le simple test d'un plugin Android ou d'une intégration Google Play Services oblige à repasser sur PC. Jusqu'à récemment, les utilisateurs de Godot pouvaient concevoir leurs scènes et écrire leur logique sur des appareils Android, mais compiler un build Gradle personnalisé avec du code natif nécessitait une station de travail complète. La sortie de GABE (Godot Android Build Environment) résout ce problème de friction en fournissant un environnement de compilation stable et autonome qui s'exécute directement sur les appareils Android et les casques XR.

Le piège de la dépendance au PC dans le développement de jeux mobiles

Développer des jeux directement sur les plateformes mobiles et XR est une tendance forte, en particulier pour les créateurs solo et les développeurs nomades. Cependant, le principal goulot d'étranglement a toujours été la compilation et le packaging. Sans support de custom build, les développeurs doivent s'appuyer sur des templates d'export pré-compilés. Ces templates sont des APK pré-construits qui intègrent le package d'assets de votre jeu (.pck ou .zip) et signent le fichier, ce qui fonctionne très bien pour les projets basiques mais échoue immédiatement dès que vous avez besoin d'intégrations natives sur la plateforme.

Si votre projet nécessite Google Play Billing, des canaux de notification personnalisés ou des intégrations poussées du Quest SDK, vous devez utiliser Gradle. Activer l'option « Use Gradle Build » dans Godot force le moteur à télécharger, configurer et compiler les classes Java ou Kotlin Android à partir des sources. Avant GABE, cela était impossible car l'éditeur ne disposait pas de l'environnement requis pour récupérer les outils de build, exécuter les tâches JDK et lier les bibliothèques natives (fichiers .aar) directement sur l'appareil. Les développeurs devaient donc obligatoirement repasser sur un PC pour générer le build final.

Cette dépendance au PC introduit également une friction importante dans le pipeline de développement. Lorsqu'un développeur modifie une ligne de code dans un plugin natif, il doit copier le projet sur une machine de bureau, lancer une synchronisation Gradle complète, compiler, transférer à nouveau l'APK sur l'appareil mobile et l'installer. Cette boucle peut facilement transformer une simple correction de logique de 30 secondes en un casse-tête de compilation et de transfert de 10 minutes. GABE élimine ce cycle en permettant aux développeurs de gérer l'intégralité du pipeline de compilation localement sur leur matériel mobile.

Sous le capot de GABE : IPC, sockets et compilation sandboxée

GABE fonctionne comme un processus daemon en arrière-plan, distinct de l'éditeur Godot principal. Cette isolation est un choix de conception critique imposé par le modèle strict de sandboxing d'Android. Une application Android unique ne peut pas facilement exécuter un compilateur Gradle headless, héberger un environnement OpenJDK et lancer des commandes de link natif sans violer les paramètres de sécurité ou dépasser les limites de mémoire allouée. GABE agit comme une application d'assistance dédiée qui contient les bibliothèques de compilation nécessaires et exécute les tâches de compilation dans un sandbox séparé.

Lorsque vous déclenchez un export personnalisé dans l'éditeur Godot sur Android ou Quest, l'éditeur initie une connexion IPC avec GABE via un port de loopback local ou l'interface Binder d'Android. Godot sérialise les propriétés d'export — comme les versions cibles du SDK, les configurations de build et les chemins des keystores — et les transmet à GABE. L'application compagnon prend alors le contrôle du pipeline de build, gérant la résolution des dépendances, la gestion du SDK, la compilation et la signature. Cela permet d'isoler de l'interface de l'éditeur le pipeline de build, qui est très gourmand en ressources.

Avec cette version stable, GABE passe du statut d'outil alpha expérimental, sujet aux déconnexions de sockets et aux crashs de résolution de chemins, à celui de compilateur prêt pour la production. Les comparaisons de versions montrent que la version stable réduit les échecs de handshake de tâches de plus de 95 % et prend entièrement en charge les plugins personnalisés avec Gradle 8.x, garantissant la compatibilité avec les dernières normes de Play Asset Delivery. Concrètement, cela signifie que vous pouvez générer vos APK de release directement sur un Meta Quest 3 ou un appareil Android, les signer et les uploader sur les stores sans avoir besoin d'un PC comme passerelle.

Étant donné que GABE maintient un daemon Gradle actif en arrière-plan, les builds suivants sont nettement plus rapides. Alors que la première compilation doit télécharger les dépendances et compiler toutes les classes à partir de zéro, les builds incrémentaux réutilisent les classes en cache, réduisant le temps de compilation de plusieurs minutes à quelques secondes.

Guide détaillé : Mettre en place un pipeline d'export mobile complet

Configurer un pipeline de build mobile local nécessite de paramétrer correctement le partage d'accès aux répertoires entre Godot et GABE. Sans des chemins d'accès correctement configurés, GABE ne parviendra pas à localiser les fichiers de votre projet ou à écrire l'APK final en raison des restrictions de scoped storage d'Android.

Étape 1 : Installer GABE et configurer le stockage

Tout d'abord, installez le client GABE stable depuis le Google Play Store ou le Meta Horizon Store sur votre appareil cible. Lorsque vous lancez GABE pour la première fois, il vous demandera les autorisations d'accès aux dossiers. Vous devez accorder à GABE l'accès au répertoire où sont stockés vos projets Godot (par exemple, /Documents/GodotProjects/). Cette étape est essentielle ; si GABE ne peut pas lire les fichiers sources du projet, il ne pourra pas compiler les templates Gradle.

Étape 2 : Configurer les paramètres d'export de l'éditeur Godot

Ouvrez votre projet dans l'éditeur Godot sur Android et allez dans Projet > Exporter. Ajoutez une configuration d'export Android et paramétrez les éléments nécessaires. Cochez l'option « Use Custom Build » pour générer un wrapper Gradle plutôt que d'utiliser le template pré-compilé par défaut. Assurez-vous que le chemin d'export cible correspond au répertoire auquel vous avez autorisé GABE à accéder, et pointez vers vos fichiers .debug.keystore ou vos keystores de release.

Étape 3 : Lancer l'export et surveiller les logs

Cliquez sur « Exporter le projet » et sélectionnez la destination. Godot va automatiquement transmettre la requête de build à GABE. La console de l'éditeur Godot affichera la sortie du build de GABE en temps réel. Vous pouvez observer l'exécution des tâches Gradle, ce qui vous permet de repérer immédiatement les erreurs de syntaxe ou les problèmes de dépendances sans avoir à consulter des logs système externes.

Connecter les plugins Android natifs à GDScript

Une fois que GABE gère vos exports Gradle, vous pouvez exploiter des plugins Android natifs directement dans le code de votre jeu. L'exemple GDScript suivant présente un wrapper prêt pour la production permettant d'interagir avec un plugin natif Google Play Billing. Il intègre des vérifications conditionnelles pour gérer l'exécution au sein de l'éditeur PC et prend en charge les callbacks asynchrones requis par les API de la plateforme Android.

# plugin_manager.gd
extends Node

signal purchase_completed(item_id: String, token: String)
signal purchase_failed(error_message: String)

var _billing_plugin: Object = null
const PLUGIN_NAME = "GodotGooglePlayBilling"

func _ready() -> void:
    _initialize_billing_plugin()

func _initialize_billing_plugin() -> void:
    # Check if the engine is running on Android and has the native singleton
    if Engine.has_singleton(PLUGIN_NAME):
        _billing_plugin = Engine.get_singleton(PLUGIN_NAME)
        
        # Connect Android native callbacks to GDScript functions
        _billing_plugin.connect("connected", Callable(self, "_on_billing_connected"))
        _billing_plugin.connect("disconnected", Callable(self, "_on_billing_disconnected"))
        _billing_plugin.connect("purchases_updated", Callable(self, "_on_purchases_updated"))
        _billing_plugin.connect("purchase_error", Callable(self, "_on_purchase_error"))
        
        # Start the billing connection
        _billing_plugin.startConnection()
        print("GABE Build verified: Native billing plugin loaded successfully.")
    else:
        # Fallback for PC editor debugging or non-Gradle exports
        print("Billing plugin not found. Running in mock/sandbox environment.")
        _billing_plugin = null

func purchase_item(item_id: String) -> void:
    if _billing_plugin:
        var sku_details = {
            "sku": item_id,
            "type": "inapp"
        }
        # In Godot 4.x, interacting with native Java arrays/dictionaries requires strict type mapping
        var query_result = _billing_plugin.querySkuDetails([item_id], "inapp")
        if query_result == 0: # OK code
            _billing_plugin.purchase(item_id)
        else:
            emit_signal("purchase_failed", "Failed to query item details from Google Play.")
    else:
        # Mock purchase behavior for local testing
        await get_tree().create_timer(1.0).timeout
        emit_signal("purchase_completed", item_id, "mock_token_12345_no_pc")

func _on_purchases_updated(purchases: Array) -> void:
    for purchase in purchases:
        if purchase.purchase_state == 1: # PURCHASED state
            # Acknowledge the purchase or consume it (mandatory in Google Play Billing Library v5+)
            if not purchase.is_acknowledged:
                _billing_plugin.acknowledgePurchase(purchase.purchase_token)
            emit_signal("purchase_completed", purchase.sku, purchase.purchase_token)

func _on_purchase_error(code: int, message: String) -> void:
    emit_signal("purchase_failed", "Billing error " + str(code) + ": " + message)

func _on_billing_connected() -> void:
    print("Successfully connected to Google Play Billing Service.")

func _on_billing_disconnected() -> void:
    print("Disconnected from Google Play Billing Service. Retrying connection...")

Ce wrapper garantit que votre code ne plantera pas lors du débogage dans le viewport standard de l'éditeur ou sur les plateformes où les API Android natives ne sont pas disponibles. En séparant la logique, vous pouvez concevoir et tester l'interface utilisateur en toute sécurité sur n'importe quel appareil, tout en réservant les intégrations natives complètes aux exports compilés via GABE. Cette architecture s'appuie sur un mapping explicite des signaux pour gérer la nature dynamique des processus de facturation mobile.

La réalité matérielle : thermal throttling et consommation des ressources sur ARM

Compiler des jeux entièrement sur des appareils Android introduit de sérieux goulots d'étranglement matériels qui n'existent pas sur les PC de bureau. Comprendre ces limites physiques vous aidera à optimiser vos builds et à éviter les crashs.

Charges de travail CPU soutenues et thermal throttling

Les processeurs mobiles modernes (comme les Snapdragon 8 Gen 2 ou Gen 3) utilisent une architecture CPU hétérogène (ARM big.LITTLE). Ils se composent de quelques cœurs haute performance conçus pour de courtes rafales de puissance, et de plusieurs cœurs à haute efficacité énergétique. La compilation est une tâche soutenue, hautement parallèle et multithreadée qui sollicite tous les cœurs de performance à 100 % de leurs capacités.

En l'espace de 60 à 90 secondes sur un build lourd, le contrôleur thermique de l'appareil va réduire la fréquence d'horloge des cœurs de performance (souvent de 40 % ou plus) pour éviter la surchauffe. Cela entraîne une chute de la vitesse de compilation. Un build qui prend 45 secondes à froid peut facilement dépasser les 3 minutes s'il est lancé juste après une compilation précédente.

Contraintes de stockage et de mémoire

Gradle est connu pour être extrêmement gourmand en ressources ; il lance un daemon en arrière-plan qui conserve les fichiers en cache dans la mémoire RAM. Sur un appareil équipé de 8 Go de RAM, exécuter simultanément Godot et GABE peut pousser l'OOM (Out-Of-Memory) killer d'Android à tuer l'un des processus. Pour éviter cela, vous devez limiter l'empreinte mémoire de Gradle en configurant le fichier gradle.properties (par exemple, en limitant le tas max à 2 Go).

De plus, le cache de dépendances de Gradle (.gradle/caches) et les outils de build du SDK peuvent rapidement saturer le stockage. Un projet simple avec quelques plugins natifs peut facilement occuper 3 à 5 Go d'espace disque. Si votre appareil a des cycles d'écriture limités ou peu d'espace libre, la vitesse de compilation ralentira considérablement en raison de temps d'attente I/O élevés.

Combler le fossé du backend : développer des systèmes multiplayer sans serveurs locaux

Développer entièrement sur un téléphone Android ou un casque XR résout le problème de l'édition côté client, mais cela introduit un problème d'architecture majeur : comment exécuter et tester votre backend ? Sur un ordinateur de bureau, les développeurs exécutent généralement une stack backend locale via Docker Compose, hébergent une instance locale PostgreSQL, lancent un cache Redis et déploient leurs serveurs de jeu backend. Sur Android, vous ne pouvez pas exécuter Docker, et faire tourner plusieurs bases de données de serveurs en arrière-plan est bloqué par les politiques de sécurité du noyau du système d'exploitation et les limites de mémoire.

Si vous tentez de build et d'exécuter votre backend manuellement, le processus est extrêmement fastidieux. Vous devez acheter et configurer un serveur privé virtuel (VPS) distant, configurer des reverse proxies et écrire des scripts shell pour déployer le code via SSH depuis votre terminal mobile. De plus, chaque modification du schéma de base de données nécessite des migrations manuelles exécutées via des connexions internet mobiles instables. Ce processus de configuration ajoute facilement 4 à 6 semaines de tâches d'infrastructure avant même de pouvoir écrire la moindre ligne de code de jeu.

C'est ici qu'un Backend-as-a-Service managé devient un outil indispensable pour votre pipeline mobile. Au lieu de configurer et de gérer des VM Linux distantes, horizOn fournit un backend pré-configuré qui s'intègre directement dans le workflow de Godot. Les fonctionnalités de jeu courantes — comme l'authentification utilisateur, les sauvegardes cloud multiplateformes, les configurations distantes et les leaderboards en temps réel — sont entièrement gérées dans le cloud.

En intégrant leur SDK dans votre projet Godot, votre client de jeu se connecte directement aux endpoints d'un backend serverless. Cette architecture vous permet de tester les états de connexion, de synchroniser les profils des joueurs et de récupérer les données des leaderboards directement au sein de vos builds compilés par GABE. Cela rend possible un cycle de vie de développement de jeu complet et professionnel entièrement depuis un appareil mobile ou un casque VR, sans avoir à gérer le moindre serveur.

Best practices pour le développement Godot sans PC

Pour maintenir un workflow productif lors du développement de jeux sans PC de bureau, suivez ces recommandations d'optimisation :

  1. Limiter l'empreinte mémoire du daemon Gradle : Ajoutez org.gradle.jvmargs=-Xmx2048m -XX:MaxMetaspaceSize=512m au fichier gradle.properties personnalisé de votre projet. Cela empêche le gestionnaire de mémoire d'Android de tuer Godot ou GABE lors de grosses compilations.
  2. Utiliser le mock local pour l'itération de la logique : Ne lancez des builds Gradle avec GABE que lors du test de plugins natifs ou de la préparation des packages de release. Pour le scripting quotidien de la logique de jeu, utilisez des configurations de mock pour exécuter le jeu instantanément via le player intégré de l'éditeur Godot.
  3. Garder le stockage interne propre : Accédez régulièrement au répertoire de votre projet et supprimez les dossiers temporaires .godot/ et de build Gradle. Vider ces caches une fois par semaine permet de libérer plusieurs gigaoctets d'espace et de résoudre d'obscurs bugs de cache de compilation.
  4. Tirer parti des services managés : Évitez d'écrire des connecteurs de base de données ou des boucles de serveurs personnalisés. Intégrez des services de plateforme managés pour garder le code d'intégration côté client simple et rapide à compiler.
  5. Désactiver le multi-dexing si non nécessaire : Si votre jeu ne dépasse pas la limite des 64 000 méthodes, désactivez le multi-dexing dans vos fichiers de build. Cela réduit la surcharge de compilation et diminue la taille des packages en évitant la création de fichiers classes.dex auxiliaires.

L'utilisation de GABE pour compiler votre projet vous donne un contrôle total sur les intégrations natives de votre jeu Android. En combinant la compilation locale avec un backend cloud managé, vous pouvez passer du prototype à une publication complète sur les stores sans jamais avoir besoin de démarrer un PC.

Prêt à scaler votre backend multiplayer ? Essayez horizOn gratuitement ou consultez les docs de l'API.


Source : Creating games entirely on Android!