Obtenir la valeur de la version stockée dans les propriétés .NET du projet Android n’est pas direct, il faut un peu ruser…
Soyons plus précis
Ce que nous voulons c’est lire la version de l’App telle que nous l’avons indiquée dans les Propriétés du projet Android, c’est à dire tel qu’on le ferait pour n’importe quel projet .NET.
C’est en effet le projet natif qui est compilé et qui contient la version (si on l’y place) plutôt que le projet Xamarin.Forms.
Mais justement c’est surtout au niveau de ce dernier qu’on a besoin de cette information pour l’afficher dans une About Box par exemple ou l’envoyer avec un rapport de bug vers un serveur.
Et c’est là que ça se complique un peu car d’une part obtenir cette information n’est pas direct mais il va falloir se débrouiller pour qu’elle puisse être exploitée non pas dans le code natif mais dans le code Xamarin.Forms…
Définir une Interface
Dès qu’il y a comme ici mélange entre Xamarin.Forms et code natif il y a fort à parier qu’il sera nécessaire de définir une Interface côté Xamarin.Forms… Et c’est le cas ici !
Donc définissons une Interface pour obtenir deux informations intéressantes pour une About Box, la version et le copyright :
S’en servir
Avant de voir comment implémenter le code de l’interface et où le faire, regardons comment l’on va s’en servir. S’agissant d’un exemple ultra simplifié pas de MVVM ici, mais vous transposerez sans difficulté.
Xaml
Donc partons de la page XAML, ici la MainPage de ce projet de test qui ne contient rien d’autre :
Comme vous le constatez il n’y a rien à dire de particulier, pas de binding, pas de mise en page luxueuse, juste un Label portant un nom pour être modifié par le code behind. Ce n’est donc pas ici que nous apprendrons quelque chose de neuf. Next.
Le code behind
C’est ici qu’on se sert de l’interface :
Il n’y a pas grand chose à décomposer pour comprendre ce code. On a juste notre Label qui s’appelle “TextBlock” (hommage à WPF !) dont on modifie la propriété Text en y ajoutant les infos suivantes : Date du jour, version de l’App et ses copyrights.
Mais si la date ne pose pas de souci, qu’en est-il des autres informations ? D’où viennent-elles ?
Dans le code Xamarin.Forms ci-dessus la provenance reste mystérieuse, on ne fait qu’appeler le conteneur IoC livré de base pour obtenir une instance de l’interface que nous avons défini plus haut… C’est la ligne qui utilise DependencyService.Get<IVersionInfo>();
Une fois l’instance sous jacente récupérée, attaquer les propriétés de l’interface pour construire le texte est le B.A.BA de la concaténation de chaînes sous C#…
Un peu de visuel
C’est beau, c’est simple, mais on ne sait toujours pas d’où viennent ces fichues informations !
Je comprends votre impatience mais nous y arrivons …
D’abord voyons les infos retournées par une capture écran :
Cela correspond au code XAML montré plus haut. La date du jour (juste pour garnir, cela ne joue aucun rôle dans notre démo), suivie des informations issues de l’interface ou plutôt du code qui implémente celle-ci, la version et le copyright.
Pour se prouver que la version retournée est bien celle qui nous intéresse :
Les informations affichées proviennent bien du fichier AssemblyInfo.cs de l’application NATIVE Android (et non du projet Xamarin.Forms) et ce sont bien les infos “.NET” de version et non pas les informations de version Android ! Tout dépend de ce qu’on veut bien entendu mais ici nous supposons que ce ne sont pas ces dernières qui nous intéressent.
(navré pour le floutage mais cela provient d’un code de démo créé pour un client)
Le code concret
Il est temps de voir comment la merveille s’accomplie et comment le miracle se réalise…
Où se cache le code concret pour commencer ?
Dans le projet natif Android. Dans une unité de code C#. Dans un répertoire “Utils” par souci de clarté.
Comment ce code devient-il disponible à l’application Xamarin.Forms ?
En indiquant simplement qu’il supporte notre Interface. Et ce par le biais du DependencyService utilisé plus haut.
En réalité j’ai du démontré déjà cent fois ce mécanisme qui sert notamment à l’injection de code natif dans du code Xamarin.Forms ce qui a mille utilisations possibles.
Donc voici le code :
La magie s’opère ainsi à la fois par la déclaration de AppVersionProvider, la classe concrète, son support de IVersionInfo définie dans le projet Xamarin.Forms mais aussi par l’enregistrement de ce code dans le conteneur IoC de Xamarin.Forms via l’attribut placé juste avant la déclaration de l’espace de noms. On utilise alors DependencyAttribute auquel on passe le nom de la classe concrète (celle qui est définie juste en dessous).
Sachant que cette classe supporte notre interface, lorsque nous demandons l’instance en partant de cette dernière dans le code Xamarin.Forms le conteneur IoC ne fait que chercher la classe qui supporte la dite interface… C’est très simple en réalité.
Conclusion
Encore une fois c’est la même technique qui est utilisée pour rendre disponible en Xamarin.Forms ce qui n’est possible qu’en code natif. C’est simple, efficace, et une fois qu’on compris c’est applicable à tout un tas de situations.
La question que vous vous posez peut-être est pourquoi est-ce si indirect ? Tout simplement parce que la version est placée dans le projet Android (ou iOS et il faudrait adapter le code tout simplement) d’une façon spécifique à .NET alors que le projet natif est en Android ne l’oublions pas. Obtenir la version Android du projet est plus direct. Mais réclamerait la même “gymnastique” car cette info n’est pas disponible côté Xamarin.Forms.
A force de lire Dot.Blog ce genre de mécanisme vous deviendra naturel ! Alors …
Stay Tuned !