Android,
A Complete Course, From
Basics to Enterprise Edition
Android, A Complete Course, From Basics to Enterprise
Edition
1.1 Hudson ou l’automatisation des tests
Cet
article est extraie du livre « Android, A Complete Course »,
disponible sur Android2ee.com.
Les
exemples ou les programmes présents dans cet ouvrage sont fournis pour
illustrer les descriptions théoriques. Ce code est libre de toute utilisation
mais n'est pas distribuable.
La
distribution du code est reservée au site :
La
propriété intellectuelle du code appartient à :
L’utilisation
de ces codes est sous votre unique responsabilité et personne d’autre que vous
ne pourra être tenu responsable des préjudices ou dommages de quelques natures
que ce soit pouvant résulter de son utilisation.
Tous
les noms de produits ou marques cités dans cet ouvrage sont des marques déposés
par leurs propriétaires respectifs.
Publié par http://android2ee.com
Titre Original : Android, A Complete Course, From
Basics to Enterprise Edition. Édition Française.
ISBN : 979-10-90388-00-0
Copyright © 2011 by Mathias Séguy
Aucune
représentation ou reproduction, même partielle, autre que celles prévues à
l’article L. 122-5 2° et 3° a) du code de la propriété intellectuelle ne peut
être faite sans l’autorisation expresse de Mathias Seguy ou, le cas échéant,
sans le respect des modalités prévues à l’article L. 122-10 dudit code
http://wiki.hudson-ci.org/display/HUDSON/Android+Emulator+Plugin
Il est possible que votre serveur d’intégration continue soit un linux distant. Dans ce cadre, il va falloir installer l’Android SDK et les différents AVD sur cet ordinateur en ligne de commandes.
Tout d’abord, vous devez télécharger la dernière version linux du Android SDK sur http://developer.android.com/sdk/index.html dans un répertoire sain de votre machine et dé-zipper le : tar -xvf android-sdk_r09-linux_x86.tar.gz
Ouvrez un shell, et positionnez-vous au sein du répertoire tool de votre répertoire Android-SDK puis lancez la commande :
./android –v update sdk –u
Cette commande lance l’update du SDK en mode verbose (le –v) et headless (le –u) sans lancer d’IHM. Elle installe alors l’ensemble des composants du SDK Android attendus. C'est-à-dire tous, ceux de Google et ceux d’Android simple. Vous êtes opérationnel pour créer vos AVD.
Si vous utilisez Hudson, vous pouvez choisir de ne pas créer d’AVD et de paramétrer ces AVD au sein d’Hudson. Hudson se chargera de les créer. Nous préconisons cette solution.
Sinon il faut créer les AVD qui vous serviront pour vos tests. En suivant la méthodologie que nous préconisons pour vos tests, il vous faut mettre en place l’ensemble des AVD pour les versions cibles de votre application. En intégration continue sur un serveur distant qui ne possède pas de GUI, il n’y a pas d’intérêt à mettre en place les AVD correspondant aux différentes tailles et densités d’écran.
Ainsi, vous devez définir les versions cibles en vous aidant du graphique des parts de marchés des différentes versions d’Android suivant :
Ce dernier est régulièrement mis à jour sur le site de Google : http://developer.android.com/resources/dashboard/platform-versions.html
À l’heure où j’écris ces lignes, il est ainsi conseillé de mettre en place les AVD Google de l’API level 3 à l’API level 11. Dans le cadre de l’intégration continue, il est conseillé de mettre en place les AVD Google API et non pas les Android simples. La seule différence entre ces deux types d’AVD est que les AVD Google possèdent l’ensemble du système, en particulier les api GoogleMap. Ils sont donc plus longs à démarrer.
En effet, les Google sont les AVD qui correspondent (depuis la version 1.5) aux appareils réels, les API « Android simple » sont épurées pour être plus rapides.
Ensuite pour mettre en place les AVD, il faut récupérer la liste des targets disponibles, pour cela utilisez la commande : ./android -v list target. Cette commande liste pour chaque target, son nom et ses skins disponibles qui sont les seules informations qui vous intéressent lors de la création d’AVD.
Si vous souhaitez maîtriser l’emplacement où se créent vos AVD, vous pouvez utiliser le paramètre –p puis spécifier le chemin de l’AVD que vous souhaitez créer. En faisant cela, sachez d’une part que de toute façon, à la racine de votre utilisateur sera créé un dossier .android qui contient les fichiers de description de vos AVD et d’autre part que Hudson cherchera les AVD là où ils devraient se trouver. Ainsi soit vous êtes linuxien ou windowsien et rien ne vous effraie, soit vous gardez le comportement par défaut de vos AVD.
Pour mettre en place les AVD, il faut taper la ligne suivante (Ouvrez un shell, et positionnez vous au sein du répertoire tool de votre répertoire Android-SDK puis lancez la commande) :
./android -v create avd -n <NomAVD> -c <MemorySize>M
-t "<TargetName>" -s <SkinName> -p ../AVD/<NomAVD>
Où :
· <NomAvd> est le nom que vous souhaitez donner à votre AVD,
· <MemorySize> est la taille que vous souhaitez donner à votre AVD,
· <TargetName> est le nom de la target de l’AVD,
· <SkinName> est le nom du skin associé.
Ce qui donne par exemple :
./android -v create avd -n GoogleL3 -c 512M -t "Google
Inc.:Google APIs:3" -s HVGA -p ../AVD/GoogleL3
Pour créer en suivant, il ne vous reste plus qu’à incrémenter le 3, dans votre nom, votre version et votre path. Vos AVD sont tous créés en 1 minute.
À l’heure actuelle, la création d’AVD en ligne de commande pause un gros problème sur mon Debian. Les AVD créés ne respectent pas la nomenclature voulue et ne sont pas reconnus par Hudson.
Les répertoires dans lequel sont créés les AVD doivent respectés la structure suivante :
Chaque AVD possède un fichier MonAVD.init et un répertoire associé MonAVD.avd.
Lors de la création en ligne de commande des AVD, la structure créée est :
On remarque que les répertoires associés aux AVD ne possèdent par l’extension « .avd ». Hudson sera incapable de trouver les AVD.
C’est pourquoi nous préconisons de laisser Hudson créer lui-même les AVD.
Dans Hudson, ouvrez une session en tant qu’administrateur et allez dans « Administrer Hudson » puis « Gestion des plugins ». Dans l’onglet « Disponibles », sélectionnez le plugin « Android Emulator Plugin » puis appuyez sur « Installez ».
Hudson est alors prêt à gérer les projets Android.
Toujours dans Hudson, ouvrez une session en tant qu’administrateur et allez dans « Administrer Hudson » puis « Configurer le système ». Vous devez remplir le champ Android SDK root en lui indiquant le chemin vers votre installation d’Android, comme dans la copie d’écran ci-dessous :
On distingue deux cas, soit Hudson s’exécute sur votre machine de développement et là, votre KeyStore est déjà installé. Soit Hudson est installé sur une machine distante qui ne possède pas Eclipse et dans ce cas, le plus simple est de recréer votre KeyStore en ligne de commande en utilisant la commande keytool (dans votre JAVA_HOME/bin) et la tache genkeypair :
-genkeypair
[-v] [-protected]
[-alias <alias>]
[-keyalg <keyalg>] [-keysize <taille_clé>]
[-sigalg <sigalg>] [-dname <nomd>]
[-validity <joursVal>] [-keypass <mot_passe_clé>]
[-keystore <keystore>] [-storepass <mot_passe_store>]
[-storetype <storetype>] [-providername <name>]
[-providerclass <provider_class_name> [-providerarg <arg>]]
...
[-providerpath <pathlist>]
Ce qui donne :
keytool -genkeypair -v -keystore myReleaseKeystorePath.jks -storepass myKeystorePassword -alias myKey
-keypass myKeyPassWord -keyalg RSA
-validity 36500
Où:
· myReleaseKeyStorePath est le chemin complet de votre KeyStore (/home/myStores/myKeyStore.jks),
· myKeystorePassword est le mot de passe de votre KeyStore,
· myKey est le nom de votre clef et
· myKeyPassWord est le mot de passe de cette clef.
La création du KeyStore avec Eclipse est décrite au chapitre 14.1 : Signer son application.
Maintenant, il vous faut définir un fichier de setting.xml pour Maven spécifique à Hudson et à la machine distante qui l’héberge.
Ce fichier de setting doit:
· Définir le plugin jayway dans le plugin group.
· Définir et activer par défaut le profil android-project qui définit l’ensemble des variables nécessaire à une compilation Android.
· Définir le profil android-release qui définit les variables pour accéder au KeyStore.
Ce qui donne :
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0
http://maven.apache.org/xsd/settings-1.0.0.xsd">
<!--
localRepository -->
<localRepository>/home/opt/apache-maven-2.2.1/repository</localRepository>
<!--
********************************************************** -->
<!-- Mise en place d'un fichier de setting
permettant de
faire
de la construction avec Hudson de projet android -->
<!--
********************************************************** -->
<pluginGroups>
<pluginGroup>
com.jayway.maven.plugins.android.generation2
</pluginGroup>
</pluginGroups>
<!--
********************************************************** -->
<!--The
definition of all the properties to set for android projects -->
<!-- ********************************************************** -->
<activeProfiles>
<activeProfile>android-project</activeProfile>
</activeProfiles>
<profiles>
<!--The
profile that must be active for all Android project-->
<profile>
<id>android-project</id>
<properties>
<!-- RT and
JSSE jar path-->
<!--
******************* -->
<!-- For
linux/Unix-->
<rt.jar.path>${java.home}/jre/lib/rt.jar</rt.jar.path>
<jsse.jar.path>${java.home}/jre/lib/jsse.jar</jsse.jar.path>
<!--The path
to the Android SDK-->
<!--
******************* -->
<android.sdk.path>YouAndroidSDKPath </android.sdk.path>
<!--version
of the plugin defined in the setting file (here so)-->
<!-- ******************************************************
-->
<jayway.plugin.version>2.8.3</jayway.plugin.version>
<proguard.plugin.version>2.0.4</proguard.plugin.version>
<proguard.version>4.4</proguard.version>
<jarsigner.plugin.version>1.2</jarsigner.plugin.version>
<build.helper.plugin.version>1.5</build.helper.plugin.version>
</properties>
</profile>
<!--
********************************************************** -->
<!--The
definition of all the properties for the release mode's profil -->
<!--
********************************************************** -->
<!--The
profile to use for the release android mode-->
<profile>
<id>android-release</id>
<activation>
<!--Just set
the variable release to true-->
<property>
<name>android-release</name>
<value>true</value>
</property>
</activation>
<!--Needed
properties to sign the application using the good key-->
<properties>
<sign.keystore>myReleaseKeystorePath.jks</sign.keystore>
<sign.alias>myKeystorePassword</sign.alias>
<sign.storepass>myKeystorePassword</sign.storepass>
<sign.keypass>myKeyPassWord</sign.keypass>
</properties>
</profile>
</profiles>
</settings>
Dans Hudson, sélectionnez « Nouvelle tâche ». Dans la fenêtre qui s’ouvre, remplissez le nom du projet et sélectionnez « Construire un projet maven 2/3 ».
Ensuite, il vous suffit de définir:
· Le nom et la description du projet,
· La gestion que vous souhaitez avoir de vos builds : les conserver, n’en conservez qu’un, …
· La gestion de votre code source : il faut le brancher sur votre SVN ou votre CVS en donnant l’url de votre repository ainsi que le répertoire de votre projet,
· La gestion de l’automatisation de vos builds (quotidienne, hebdomadaire, dès qu’un commit est effectué sur le code, …),
· Le build en lui-même : la localisation du pom.xml du projet et le goal maven à lancer (par défaut, en intégration continue, il faut utiliser le goal « clean install »),
· L’environnement Android des builds que vous souhaitez mettre en place. Cela vous permet soit de définir un émulateur qui existe déjà, soit de laisser le soin à Hudson de gérer l’émulateur en lui donnant ses spécificités (Hudson le créera, s’il n’existe pas).
Les valeurs possibles pour l’Android OS sont 2.1 ou android-7 ou Google Inc.:Google APIs:9 où bien sûr les numéros de versions sont à spécifier en fonction de l’OS que vous souhaitez utiliser.
Voilà,
il ne vous reste plus qu’à sauver votre projet de build. Il apparaît maintenant
dans votre tableau de bord Hudson. Il vous suffit de cliquer dessus, puis dans
la colonne de gauche de cliquer sur « Lancer un Build ». Les copies d’écran ci-dessous explicitent cette
configuration :
L’objectif de ce paragraphe est de mettre en place une optimisation de la création des builds Android pour Hudson. En effet, un projet Android sera buildé en fonction d’un ensemble de paramètres (version de l’émulateur, taille de l’écran, densité,…) dans différents projets de build Hudson. Hudson permettant la création d’un nouveau projet de build à partir d’un projet existant, il est intéressant de créer un ensemble de projets de build qui ne seront là que pour créer facilement un nouvel ensemble de projets de build pour un projet Android.
Sachant qu’un projet Android doit être buildé pour l’ensemble des versions du système (de la 1.5 à la 3.0 et sûrement bientôt plus), il est utile de créer à minima autant de projet de build que de versions, c'est-à-dire pour 7 versions différentes. De plus, chacun de ces builds doit être effectué en mode normal et en mode release, soit 14 projets de build différents.
La seconde remarque étant qu’Hudson permet la création d’AVD, il suffit de créer par projet de build un AVD distinct. En utilisant la création de projet de build à partir d’un projet existant, il devient facile de créer ces différents projets de build.
Enfin la dernière remarque est que les builds peuvent se chaîner, il est alors intéressant de chainer l’ensemble des projets de build pour un même projet Android. Un chaînage cohérent avec les numéros de versions de l’OS Android paraît adapté ; construction pour le level3, puis le level 4,…
Lorsque l’on met en place une chaîne de projet de build, il faut faire attention à ce que seul le premier élément de la chaîne se déclenche automatiquement (soit par la détection d’un changement au niveau des sources, soit par déclenchement périodique…). Il est donc préconisé de faire débuter cette chaîne par un projet de build qui ne fait rien d’autre que de se déclencher automatiquement et de lancer la chaine de builds. Ce projet peut s’appeler NomDuProjet BuildChainLauncher.
Concernant la création des AVD, il est préconisé d’utiliser votre Hudson pour les créer. Si vous souhaitez maîtriser leur emplacement, mettez un lien symbolique du répertoire userHudson/.android/avd vers le répertoire où vous souhaitez stocker vos AVD. La commande linux pour la création de lien symbolique étant : ln -s {/path/to/file-name} {link-name}
Votre environnement d’intégration continue est opérationnel, vous avez mis en place votre fichier setting.xml ainsi que votre KeyStore.
Vous pouvez utiliser maintenant soit un Pom minimaliste pour votre projet, soit, ce qui est préconisé, utiliser le Pom Android ultime décrit au chapitre 15.2 Synthèse Android-Maven : le Pom Android ultime.
Il vous suffit de modifier les variables dans le bloc properties, ainsi que les coordonnées de votre projet, pour adapter le build à vos contraintes. Le reste du fichier n’a pas à être modifié.
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>net.stinfoservices.android.tuto.maven</groupId>
<artifactId>MavenAndroidTuto</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>apk</packaging>
<name>MavenAndroidTuto</name>
<properties>
<!-- L'encoding du projet
-->
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<!-- JDK version -->
<jdk.version>1.6</jdk.version>
<java.source.version>1.6</java.source.version>
<java.target.version>1.6</java.target.version>
<!-- Android SDK version
-->
<android.sdk.version>2.1</android.sdk.version>
<!-- Android jar
dependency-->
<google.com.android.version>2.3_r1</google.com.android.version>
</properties>
<dependencies>
<dependency>
<groupId>android</groupId>
<artifactId>android</artifactId>
<version>${google.com.android.version}</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<sourceDirectory>src</sourceDirectory>
<plugins>
<plugin>
<groupId>com.jayway.maven.plugins.android.generation2</groupId>
<artifactId>maven-android-plugin</artifactId>
<version>${jayway.plugin.version}</version>
<configuration>
<sdk>
<platform>${android.sdk.version}</platform>
<path>${android.sdk.path}</path>
</sdk>
<deleteConflictingFiles>true</deleteConflictingFiles>
<undeployBeforeDeploy>true</undeployBeforeDeploy>
</configuration>
<extensions>true</extensions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3.2</version>
<configuration>
<source>${java.source.version}</source>
<target>${java.target.version}</target>
</configuration>
</plugin>
</plugins>
</build>
<profiles>
<!--The profile to use for the
release android mode-->
<profile>
<id>android-release</id>
<activation>
<!--Just set
the variable release to true-->
<property>
<name>release-mode</name>
<value>true</value>
</property>
</activation>
<build>
<plugins>
<!-- Define
the Proguard plugin to optimize, shrink, obfuscate and
preverify
when compiling-->
<plugin>
<groupId>com.pyx4me</groupId>
<artifactId>proguard-maven-plugin</artifactId>
<version>${proguard.plugin.version}</version>
<!-- Define the execution context (in the
process-class phase) and its
options -->
<executions>
<execution>
<id>process-classes-with-proguard</id>
<phase>process-classes</phase>
<goals>
<goal>proguard</goal>
</goals>
<configuration>
<proguardVersion>${proguard.version}</proguardVersion>
<maxMemory>256m</maxMemory>
<injar>android-classes</injar>
<libs>
<lib>${rt.jar.path}</lib>
<lib>${jsse.jar.path}</lib>
</libs>
<skip>false</skip>
<obfuscate>true</obfuscate>
<addMavenDescriptor>false</addMavenDescriptor>
<proguardInclude>${project.basedir}/proguard.cfg</proguardInclude>
</configuration>
</execution>
</executions>
<!--The
proguard dependencies-->
<dependencies>
<dependency>
<groupId>net.sf.proguard</groupId>
<artifactId>proguard</artifactId>
<version>${proguard.version}</version>
<scope>runtime</scope>
</dependency>
</dependencies>
</plugin>
<!--Define the JarSigner to be
execute during the package phase-->
<plugin>
<artifactId>maven-jarsigner-plugin</artifactId>
<version>${jarsigner.plugin.version}</version>
<inherited>true</inherited>
<executions>
<execution>
<id>sign-application-apk</id>
<phase>package</phase>
<goals>
<goal>sign</goal>
<goal>verify</goal>
</goals>
</execution>
</executions>
<configuration>
<removeExistingSignatures>true</removeExistingSignatures>
<archiveDirectory />
<archive>${project.build.directory}/${project.build.finalName}.${project.packaging}</archive>
<verbose>true</verbose>
<certs>true</certs>
<keystore>${sign.keystore}</keystore>
<alias>${sign.alias}</alias>
<storepass>${sign.storepass}</storepass>
<keypass>${sign.keypass}</keypass>
</configuration>
</plugin>
<!--Define the usage of the maven
android plugin at the package phase-->
<plugin>
<groupId>com.jayway.maven.plugins.android.generation2</groupId>
<artifactId>maven-android-plugin</artifactId>
<version>${jayway.plugin.version}</version>
<executions>
<execution>
<id>zipalign-application-apk</id>
<phase>package</phase>
<goals>
<goal>zipalign</goal>
</goals>
</execution>
</executions>
<configuration>
<undeployBeforeDeploy>true</undeployBeforeDeploy>
<zipalign>
<verbose>true</verbose>
<inputApk>${project.build.directory}/${project.artifactId}-${project.version}.apk</inputApk>
<outputApk>${project.build.directory}/${project.artifactId}-${project.version}-signed-aligned.apk</outputApk>
</zipalign>
<sign>
<debug>false</debug>
</sign>
</configuration>
</plugin>
<!-- Define
the build hepler plugin usage at the phase package that
will
attach additional artifact here the proguard_map -->
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<version>${build.helper.plugin.version}</version>
<configuration>
<artifacts>
<artifact>
<file>${project.build.directory}/proguard_map.txt</file>
<type>map</type>
<classifier>release</classifier>
</artifact>
</artifacts>
</configuration>
<executions>
<execution>
<id>attach-signed-aligned</id>
<phase>package</phase>
<goals>
<goal>attach-artifact</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
</project>
Si vous souhaitez utiliser le Pom Android ultime décrit au chapitre 15.2 Synthèse Android-Maven : le Pom Android ultime, il faut que vous fassiez attention à utiliser le fichier setting.xml configuré pour Hudson. Il n’y a pas de modifications à faire et tout marche comme sur des roulettes.
Démarré par l'utilisateur mseguy
Updating http://ks370153.kimsufi.com/svn/Android
At revision 81
no change for http://ks370153.kimsufi.com/svn/Android since the previous build
Found mavenVersion 2.2.1 from file jar:file:/home/opt/apache-maven-2.2.1/lib/maven-2.2.1-uber.jar!/META-INF/maven/org.apache.maven/maven-core/pom.properties
[android] Using Android SDK: /home/sti/android/android-sdk-linux_x86
[android] Starting Android emulator
$ /home/sti/android/android-sdk-linux_x86/tools/emulator -ports 43055,34905 -no-boot-anim -avd GoogleL9
emulator: ERROR: unknown virtual device name: 'GoogleL9'
emulator: could not find virtual device named 'GoogleL9'
[android] Emulator did not appear to start; giving up
$ /home/sti/android/android-sdk-linux_x86/platform-tools/adb disconnect localhost:34905
[android] Stopping Android emulator
[android] Failed to execute emulator command 'kill': java.net.ConnectException: Connection refused
Finished: NOT_BUILT
Ce problème est lié à la création de vos AVD : Vérifiez que ceux-ci sont bien créés et sinon laissez Hudson les créer. (cf. 15.3.1.2 Problème lors de la création des AVD).
Vérifiez que votre variable est déclarée dans votre fichier de setting ainsi que dans Hudson.
Embedded error: Path "/home/opt/hudson/jobs/MavenAndroidTuto/workspace/trunk/MavenAndroidTuto/trunk/MavenAndroidTuto/D:\Eclipse\eclipsex64_Android_Custo\android-sdk_r08-windows\android-sdk-windows/platforms"
is not a directory. Please provide a proper Android SDK directory path as
configuration parameter <sdk><path>...</path></sdk> in
the plugin <configuration/>. As an alternative, you may add the parameter
to commandline: -Dandroid.sdk.path=... or set environment variable
ANDROID_HOME.
Vérifiez que votre variable est déclarée dans votre fichier de setting ainsi que dans Hudson.
Cela signifie que le mieux est que dans Hudson vous cochiez la case « reset emulator state at start up » au niveau de la configuration de votre projet.