Mapbox Unity : carte qui ne s’affiche pas sur Android (DllNotFoundException sqlite3)

Votre carte Mapbox fonctionne parfaitement dans l’éditeur Unity, mais dès que vous faites un build Android, plus rien ne s’affiche ? L’application se lance, la scène charge, mais la map reste désespérément vide ? Il y a de grandes chances que vous soyez face à un bug connu du Mapbox Unity SDK lié à la bibliothèque native SQLite3.

Chez Pixfeed, on a récemment résolu ce problème pour un client qui développait une application de géolocalisation sous Unity 2022.3 avec le SDK Mapbox. Tout fonctionnait en éditeur, mais le build Android refusait d’initialiser la carte. Après diagnostic, la cause était claire — et la correction tient en une seule ligne. On vous partage la méthode complète dans cet article.

Symptômes typiques
Le build Android se lance normalement, l’UI s’affiche, mais la carte Mapbox ne s’initialise jamais. La console Unity ou le debug text reste bloqué sur « InitAfterAccess START ». Ce comportement n’apparaît jamais dans l’éditeur Unity ni dans les builds Windows/macOS.

Pourquoi la carte Mapbox fonctionne dans l’éditeur mais pas sur Android

L’éditeur Unity fonctionne dans un environnement desktop classique où toutes les bibliothèques natives sont disponibles directement sur le système de fichiers. Quand vous lancez une scène avec le Mapbox SDK dans l’éditeur, le singleton MapboxAccess se crée, charge la configuration depuis les Resources, initialise le cache SQLite local et démarre le chargement des tuiles de carte. Tout ce processus est quasi instantané.

Sur Android, c’est une autre histoire. Le build empaquète l’application dans un APK ou un AAB, et les bibliothèques natives doivent être explicitement incluses pour chaque architecture cible (ARMv7, ARM64). Le Mapbox Unity SDK dépend de SQLite4Unity3d pour son système de cache disque. Si la bibliothèque native libsqlite3.so correspondant à l’architecture du device n’est pas présente dans le build, l’initialisation du SDK échoue — souvent sans aucun feedback visible dans l’UI, ce qui rend le problème difficile à diagnostiquer sans outillage.

Le problème est aggravé par le fait que la maintenance officielle du repo mapbox-unity-sdk s’est considérablement ralentie ces dernières années. Le SDK n’est plus aligné avec les évolutions récentes d’Unity et d’Android (IL2CPP, ARM64 obligatoire, API level 33+), et les correctifs pour ces plateformes ne sont pas intégrés dans les releases officielles.

Identifier la cause exacte avec un diagnostic embarqué

Avant de corriger quoi que ce soit, il faut confirmer que le problème vient bien de SQLite3. Voici la méthode qu’on utilise chez Pixfeed quand un client nous remonte ce type de bug : on modifie temporairement la coroutine d’initialisation dans AbstractMap.cs pour capturer et afficher l’exception directement sur l’écran du téléphone, sans avoir besoin de brancher un câble USB ni d’utiliser adb logcat.

Modifier AbstractMap.cs pour le diagnostic

Le fichier se trouve dans Assets/Mapbox/Unity/Map/AbstractMap.cs. Localisez la méthode InitAfterAccess et remplacez-la par cette version instrumentée. On utilise une fonction Log() locale pour centraliser l’écriture sur le debug text et garder le code lisible :

private IEnumerator InitAfterAccess()
{
    // Helper local pour afficher les messages de debug à l'écran
    System.Action Log = (string msg) =>
    {
        if (_debugText != null)
            _debugText.text += "\n" + msg;
    };

    Log("InitAfterAccess START");

    MapboxAccess access = null;
    try
    {
        access = MapboxAccess.Instance;
        Log("Instance OK");
    }
    catch (Exception ex)
    {
        Log("ERROR Instance: " + ex.GetType().Name + " - " + ex.Message);
        yield break;
    }

    float timeout = 10f;
    float elapsed = 0f;
    while (access == null
        || access.Configuration == null
        || string.IsNullOrEmpty(access.Configuration.AccessToken))
    {
        elapsed += Time.deltaTime;
        if (elapsed > timeout)
        {
            Log("TIMEOUT: Config not loaded after " + timeout + "s");
            yield break;
        }
        yield return null;
    }

    Log("Mapbox config OK");

    _fileSource = access;
    yield return null;
    yield return null;

    if (_initializeOnStart)
    {
        try
        {
            SetUpMap();
        }
        catch (Exception ex)
        {
            Log("ERROR SetUpMap: " + ex.GetType().Name + " - " + ex.Message);
        }
    }
}

Assurez-vous d’avoir un composant TextMeshProUGUI référencé dans le champ _debugText de votre AbstractMap pour voir les messages à l’écran. Faites un build Android, lancez l’app sur le device, et lisez le message d’erreur.

Le message d’erreur attendu

Si le problème vient de SQLite3, vous verrez ce message sur l’écran :

InitAfterAccess START
ERROR Instance:
DllNotFoundException - Unable to load DLL 'sqlite3'.
Tried to load the following dynamic libraries:
Unable to load dynamic library 'sqlite3' because of
'Failed to open the requested dynamic library (0x06000000)
dlerror() = dlopen failed: library "sqlite3" not found

Ce message confirme que le singleton MapboxAccess échoue dans son constructeur quand il tente de créer un cache SQLite pour stocker les tuiles de carte localement. Le problème n’a rien à voir avec votre clé API, vos permissions Android ou votre code applicatif.

Comprendre le mécanisme technique

Pour bien saisir pourquoi ce bug survient, il faut comprendre la chaîne d’initialisation du SDK. Quand votre scène Unity démarre, AbstractMap.Start() lance une coroutine qui appelle MapboxAccess.Instance. Ce getter crée le singleton via un constructeur privé qui enchaîne les étapes suivantes :

LoadAccessToken() charge la configuration JSON depuis les Resources Unity, puis SetConfiguration() appelle ConfigureFileSource(). C’est dans cette dernière méthode que tout se joue. Voici le code original dans MapboxAccess.cs, situé dans Assets/Mapbox/Unity/ :

void ConfigureFileSource()
{
    _fileSource = new CachingWebFileSource(
        _configuration.AccessToken,
        _configuration.GetMapsSkuToken,
        _configuration.AutoRefreshCache)
        .AddCache(new MemoryCache(_configuration.MemoryCacheSize))
#if !UNITY_WEBGL
        .AddCache(new SQLiteCache(_configuration.FileCacheSize))
#endif
        ;
}

La directive #if !UNITY_WEBGL exclut le cache SQLite uniquement pour les builds WebGL. Mais sur Android, la condition est vraie, donc le SDK tente de créer un SQLiteCache. Cette classe utilise SQLite4Unity3d qui nécessite la bibliothèque native libsqlite3.so compilée pour l’architecture ARM du device.

Historiquement, le SDK Mapbox incluait ces binaires dans Assets/Mapbox/Core/Plugins/sqlite/Android/libs/. Mais selon les versions et les configurations de build, ces fichiers peuvent ne pas être correctement packagés dans l’APK, en particulier avec IL2CPP et ARM64, deux paramètres devenus obligatoires pour publier sur le Google Play Store.

La solution : désactiver SQLiteCache sur Android

C’est le fix le plus stable pour débloquer rapidement un build Android. On l’a appliqué chez Pixfeed pour notre client, et il fonctionne sur toutes les versions du SDK Mapbox Unity testées (1.4.x à 2.1.x). Il suffit d’ajouter !UNITY_ANDROID à la directive de compilation conditionnelle dans MapboxAccess.cs pour exclure le cache SQLite des builds Android :

void ConfigureFileSource()
{
    _fileSource = new CachingWebFileSource(
        _configuration.AccessToken,
        _configuration.GetMapsSkuToken,
        _configuration.AutoRefreshCache)
        .AddCache(new MemoryCache(_configuration.MemoryCacheSize))
#if !UNITY_WEBGL && !UNITY_ANDROID
        .AddCache(new SQLiteCache(_configuration.FileCacheSize))
#endif
        ;
}

La seule ligne qui change est la directive de préprocesseur, passant de #if !UNITY_WEBGL à #if !UNITY_WEBGL && !UNITY_ANDROID. Si votre application a besoin du cache offline (cartes volumineuses, usage hors connexion), passez plutôt à la solution alternative décrite plus bas qui consiste à inclure libsqlite3.so dans le build.

Pourquoi ce fix fonctionne

Trois choses à retenir pour comprendre pourquoi cette correction est fiable et pas un simple bricolage :

Le cache SQLite est optionnel dans l’architecture du SDK Mapbox. Il sert uniquement à persister les tuiles de carte sur le disque entre les sessions. Le MemoryCache, lui, reste actif dans tous les cas et assure le fonctionnement normal de la carte pendant l’exécution de l’application.

Mapbox a d’ailleurs déjà appliqué cette logique pour WebGL avec #if !UNITY_WEBGL. On étend simplement cette exclusion à Android, où la combinaison IL2CPP + bibliothèques natives ARM représente un point de friction connu et documenté dans les issues du SDK.

Impact sur les performances
En pratique, l’impact est négligeable pour la majorité des applications. Les tuiles se rechargent depuis le réseau au prochain lancement, ce qui est transparent pour l’utilisateur. Seuls les cas d’usage offline ou les applications avec des cartes très volumineuses nécessitent le cache disque — et pour ceux-là, la solution alternative avec libsqlite3.so est plus adaptée.

Étapes de la correction

1

Ouvrir MapboxAccess.cs

Naviguez vers Assets/Mapbox/Unity/MapboxAccess.cs dans votre projet Unity.

2

Modifier la directive de compilation

Trouvez la ligne #if !UNITY_WEBGL dans la méthode ConfigureFileSource et remplacez-la par #if !UNITY_WEBGL && !UNITY_ANDROID.

3

Rebuild Android

Faites un nouveau build Android depuis Unity (File → Build Settings → Build).

4

Tester sur device

Installez l’APK sur votre appareil Android et vérifiez que la carte s’affiche correctement.

Retour arrière et nettoyage

Une fois le fix validé sur device, pensez à remettre votre projet au propre :

Remettez AbstractMap.cs d’origine. Le code de diagnostic n’a pas vocation à rester en production. Si vous avez utilisé la version instrumentée décrite plus haut, replacez le fichier original ou supprimez la fonction Log() et les blocs try-catch ajoutés.

Retirez le debug text de votre UI. Si vous avez ajouté un TextMeshProUGUI pour afficher les messages de diagnostic, retirez-le de votre scène ou désactivez le GameObject avant de publier.

Conservez uniquement la modification de MapboxAccess.cs. C’est le seul fichier qui doit rester modifié dans votre projet.

Solution alternative : inclure la bibliothèque native sqlite3

Si vous avez besoin du cache disque sur Android (applications hors-ligne, cartes volumineuses), vous pouvez résoudre le problème en incluant les binaires SQLite3 compilés pour ARM64 dans votre projet. La communauté a documenté cette approche dans l’issue #1331 du SDK Mapbox Unity :

La procédure consiste à placer le fichier libsqlite3.so compilé pour ARM64 dans Assets/Mapbox/Plugins/Android/libs/arm64-v8a/, puis à configurer les import settings dans Unity (Platform: Android, CPU: ARM64). Cependant, cette approche nécessite de maintenir les binaires à jour et de les compiler pour chaque architecture cible, ce qui ajoute de la complexité au projet.

Autres causes possibles de carte noire sur Android

Si le diagnostic ne montre pas l’erreur SQLite3, voici les autres causes fréquentes de carte Mapbox qui ne s’affiche pas sur Android :

Permissions Android manquantes. Vérifiez que votre AndroidManifest.xml contient les permissions ACCESS_FINE_LOCATION, ACCESS_COARSE_LOCATION et INTERNET. Sans la permission réseau, le SDK ne peut pas télécharger les tuiles de carte depuis les serveurs Mapbox.

Clé API non autorisée pour Android. Dans la console Mapbox, vérifiez que votre token n’est pas restreint à certaines plateformes. Un token configuré uniquement pour le web ne fonctionnera pas dans un build mobile.

Conflit d’architecture ARM. Si vous ciblez uniquement ARMv7 alors que le device est ARM64 (ou inversement), certaines bibliothèques natives peuvent ne pas se charger. Vérifiez vos Target Architectures dans Player Settings → Other Settings.

Proguard / R8 qui supprime des classes. Si vous utilisez la minification de code dans votre build Android, le compilateur peut supprimer des classes du SDK Mapbox qu’il considère inutilisées. Ajoutez des règles de keep dans votre fichier proguard-user.txt pour les packages Mapbox.

Style de carte invalide ou inaccessible. Si votre style Mapbox référence des sources ou des sprites hébergées sur un domaine personnalisé non atteignable depuis le device, la carte peut rester vide même si le SDK s’initialise correctement. Testez d’abord avec un style par défaut (mapbox://styles/mapbox/streets-v11).

Pipeline de rendu incompatible. Sur Unity 2021+ avec URP ou HDRP, certains shaders utilisés par le SDK Mapbox peuvent ne pas fonctionner correctement. Vérifiez que le matériau de la carte utilise un shader compatible avec votre pipeline de rendu.

Le bug SQLite3 peut aussi survenir sur iOS dans certaines configurations. Si c’est le cas, vous pouvez adapter la directive en #if !UNITY_WEBGL && !UNITY_ANDROID && !UNITY_IOS. Cependant, iOS inclut généralement SQLite nativement, donc le problème est moins fréquent.

Oui, la directive de préprocesseur est une fonctionnalité standard de C# et Unity. Elle fonctionne identiquement sur Unity 2020 LTS, 2021 LTS, 2022 LTS et Unity 6.

Non. La modification de AbstractMap.cs décrite dans cet article est uniquement un outil de diagnostic. Une fois le problème identifié et corrigé dans MapboxAccess.cs, vous pouvez remettre le fichier AbstractMap.cs original.

La maintenance officielle du repo s’est considérablement ralentie et il n’est plus aligné avec les plateformes mobiles modernes. Pour les nouveaux projets, évaluez des alternatives comme le Mapbox Maps SDK for Android natif ou des solutions comme Google Maps SDK for Unity. Pour les projets existants, le SDK reste fonctionnel avec les corrections décrites dans cet article.

Un bug bloque votre build Android ?
Chez Pixfeed, on diagnostique et on corrige vos problèmes Unity, Mapbox et intégrations SDK en 24-48h. Forfait fixe, pas de surprise.
Nous contacter