Share via


Conseils de dépannage

Obtention d’informations de diagnostic

Xamarin.Android a quelques endroits à regarder lors du suivi de divers bogues. Il s’agit notamment des paramètres suivants :

  1. Sortie MSBuild de diagnostic.
  2. Journaux de déploiement d’appareils.
  3. Sortie du journal de débogage Android.

Sortie MSBuild de diagnostic

MsBuild de diagnostic peut contenir des informations supplémentaires relatives à la génération de packages et peut contenir des informations de déploiement de package.

Pour activer la sortie MSBuild de diagnostic dans Visual Studio :

  1. Cliquez sur Options des outils > ...
  2. Dans l’arborescence de gauche, sélectionnez Projets et Solutions > Générer et Exécuter
  3. Dans le panneau de droite, définissez la liste déroulante détaillée de sortie de build MSBuild sur Diagnostic
  4. Cliquez sur OK.
  5. Nettoyez et regénérez votre package.
  6. La sortie de diagnostic est visible dans le panneau Sortie.

Pour activer la sortie MSBuild de diagnostic dans Visual Studio pour Mac/OS X :

  1. Cliquez sur Visual Studio pour Mac > Préférences...
  2. Dans l’arborescence de gauche, sélectionnez Projects > Build
  3. Dans le volet de droite, définissez la liste déroulante Détail du journal sur Diagnostic
  4. Cliquez sur OK.
  5. Redémarrer Visual Studio pour Mac
  6. Nettoyez et regénérez votre package.
  7. La sortie de diagnostic est visible dans le panneau Erreurs (Afficher les erreurs de remplissage), > en cliquant sur le bouton > Générer la sortie.

Journaux de déploiement d’appareils

Pour activer la journalisation du déploiement d’appareils dans Visual Studio :

  1. Options des outils > ...>
  2. Dans l’arborescence de gauche, sélectionnez Xamarin > Android Paramètres
  3. Dans le panneau de droite, activez la zone de journalisation de débogage de l’extension [X] (écrit monodroid.log sur votre bureau) case activée.
  4. Les messages de journal sont écrits dans le fichier monodroid.log sur votre bureau.

Visual Studio pour Mac écrit toujours les journaux de déploiement d’appareils. Les induisants sont légèrement plus difficiles ; Un fichier journal AndroidUtils est créé pour chaque jour + heure qu’un déploiement se produit, par exemple : AndroidTools-2012-10-24_12-35-45.log.

  • Sur Windows, les fichiers journaux sont écrits dans %LOCALAPPDATA%\XamarinStudio-{VERSION}\Logs.
  • Sur OS X, les fichiers journaux sont écrits dans $HOME/Library/Logs/XamarinStudio-{VERSION}.

Sortie du journal de débogage Android

Android écrit de nombreux messages dans le journal de débogage Android. Xamarin.Android utilise les propriétés système Android pour contrôler la génération de messages supplémentaires dans le journal de débogage Android. Les propriétés système Android peuvent être définies via la commande setprop dans le pont de débogage Android (adb) :

adb shell setprop PROPERTY_NAME PROPERTY_VALUE

Les propriétés système sont lues au démarrage du processus et doivent donc être définies avant le lancement de l’application ou l’application doit être redémarrée une fois les propriétés système modifiées.

Propriétés système de Xamarin.Android

Xamarin.Android prend en charge les propriétés système suivantes :

  • debug.mono.debug : si une chaîne non vide équivaut à *mono-debug*.

  • debug.mono.env : liste de variables d’environnement séparées par un canal (''|) à exporter au démarrage de l’application, avant l’initialisation de mono. Cela permet de définir des variables d’environnement qui contrôlent la journalisation mono.

    Remarque

    Étant donné que la valeur est «| séparée », la valeur doit avoir un niveau supplémentaire de guillemets, car la commande « adb shell » supprime un ensemble de guillemets.

    Remarque

    Les valeurs des propriétés système Android ne peuvent pas dépasser 92 caractères.

    Exemple :

    adb shell setprop debug.mono.env "'MONO_LOG_LEVEL=info|MONO_LOG_MASK=asm'"
    
  • debug.mono.log : liste de composants séparés par des virgules (',') qui doivent imprimer des messages supplémentaires dans le journal de débogage Android. Par défaut, rien n’est défini. Les composants sont les suivants :

    • all : Imprimer tous les messages
    • gc : Imprimer des messages liés au GC.
    • gref : Imprimer (faible, global) les messages d’allocation de référence et de désallocation.
    • lref : Imprimer les messages d’allocation de référence locale et de désallocation.

    Remarque

    Elles sont extrêmement détaillées. N’activez pas, sauf si vous avez vraiment besoin de.

  • debug.mono.trace : autorise la définition du paramètre mono-trace=PROPERTY_VALUE .

Suppression et suppression binobj

Xamarin.Android a souffert par le passé d’une situation telle que :

  • Vous rencontrez une erreur de build ou d’exécution étrange.
  • Vous Clean, Rebuildou supprimez manuellement vos répertoires et obj vos bin répertoires.
  • Le problème va disparaître.

Nous sommes fortement investis dans la résolution des problèmes tels que ceux-ci en raison de leur impact sur la productivité des développeurs.

Si un problème tel que celui-ci se produit :

  1. Prenez une note mentale. Quelle a été la dernière action qui a fait entrer votre projet dans cet état ?
  2. Enregistrez votre journal de build actuel. Réessayez de générer, puis enregistrez un journal de génération de diagnostic.
  3. Envoyez un rapport de bogue.

Avant de supprimer vos répertoires et obj vos bin répertoires, compressez-les et enregistrez-les pour un diagnostic ultérieur si nécessaire. Vous pouvez probablement simplement utiliser Clean votre projet d’application Xamarin.Android pour que les choses fonctionnent à nouveau.

Xamarin.Android ne peut pas résoudre System.ValueTuple

Cette erreur se produit en raison d’une incompatibilité avec Visual Studio.

  • Visual Studio 2017 Update 1 (version 15.1 ou antérieure) est compatible uniquement avec System.ValueTuple NuGet 4.3.0 (ou version antérieure).

  • Visual Studio 2017 Update 2 (version 15.2 ou ultérieure) est compatible uniquement avec System.ValueTuple NuGet 4.3.1 (ou version ultérieure).

Choisissez le fichier NuGet System.ValueTuple approprié qui correspond à votre installation de Visual Studio 2017.

GC Messages

Les messages de composant GC peuvent être affichés en définissant la propriété système debug.mono.log sur une valeur qui contient gc.

Les messages GC sont générés chaque fois que le GC s’exécute et fournit des informations sur le travail effectué par le GC :

I/monodroid-gc(12331): GC cleanup summary: 81 objects tested - resurrecting 21.

Des informations gc supplémentaires telles que les informations de minutage peuvent être générées en définissant la variable d’environnement MONO_LOG_LEVEL sur debug:

adb shell setprop debug.mono.env MONO_LOG_LEVEL=debug

Cela entraîne (beaucoup de) messages Mono supplémentaires, y compris ces trois conséquences :

D/Mono (15723): GC_BRIDGE num-objects 1 num_hash_entries 81226 sccs size 81223 init 0.00ms df1 285.36ms sort 38.56ms dfs2 50.04ms setup-cb 9.95ms free-data 106.54ms user-cb 20.12ms clenanup 0.05ms links 5523436/5523436/5523096/1 dfs passes 1104 6883/11046605
D/Mono (15723): GC_MINOR: (Nursery full) pause 2.01ms, total 287.45ms, bridge 225.60 promoted 0K major 325184K los 1816K
D/Mono ( 2073): GC_MAJOR: (user request) pause 2.17ms, total 2.47ms, bridge 28.77 major 576K/576K los 0K/16K

Dans le GC_BRIDGE message, num-objects est le nombre d’objets pont que cette passe prend en compte et num_hash_entries est le nombre d’objets traités pendant cet appel du code de pont.

Dans les GC_MINOR messages et GC_MAJOR les messages, total est la durée pendant laquelle le monde est suspendu (aucun thread n’est en cours d’exécution), tandis que bridge le temps nécessaire au code de traitement de pont (qui traite de la machine virtuelle Java). Le monde n’est pas suspendu pendant que le traitement des ponts se produit.

En règle générale, plus la valeur num_hash_entriesest élevée, plus le bridge temps nécessaire aux collections et plus le total temps consacré à la collecte sera élevé.

Messages de référence globaux

Pour activer la journalisation gref (Global Reference loling), la propriété système debug.mono.log doit contenir gref, par exemple :

adb shell setprop debug.mono.log gref

Xamarin.Android utilise des références globales Android pour fournir des mappages entre les instances Java et les instances managées associées, comme lors de l’appel d’une méthode Java, une instance Java doit être fournie à Java.

Malheureusement, les émulateurs Android autorisent uniquement les références globales 2000 à exister à la fois. Le matériel a une limite beaucoup plus élevée de 52000 références globales. La limite inférieure peut être problématique lors de l’exécution d’applications sur l’émulateur, de sorte que savoir l’instance provient peut être très utile.

Remarque

Le nombre de références globales est interne à Xamarin.Android et n’inclut pas (et ne peut pas) inclure des références globales extraites par d’autres bibliothèques natives chargées dans le processus. Utilisez le nombre de références globales comme estimation.

I/monodroid-gref(12405): +g+ grefc 108 gwrefc 0 obj-handle 0x40517468/L -> new-handle 0x40517468/L from    at Java.Lang.Object.RegisterInstance(IJavaObject instance, IntPtr value, JniHandleOwnership transfer)
I/monodroid-gref(12405):    at Java.Lang.Object.SetHandle(IntPtr value, JniHandleOwnership transfer)
I/monodroid-gref(12405):    at Java.Lang.Object..ctor(IntPtr handle, JniHandleOwnership transfer)
I/monodroid-gref(12405):    at Java.Lang.Thread+RunnableImplementor..ctor(System.Action handler, Boolean removable)
I/monodroid-gref(12405):    at Java.Lang.Thread+RunnableImplementor..ctor(System.Action handler)
I/monodroid-gref(12405):    at Android.App.Activity.RunOnUiThread(System.Action action)
I/monodroid-gref(12405):    at Mono.Samples.Hello.HelloActivity.UseLotsOfMemory(Android.Widget.TextView textview)
I/monodroid-gref(12405):    at Mono.Samples.Hello.HelloActivity.<OnCreate>m__3(System.Object o)
I/monodroid-gref(12405): handle 0x40517468; key_handle 0x40517468: Java Type: `mono/java/lang/RunnableImplementor`; MCW type: `Java.Lang.Thread+RunnableImplementor`
I/monodroid-gref(12405): Disposing handle 0x40517468
I/monodroid-gref(12405): -g- grefc 107 gwrefc 0 handle 0x40517468/L from    at Java.Lang.Object.Dispose(System.Object instance, IntPtr handle, IntPtr key_handle, JObjectRefType handle_type)
I/monodroid-gref(12405):    at Java.Lang.Object.Dispose()
I/monodroid-gref(12405):    at Java.Lang.Thread+RunnableImplementor.Run()
I/monodroid-gref(12405):    at Java.Lang.IRunnableInvoker.n_Run(IntPtr jnienv, IntPtr native__this)
I/monodroid-gref(12405):    at System.Object.c200fe6f-ac33-441b-a3a0-47659e3f6750(IntPtr , IntPtr )
I/monodroid-gref(27679): +w+ grefc 1916 gwrefc 296 obj-handle 0x406b2b98/G -> new-handle 0xde68f4bf/W from take_weak_global_ref_jni
I/monodroid-gref(27679): -w- grefc 1915 gwrefc 294 handle 0xde691aaf/W from take_global_ref_jni

Il existe quatre messages de conséquence :

  • Création de référence globale : il s’agit des lignes qui commencent par +g+ et fournissent une trace de pile pour le chemin de code de création.
  • Destruction de référence globale : il s’agit des lignes qui commencent par -g- et peuvent fournir une trace de pile pour le chemin d’accès du code qui élimine la référence globale. Si le GC est supprimé du gref, aucune trace de pile n’est fournie.
  • Création de référence globale faible : voici les lignes qui commencent par +w+ .
  • Destruction de référence globale faible : il s’agit de lignes qui commencent par -w- .

Dans tous les messages, la valeur grefc est le nombre de références globales créées par Xamarin.Android, tandis que la valeur grefwc est le nombre de références globales faibles créées par Xamarin.Android. La valeur de handle ou obj-handle est la valeur de handle JNI, et le caractère après le « /est le type de valeur de handle : /L pour référence locale, /G pour les références globales et /W pour les références globales faibles.

Dans le cadre du processus GC, les références globales (+g+) sont converties en références globales faibles (provoquant un +w+ et -g-), un GC côté Java est lancé, puis la référence globale faible est case activée ed pour voir si elle a été collectée. S’il est encore vivant, un nouveau gref est créé autour de la référence faible (+g+, -w-), sinon le ref faible est détruit (-w).

Une instance Java est créée et encapsulée par un MCW

I/monodroid-gref(27679): +g+ grefc 2211 gwrefc 0 obj-handle 0x4066df10/L -> new-handle 0x4066df10/L from ...
I/monodroid-gref(27679): handle 0x4066df10; key_handle 0x4066df10: Java Type: `android/graphics/drawable/TransitionDrawable`; MCW type: `Android.Graphics.Drawables.TransitionDrawable`

Un GC est en cours d’exécution...

I/monodroid-gref(27679): +w+ grefc 1953 gwrefc 259 obj-handle 0x4066df10/G -> new-handle 0xde68f95f/W from take_weak_global_ref_jni
I/monodroid-gref(27679): -g- grefc 1952 gwrefc 259 handle 0x4066df10/G from take_weak_global_ref_jni

L’objet est toujours actif, comme handle != null

wref retourné en gref

I/monodroid-gref(27679): *try_take_global obj=0x4976f080 -> wref=0xde68f95f handle=0x4066df10
I/monodroid-gref(27679): +g+ grefc 1930 gwrefc 39 obj-handle 0xde68f95f/W -> new-handle 0x4066df10/G from take_global_ref_jni
I/monodroid-gref(27679): -w- grefc 1930 gwrefc 38 handle 0xde68f95f/W from take_global_ref_jni

L’objet est mort, en tant que handle == null

wref est libéré, aucun nouveau gref créé

I/monodroid-gref(27679): *try_take_global obj=0x4976f080 -> wref=0xde68f95f handle=0x0
I/monodroid-gref(27679): -w- grefc 1914 gwrefc 296 handle 0xde68f95f/W from take_global_ref_jni

Il existe une rides « intéressante » ici : sur les cibles exécutant Android avant 4.0, la valeur gref est égale à l’adresse de l’objet Java dans la mémoire du runtime Android. (Autrement dit, le GC est un non-déplacement, conservateur, collecteur, et il met à disposition des références directes à ces objets.) Ainsi, après une séquence +g+, +w+, -g-, +g+, -w-, le gref résultant aura la même valeur que la valeur gref d’origine. Cela rend l’grepping dans les journaux assez simple.

Android 4.0, cependant, a un collecteur en déplacement et n’a plus de références directes aux objets de machine virtuelle runtime Android. Par conséquent, après une séquence +g+, +w+, -g-, +g+, -w-, la valeur gref sera différente. Si l’objet survive à plusieurs contrôleurs de groupe, il passe par plusieurs valeurs gref, ce qui complique la détermination de l’emplacement d’allocation d’une instance.

Interrogation par programmation

Vous pouvez interroger les nombres GREF et WREF en interrogeant l’objet JniRuntime .

Java.Interop.JniRuntime.CurrentRuntime.GlobalReferenceCount - Nombre de références globales

Java.Interop.JniRuntime.CurrentRuntime.WeakGlobalReferenceCount - Nombre de références faibles

Journaux de débogage Android

Les journaux de débogage Android peuvent fournir un contexte supplémentaire concernant les erreurs d’exécution que vous voyez.

Les performances à virgule flottante sont terribles !

Sinon, « Mon application exécute 10 fois plus rapidement avec la build de débogage qu’avec la build Release ! »

Xamarin.Android prend en charge plusieurs API d’appareil : armeabi, armeabi-v7a et x86. Les API d’appareil peuvent être spécifiées dans l’onglet > Application propriétés > du projet Architectures prises en charge.

Les builds de débogage utilisent un package Android qui fournit toutes les API, et utilise donc l’ABI le plus rapide pour l’appareil cible.

Les builds de mise en production incluent uniquement les API sélectionnées dans l’onglet Propriétés du projet. Plusieurs peuvent être sélectionnés.

armeabi est l’ABI par défaut et a la prise en charge des appareils la plus large. Toutefois, armeabi ne prend pas en charge les appareils multi-UC et le matériel à virgule flottante, amont autres choses. Par conséquent, les applications qui utilisent le runtime de mise en production armeabi sont liées à un seul cœur et utilisent une implémentation à flotteur souple. Ces deux éléments peuvent contribuer à des performances beaucoup plus lentes pour votre application.

Si votre application nécessite des performances à virgule flottante décentes (par exemple, des jeux), vous devez activer l’ABI armeabi-v7a . Vous pouvez uniquement prendre en charge le runtime armeabi-v7a , bien que cela signifie que les appareils plus anciens qui prennent uniquement en charge armeabi ne pourront pas exécuter votre application.

Impossible de localiser android SDK

Il existe 2 téléchargements disponibles à partir de Google pour le Kit de développement logiciel (SDK) Android pour Windows. Si vous choisissez le programme d’installation de .exe, il écrit les clés de Registre qui indiquent à Xamarin.Android où elle a été installée. Si vous choisissez le fichier .zip et décompressez-le vous-même, Xamarin.Android ne sait pas où rechercher le Kit de développement logiciel (SDK). Vous pouvez indiquer à Xamarin.Android où se trouve le Kit de développement logiciel (SDK) dans Visual Studio en accédant aux options > d’outils > Paramètres Android Xamarin > :

Android SDK Location in Xamarin Android Settings

L’IDE n’affiche pas l’appareil cible

Parfois, vous tentez de déployer votre application sur un appareil, mais l’appareil sur lequel vous souhaitez effectuer le déploiement n’apparaît pas dans la boîte de dialogue Sélectionner un appareil. Cela peut se produire lorsque le pont de débogage Android décide d’aller en vacances.

Pour diagnostiquer ce problème, recherchez le programme adb, puis exécutez :

adb devices

Si votre appareil n’est pas présent, vous devez redémarrer le serveur Pont de débogage Android afin que votre appareil soit trouvé :

adb kill-server
adb start-server

Le logiciel HTC Sync peut empêcher le démarrage du serveur de base de données de fonctionner correctement. Si la commande adb start-server n’imprime pas le port sur lequel il démarre, quittez le logiciel HTC Sync et essayez de redémarrer le serveur adb.

Impossible d’exécuter l’exécutable de tâche spécifié « keytool »

Cela signifie que votre chemin d’accès ne contient pas le répertoire où se trouve le répertoire bin du Kit de développement logiciel (SDK) Java. Vérifiez que vous avez suivi ces étapes dans le guide d’installation .

monodroid.exe ou aresgen.exe quitté avec le code 1

Pour vous aider à déboguer ce problème, accédez à Visual Studio et modifiez le niveau de détail MSBuild, pour ce faire, sélectionnez : Options outils >> Project and Solutions > Build and Run > MSBuild Project Build Verbosity et définir cette valeur sur Normal.

Regénérer et case activée volet Sortie de Visual Studio, qui doit contenir l’erreur complète.

Il n’y a pas suffisamment d’espace de stockage sur l’appareil pour déployer le package

Cela se produit lorsque vous ne démarrez pas l’émulateur à partir de Visual Studio. Lorsque vous démarrez l’émulateur en dehors de Visual Studio, vous devez passer les -partition-size 512 options, par exemple.

emulator -partition-size 512 -avd MonoDroid

Vérifiez que vous utilisez le nom correct du simulateur, c’est-à-dire le nom que vous avez utilisé lors de la configuration du simulateur.

INSTALL_FAILED_INVALID_APK lors de l’installation d’un package

Les noms de package Android doivent contenir un point ('.'). Modifiez le nom de votre package pour qu’il contienne un point.

  • Dans Visual Studio :
    • Cliquez avec le bouton droit sur les propriétés de votre projet >
    • Cliquez sur l’onglet Manifeste Android sur la gauche.
    • Mettez à jour le champ Nom du package.
      • Si vous voyez le message « Aucune AndroidManifest.xml trouvée. Cliquez pour en ajouter un. » cliquez sur le lien, puis mettez à jour le champ Nom du package.
  • Dans Visual Studio pour Mac :
    • Cliquez avec le bouton droit sur les options de votre projet > .
    • Accédez à la section Build /Android Application.
    • Modifiez le champ Nom du package pour qu’il contienne un « . ».

INSTALL_FAILED_MISSING_SHARED_LIBRARY lors de l’installation d’un package

Une « bibliothèque partagée » dans ce contexte n’est pas un fichier de bibliothèque partagée native (libfoo.so). Il s’agit plutôt d’une bibliothèque qui doit être installée séparément sur l’appareil cible, telle que Google Cartes.

Le package Android spécifie les bibliothèques partagées requises avec l’élément <uses-library/> . Si une bibliothèque requise n’est pas présente sur l’appareil cible (par exemple//uses-library/@android:required, true, ce qui est la valeur par défaut), l’installation du package échoue avec INSTALL_FAILED_MISSING_SHARED_LIBRARY.

Pour déterminer les bibliothèques partagées requises, affichez le fichier AndroidManifest.xml généré(par exemple obj\Debug\android\AndroidManifest.xml) et recherchez les <uses-library/> éléments. <uses-library/>Les éléments peuvent être ajoutés manuellement dans le fichier Properties\AndroidManifest.xml de votre projet et via l’attribut personnalisé UsesLibraryAttribute.

Par exemple, l’ajout d’une référence d’assembly à Mono.Android.Google Cartes.dll ajoutera implicitement une <uses-library/> bibliothèque partagée google Cartes.

INSTALL_FAILED_UPDATE_INCOMPATIBLE lors de l’installation d’un package

Les packages Android ont trois exigences :

  • Ils doivent contenir un '.' (voir l’entrée précédente)
  • Ils doivent avoir un nom de package de chaîne unique (par conséquent, la convention inverse-tld affichée dans les noms d’applications Android, e.g. com.android.chrome pour l’application Chrome)
  • Lors de la mise à niveau des packages, le package doit avoir la même clé de signature.

Imaginez donc ce scénario :

  1. Vous générez et déployez votre application en tant qu’application de débogage
  2. Vous modifiez la clé de signature, par exemple pour l’utiliser en tant qu’application Release (ou parce que vous n’aimez pas la clé de signature de débogage fournie par défaut)
  3. Vous installez votre application sans la supprimer en premier, par exemple, Déboguer > sans débogage dans Visual Studio

Lorsque cela se produit, l’installation du package échoue avec une erreur INSTALL_FAILED_UPDATE_INCOMPATIBLE, car le nom du package n’a pas changé pendant la clé de signature. Le journal de débogage Android contient également un message similaire à :

E/PackageManager(  146): Package [PackageName] signatures do not match the previously installed version; ignoring!

Pour corriger cette erreur, supprimez complètement l’application de votre appareil avant de la réinstaller.

INSTALL_FAILED_UID_CHANGED lors de l’installation d’un package

Lorsqu’un package Android est installé, il reçoit un ID d’utilisateur (UID). Parfois, pour des raisons actuellement inconnues, lors de l’installation sur une application déjà installée, l’installation échoue avec INSTALL_FAILED_UID_CHANGED:

ERROR [2015-03-23 11:19:01Z]: ANDROID: Deployment failed
Mono.AndroidTools.InstallFailedException: Failure [INSTALL_FAILED_UID_CHANGED]
   at Mono.AndroidTools.Internal.AdbOutputParsing.CheckInstallSuccess(String output, String packageName)
   at Mono.AndroidTools.AndroidDevice.<>c__DisplayClass2c.<InstallPackage>b__2b(Task`1 t)
   at System.Threading.Tasks.ContinuationTaskFromResultTask`1.InnerInvoke()
   at System.Threading.Tasks.Task.Execute()

Pour contourner ce problème, désinstallez entièrement le package Android, soit en installant l’application à partir de l’interface utilisateur utilisateur de la cible Android, soit en utilisant adb:

$ adb uninstall @PACKAGE_NAME@

NE PAS UTILISERadb uninstall -k, car cela permet de conserver les données d’application et donc de conserver l’UID en conflit sur l’appareil cible.

Échec du lancement des applications de mise en production sur l’appareil

La sortie du journal de débogage Android contient-elle un message similaire à :

D/AndroidRuntime( 1710): Shutting down VM
W/dalvikvm( 1710): threadid=1: thread exiting with uncaught exception (group=0xb412f180)
E/AndroidRuntime( 1710): FATAL EXCEPTION: main
E/AndroidRuntime( 1710): java.lang.UnsatisfiedLinkError: Couldn't load monodroid: findLibrary returned null
E/AndroidRuntime( 1710):        at java.lang.Runtime.loadLibrary(Runtime.java:365)

Dans ce cas, il existe deux causes possibles :

  1. Le .apk ne fournit pas d’ABI pris en charge par l’appareil cible. Par exemple, le .apk contient uniquement des fichiers binaires armeabi-v7a, et l’appareil cible prend uniquement en charge armeabi.

  2. Un bogue Android. Si c’est le cas, désinstallez l’application, croisez vos doigts et réinstallez l’application.

Pour corriger (1), modifiez les options/propriétés du projet et ajoutez la prise en charge de l’ABI nécessaire à la liste des API prises en charge. Pour déterminer l’ABI que vous devez ajouter, exécutez la commande adb suivante sur votre appareil cible :

adb shell getprop ro.product.cpu.abi
adb shell getprop ro.product.cpu.abi2

La sortie contient les API primaires (et secondaires facultatives).

$ adb shell getprop | grep ro.product.cpu
[ro.product.cpu.abi2]: [armeabi]
[ro.product.cpu.abi]: [armeabi-v7a]

La propriété OutPath n’est pas définie pour le projet « MyApp.csproj »

Cela signifie généralement que vous disposez d’un ordinateur HP et que la variable d’environnement « Platform » a été définie sur quelque chose comme MCD ou HPD. Cela est en conflit avec la propriété MSBuild Platform qui est généralement définie sur « Any CPU » ou « x86 ». Vous devez supprimer cette variable d’environnement de votre machine avant que MSBuild puisse fonctionner :

  • variables d’environnement > avancées > système > Panneau de configuration

Redémarrez Visual Studio ou Visual Studio pour Mac et essayez de reconstruire. Les choses devraient maintenant fonctionner comme prévu.

java.lang.ClassCastException : mono.android.runtime.JavaObject ne peut pas être converti en ...

Xamarin.Android 4.x ne marshale pas correctement les types génériques imbriqués correctement. Par exemple, considérez le code C# suivant à l’aide de SimpleExpandableListAdapter :

// BAD CODE; DO NOT USE
var groupData = new List<IDictionary<string, object>> () {
        new Dictionary<string, object> {
                { "NAME", "Group 1" },
                { "IS_EVEN", "This group is odd" },
        },
};
var childData = new List<IList<IDictionary<string, object>>> () {
        new List<IDictionary<string, object>> {
                new Dictionary<string, object> {
                        { "NAME", "Child 1" },
                        { "IS_EVEN", "This group is odd" },
                },
        },
};
mAdapter = new SimpleExpandableListAdapter (
        this,
        groupData,
        Android.Resource.Layout.SimpleExpandableListItem1,
        new string[] { "NAME", "IS_EVEN" },
        new int[] { Android.Resource.Id.Text1, Android.Resource.Id.Text2 },
        childData,
        Android.Resource.Layout.SimpleExpandableListItem2,
        new string[] { "NAME", "IS_EVEN" },
        new int[] { Android.Resource.Id.Text1, Android.Resource.Id.Text2 }
);

Le problème est que Xamarin.Android marshale incorrectement les types génériques imbriqués. Il List<IDictionary<string, object>> est marshalé sur un java.lang.ArrrayList, mais il ArrayList contient mono.android.runtime.JavaObject des instances (qui référencent les Dictionary<string, object> instances) au lieu d’un élément qui implémente java.util.Map, ce qui entraîne l’exception suivante :

E/AndroidRuntime( 2991): FATAL EXCEPTION: main
E/AndroidRuntime( 2991): java.lang.ClassCastException: mono.android.runtime.JavaObject cannot be cast to java.util.Map
E/AndroidRuntime( 2991):        at android.widget.SimpleExpandableListAdapter.getGroupView(SimpleExpandableListAdapter.java:278)
E/AndroidRuntime( 2991):        at android.widget.ExpandableListConnector.getView(ExpandableListConnector.java:446)
E/AndroidRuntime( 2991):        at android.widget.AbsListView.obtainView(AbsListView.java:2271)
E/AndroidRuntime( 2991):        at android.widget.ListView.makeAndAddView(ListView.java:1769)
E/AndroidRuntime( 2991):        at android.widget.ListView.fillDown(ListView.java:672)
E/AndroidRuntime( 2991):        at android.widget.ListView.fillFromTop(ListView.java:733)
E/AndroidRuntime( 2991):        at android.widget.ListView.layoutChildren(ListView.java:1622)

La solution de contournement consiste à utiliser les types de collection Java fournis au lieu des System.Collections.Generic types « internes ». Cela entraîne des types Java appropriés lors du marshaling des instances. (Le code suivant est plus compliqué que nécessaire pour réduire les durées de vie gref. Il peut être simplifié pour modifier le code d’origine via s/List/JavaList/g et s/Dictionary/JavaDictionary/g si les durées de vie gref ne sont pas un souci.)

// insert good code here
using (var groupData = new JavaList<IDictionary<string, object>> ()) {
    using (var groupEntry = new JavaDictionary<string, object> ()) {
        groupEntry.Add ("NAME", "Group 1");
        groupEntry.Add ("IS_EVEN", "This group is odd");
        groupData.Add (groupEntry);
    }
    using (var childData = new JavaList<IList<IDictionary<string, object>>> ()) {
        using (var childEntry = new JavaList<IDictionary<string, object>> ())
        using (var childEntryDict = new JavaDictionary<string, object> ()) {
            childEntryDict.Add ("NAME", "Child 1");
            childEntryDict.Add ("IS_EVEN", "This child is odd.");
            childEntry.Add (childEntryDict);
            childData.Add (childEntry);
        }
        mAdapter = new SimpleExpandableListAdapter (
            this,
            groupData,
            Android.Resource.Layout.SimpleExpandableListItem1,
            new string[] { "NAME", "IS_EVEN" },
            new int[] { Android.Resource.Id.Text1, Android.Resource.Id.Text2 },
            childData,
            Android.Resource.Layout.SimpleExpandableListItem2,
            new string[] { "NAME", "IS_EVEN" },
            new int[] { Android.Resource.Id.Text1, Android.Resource.Id.Text2 }
        );
    }
}

NullReferenceExceptions inattendues

Parfois, le journal de débogage Android mentionne les nullReferenceExceptions qui « ne peuvent pas se produire » ou proviennent du code d’exécution Mono pour Android peu avant que l’application ne meurt :

E/mono(15202): Unhandled Exception: System.NullReferenceException: Object reference not set to an instance of an object
E/mono(15202):   at Java.Lang.Object.GetObject (IntPtr handle, System.Type type, Boolean owned)
E/mono(15202):   at Java.Lang.Object._GetObject[IOnTouchListener] (IntPtr handle, Boolean owned)
E/mono(15202):   at Java.Lang.Object.GetObject[IOnTouchListener] (IntPtr handle, Boolean owned)
E/mono(15202):   at Android.Views.View+IOnTouchListenerAdapter.n_OnTouch_Landroid_view_View_Landroid_view_MotionEvent_(IntPtr jnienv, IntPtr native__this, IntPtr native_v, IntPtr native_e)
E/mono(15202):   at (wrapper dynamic-method) object:b039cbb0-15e9-4f47-87ce-442060701362 (intptr,intptr,intptr,intptr)

or

E/mono    ( 4176): Unhandled Exception:
E/mono    ( 4176): System.NullReferenceException: Object reference not set to an instance of an object
E/mono    ( 4176): at Android.Runtime.JNIEnv.NewString (string)
E/mono    ( 4176): at Android.Util.Log.Info (string,string)

Cela peut se produire lorsque le runtime Android décide d’abandonner le processus, ce qui peut se produire pour n’importe quel nombre de raisons, y compris atteindre la limite GREF de la cible ou faire quelque chose de « incorrect » avec JNI.

Pour voir si c’est le cas, case activée le journal de débogage Android pour un message de votre processus similaire à :

E/dalvikvm(  123): VM aborting

Abandonner en raison de l’épuisement global des références

La couche JNI du runtime Android prend uniquement en charge un nombre limité de références d’objets JNI à un moment donné. Lorsque cette limite est dépassée, les choses s’interrompent.

La limite GREF (référence globale) est de 2 000 références dans l’émulateur et environ 52 000 références sur le matériel.

Vous savez que vous commencez à créer trop de greFs lorsque vous voyez des messages tels que ceux-ci dans le journal de débogage Android :

D/dalvikvm(  602): GREF has increased to 1801

Lorsque vous atteignez la limite GREF, un message tel que celui-ci est imprimé :

D/dalvikvm(  602): GREF has increased to 2001
W/dalvikvm(  602): Last 10 entries in JNI global reference table:
W/dalvikvm(  602):  1991: 0x4057eff8 cls=Landroid/graphics/Point; (20 bytes)
W/dalvikvm(  602):  1992: 0x4057f010 cls=Landroid/graphics/Point; (28 bytes)
W/dalvikvm(  602):  1993: 0x40698e70 cls=Landroid/graphics/Point; (20 bytes)
W/dalvikvm(  602):  1994: 0x40698e88 cls=Landroid/graphics/Point; (20 bytes)
W/dalvikvm(  602):  1995: 0x40698ea0 cls=Landroid/graphics/Point; (28 bytes)
W/dalvikvm(  602):  1996: 0x406981f0 cls=Landroid/graphics/Point; (20 bytes)
W/dalvikvm(  602):  1997: 0x40698208 cls=Landroid/graphics/Point; (20 bytes)
W/dalvikvm(  602):  1998: 0x40698220 cls=Landroid/graphics/Point; (28 bytes)
W/dalvikvm(  602):  1999: 0x406956a8 cls=Landroid/graphics/Point; (20 bytes)
W/dalvikvm(  602):  2000: 0x406956c0 cls=Landroid/graphics/Point; (20 bytes)
W/dalvikvm(  602): JNI global reference table summary (2001 entries):
W/dalvikvm(  602):    51 of Ljava/lang/Class; 164B (41 unique)
W/dalvikvm(  602):    46 of Ljava/lang/Class; 188B (17 unique)
W/dalvikvm(  602):     6 of Ljava/lang/Class; 212B (6 unique)
W/dalvikvm(  602):    11 of Ljava/lang/Class; 236B (7 unique)
W/dalvikvm(  602):     3 of Ljava/lang/Class; 260B (3 unique)
W/dalvikvm(  602):     4 of Ljava/lang/Class; 284B (2 unique)
W/dalvikvm(  602):     8 of Ljava/lang/Class; 308B (6 unique)
W/dalvikvm(  602):     1 of Ljava/lang/Class; 316B
W/dalvikvm(  602):     4 of Ljava/lang/Class; 332B (3 unique)
W/dalvikvm(  602):     1 of Ljava/lang/Class; 356B
W/dalvikvm(  602):     2 of Ljava/lang/Class; 380B (1 unique)
W/dalvikvm(  602):     1 of Ljava/lang/Class; 428B
W/dalvikvm(  602):     1 of Ljava/lang/Class; 452B
W/dalvikvm(  602):     1 of Ljava/lang/Class; 476B
W/dalvikvm(  602):     2 of Ljava/lang/Class; 500B (1 unique)
W/dalvikvm(  602):     1 of Ljava/lang/Class; 548B
W/dalvikvm(  602):     1 of Ljava/lang/Class; 572B
W/dalvikvm(  602):     2 of Ljava/lang/Class; 596B (2 unique)
W/dalvikvm(  602):     1 of Ljava/lang/Class; 692B
W/dalvikvm(  602):     1 of Ljava/lang/Class; 956B
W/dalvikvm(  602):     1 of Ljava/lang/Class; 1004B
W/dalvikvm(  602):     1 of Ljava/lang/Class; 1148B
W/dalvikvm(  602):     2 of Ljava/lang/Class; 1172B (1 unique)
W/dalvikvm(  602):     1 of Ljava/lang/Class; 1316B
W/dalvikvm(  602):     1 of Ljava/lang/Class; 3428B
W/dalvikvm(  602):     1 of Ljava/lang/Class; 3452B
W/dalvikvm(  602):     1 of Ljava/lang/String; 28B
W/dalvikvm(  602):     2 of Ldalvik/system/VMRuntime; 12B (1 unique)
W/dalvikvm(  602):    10 of Ljava/lang/ref/WeakReference; 28B (10 unique)
W/dalvikvm(  602):     1 of Ldalvik/system/PathClassLoader; 44B
W/dalvikvm(  602):  1553 of Landroid/graphics/Point; 20B (1553 unique)
W/dalvikvm(  602):   261 of Landroid/graphics/Point; 28B (261 unique)
W/dalvikvm(  602):     1 of Landroid/view/MotionEvent; 100B
W/dalvikvm(  602):     1 of Landroid/app/ActivityThread$ApplicationThread; 28B
W/dalvikvm(  602):     1 of Landroid/content/ContentProvider$Transport; 28B
W/dalvikvm(  602):     1 of Landroid/view/Surface$CompatibleCanvas; 44B
W/dalvikvm(  602):     1 of Landroid/view/inputmethod/InputMethodManager$ControlledInputConnectionWrapper; 36B
W/dalvikvm(  602):     1 of Landroid/view/ViewRoot$1; 12B
W/dalvikvm(  602):     1 of Landroid/view/ViewRoot$W; 28B
W/dalvikvm(  602):     1 of Landroid/view/inputmethod/InputMethodManager$1; 28B
W/dalvikvm(  602):     1 of Landroid/view/accessibility/AccessibilityManager$1; 28B
W/dalvikvm(  602):     1 of Landroid/widget/LinearLayout$LayoutParams; 44B
W/dalvikvm(  602):     1 of Landroid/widget/LinearLayout; 332B
W/dalvikvm(  602):     2 of Lorg/apache/harmony/xnet/provider/jsse/TrustManagerImpl; 28B (1 unique)
W/dalvikvm(  602):     1 of Landroid/view/SurfaceView$MyWindow; 36B
W/dalvikvm(  602):     1 of Ltouchtest/RenderThread; 92B
W/dalvikvm(  602):     1 of Landroid/view/SurfaceView$3; 12B
W/dalvikvm(  602):     1 of Ltouchtest/DrawingView; 412B
W/dalvikvm(  602):     1 of Ltouchtest/Activity1; 180B
W/dalvikvm(  602): Memory held directly by tracked refs is 75624 bytes
E/dalvikvm(  602): Excessive JNI global references (2001)
E/dalvikvm(  602): VM aborting

Dans l’exemple ci-dessus (qui provient de 685215 de bogues), le problème est que trop d’instances Android.Graphics.Point sont créées ; consultez le commentaire #2 pour obtenir la liste des correctifs pour ce bogue particulier.

En règle générale, une solution utile consiste à rechercher le type dont le type a trop d’instances allouées ( Android.Graphics.Point dans le vidage ci-dessus), puis à trouver l’emplacement où ils sont créés dans votre code source et à les supprimer correctement (afin que leur durée de vie d’objet Java soit raccourcie). Cela n’est pas toujours approprié (#685215 est multithread, donc la solution triviale évite l’appel Dispose), mais c’est la première chose à prendre en compte.

Vous pouvez activer la journalisation GREF pour voir quand les greFs sont créés et combien d’entre eux existent.

Abandonner en raison d’une incompatibilité de type JNI

Si vous déployez manuellement du code JNI, il est possible que les types ne correspondent pas correctement, par exemple si vous essayez d’appeler java.lang.Runnable.run sur un type qui n’implémente java.lang.Runnablepas . Lorsque cela se produit, un message similaire à celui-ci s’affiche dans le journal de débogage Android :

W/dalvikvm( 123): JNI WARNING: can't call Ljava/Type;;.method on instance of Lanother/java/Type;
W/dalvikvm( 123):              in Lmono/java/lang/RunnableImplementor;.n_run:()V (CallVoidMethodA)
...
E/dalvikvm( 123): VM aborting

Prise en charge du code dynamique

Le code dynamique ne compile pas

Pour utiliser la dynamique C# dans votre application ou bibliothèque, vous devez ajouter System.Core.dll, Microsoft.CSharp.dll et Mono.CSharp.dll à votre projet.

Dans la build Release, MissingMethodException se produit pour le code dynamique au moment de l’exécution.

  • Il est probable que votre projet d’application n’ait pas de références à System.Core.dll, Microsoft.CSharp.dll ou Mono.CSharp.dll. Vérifiez que ces assemblys sont référencés.

    • Gardez à l’esprit que le code dynamique coûte toujours. Si vous avez besoin d’un code efficace, envisagez de ne pas utiliser de code dynamique.
  • Dans la première préversion, ces assemblys ont été exclus, sauf si les types de chaque assembly sont explicitement utilisés par le code de l’application. Pour obtenir une solution de contournement, consultez les rubriques suivantes : http://lists.ximian.com/pipermail/mo...il/009798.html

Projets générés avec incident AOT+LLVM sur des appareils x86

Lors du déploiement d’une application créée avec AOT+LLVM sur des appareils x86, vous pouvez voir un message d’erreur d’exception similaire à ce qui suit :

Assertion: should not be reached at /Users/.../external/mono/mono/mini/tramp-x86.c:124
Fatal signal 6 (SIGABRT), code -6 in tid 4051 (Xamarin.bug56111)

Il s’agit d’un problème connu : la solution de contournement consiste à désactiver LLVM.