Android, A Complete Course, From Basics to Enterprise Edition

Maven.

Android, A Complete Course, From Basics to Enterprise Edition. 1

Composants graphiques complexes Android. 1

1       Maven et Intégration continue. 1

1.1         Maven. 1

 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 :

http://android2ee.com.

La propriété intellectuelle du code appartient à :

Mathias Séguy

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

1         Maven et Intégration continue

1.1       Maven

http://www.sonatype.com/books/mvnref-book/reference/android-dev.html

1.1.1       Installer Maven

Tout d’abord, il vous faut installer Maven sur votre poste de travail : http://maven.apache.org/download.html et télécharger la dernière distribution de Maven. Il vous faut ensuite, décompresser cette archive puis :

·         Rajouter la variable d’environnement : M2_HOME en lui indiquant le chemin de votre dossier décompressé.

·         Rajouter dans votre path system la variable %M2_HOME%\bin

La page http://maven.apache.org/download.html explique en détail les opérations à effectuer (en bas de page).

1.1.2       Premier contact avec Maven

Arrêtons de penser « Android » un instant et revenons à une pensée « Java ».

L'objectif de Maven est de rationaliser au moyen de normes et d'outils le cycle de vie d'un projet. Cela signifie gérer la compilation, le passage des tests unitaires, le packaging, le déploiement, les rapports du projet (java doc, rapports de tests, PMD), la liaison avec un outil de versionning des sources, la liaison avec un outil d'intégration continue....

Pour cela Maven propose des outils et des normes.

Les outils permettent de s'abstraire de l'écriture de ces taches (MakeFile, Ant). La normalisation permet à tout développeur de passer d'un projet Maven à un autre sans être perdu. Le fichier POM (Project Object Model) est un fichier normalisé qui décrit le projet et permet à Maven de lui faire suivre un cycle de vie.

Mais commençons par le commencement et construisons un premier projet Maven.

1.1.2.1       Premier Pom

Créer un projet MyProject

Créer un fichier pom.xml dans MyProject et y écrire le contenu détaillé ici :

 <project>

   <modelVersion>4.0.0</modelVersion>

   <groupId>com.mycompany.myproject</groupId>

   <artifactId>MyProject</artifactId>

   <version>SNAPSHOT</version>

 </project>

 

Créer le dossier src/main/java/com/mycompany/myproject dans MyProject

Écrire le source src/main/java/com/mycompany/myproject/Person.java dedans

package com.mycompany.myproject;

                 public class Person {

                    public String name;

                    public String telephone;

                    public String email;

                    public String toString() {

                        return new StringBuilder()

                            .append(name).append(",")

                            .append(telephone).append(",")

                            .append(email).toString();

                    }

                 }

Compiler et packager: Effectuez "mvn package" dans le dossier MyProject

[INFO] Building jar: /MyProject/target/MyProject-SNAPSHOT.jar

[INFO] ------------------------------------------------------------------------

[INFO] BUILD SUCCESSFUL

[INFO] ------------------------------------------------------------------------

Les sources du projet sont compilées dans target/classes

Le projet est packagé dans target/MyProject-SNAPSHOT.jar

1.1.2.2       Que s'est il passé ?

1.1.2.2.1        Coordonnées d'un projet

Tout d'abord, Maven propose un système de coordonnées sur l'espace de tous les projets informatiques. Ces coordonnées possèdent trois variables (comme la notion de latitude, longitude, altitude) qui sont:

 groupId: Identifiant du groupe (organisation, équipe, compagnie, ou toute autre notion de groupe de développement). La convention est de commencer par le nom de domaine de l'organisation (comme pour le package root java du projet) qui est com, net, org... Exemple:net.fr.tlse.sti.android

artifactId: Identifiant du projet au sein de l'ensemble des projets appartenant au groupId. Il ne faut pas utiliser de « . » dans le nom des artifactId.

version: Identifiant de la version à construire. Il y en a de deux types distincts, le premier est celui connu de tous (un numéro de version normal) et le second s'appelle SnapShot. Par convention, pour un numéro de version normal, cet identifiant doit être:

<major version>.<minor version>.<incremental version>-<qualifier>

Ce qui donne par exemple 2.1.0-alpha. Le qualifier n'est pas obligatoire, les autres sont fortement recommandés. Une version de type SnapShot est en fait une syntaxe permettant de construire des versions (typiquement au cours du build de la nuit) nommées en utilisant le jour où a eu lieu le build. Cette syntaxe est à utiliser pour un projet en cours de développement qui n'atteint pas une version mais qui effectue des build réguliers (soit pour une intégration continue, soit pour une mise à disposition du source pour d'autres modules, projets).

Une quatrième notion d'identifiant est la suivante:

Classifier : Permet d'ajouter à une coordonnée (donc un même projet avec une même version i.e. Le même code) une information supplémentaire. Cela peut être le type de JDK utilisé pour le build, ou la plateforme de destination,... C'est une possibilité pour permettre d'ajouter de l'information à un même code qui n'est pas packagé de la même manière. En d'autre termes, un projet qui sera compilé avec le JDK 1.3 et le JDK 1.6 et qui n'a pas de code modifié utilisera la notion de classifier pour distinguer les deux builds.

Ainsi notre premier POM définit le projet (son nom unique et exact).

1.1.2.2.2        Convention sur la structure d'un projet.

Par convention, Maven suppose que la structure du projet est la suivante:

my-app

|-- pom.xml

`-- src

    |-- main

    |   |-- java

    |   |   `-- com

    |   |       `-- mycompany

    |   |           `-- app

    |   |               `-- App.java

    |   `-- resources

    |       |-- com

    |                  `-- mycompany

    |                      `-- app

    |                          `-- App.properties

    `-- test

        |-- java

        |   `-- com

        |       `-- mycompany

        |           `-- app

        |               `-- AppTest.java

        `-- resources

            `-- com

             `-- mycompany

                   `-- app

                       `-- AppTest.properties

 

Ainsi il n'a pas besoin d'informations supplémentaires pour compiler, packager ou tester un projet. Le respect de cette structure permet à Maven d'effectuer les actions sur le projet. C'est pour cette raison que la classe a été positionnée dans le répertoire src/main/java/com/mycompany/myproject.

Dans le cas d’Android, cette structure ne peut être respectée, elle est en opposition avec la structure imposée pour un projet Android, c’est à Maven de s’adapter et non pas à Android.

1.1.2.2.3        Cycles de vie d'un build de projet.

Pour maven la construction d'un projet s'effectue toujours étape par étape. Chaque phase étant nécessaire pour que la phase suivante s'effectue. Chaque étape peut se composer de plusieurs sous taches, objectif (goal). La liste des taches pour un build est:

Validate : Valide que le projet est correct et que toutes les informations nécessaires sont présentes.

Compile : Compile le code source du projet

Test : Teste le code source compilé en utilisant le framework de tests disponible. Ces tests ne nécessitent pas que le code soit déployé ou packagé.

Package : Package le code compile dans son format de distribution cible (Jar, War, Apk).

Integration-test : Génère et déploie le package si nécessaire dans un espace d’intégration pour effectuer les tests d’intégration.

Verify : Lance les vérifications permettant d’assurer que le package est valide et les critères de qualité rencontrés.

Install : Installe le package dans le repository local pour être utilisé en tant que dépendance vers les projets locaux qui le référence.

Deploy: Effectué dans un espace d’intégration ou de production, elle copie le package final dans le repository distant permettant son partage avec d’autres développeurs et projets.

Ainsi pour que maven effectue une tâche, il suffit de le lui indiquer. Ainsi pour lancer:

·         la compilation: « mvn:package » suffit,

·         les tests, « mvn:verify » suffit,

·         le partage avec d'autres projets, « mvn:install » doit être appelé (le package est déployé dans le repository local).

Chaque phase contient un ensemble d'objectifs. Chaque phase est liée à un goal principal, c'est lui qui est appelé lors du mvn:***. Ce mapping est partiellement reproduit ci dessous.

 

Etape (ou phase)

But (ou goals)

process-resources

resources:resources

compile

compiler:compile

process-test-resources

resources:testResources

test-compile

compiler:testCompile

test

surefire:test

package

jar:jar

install

install:install

deploy

deploy:deploy

 

1.1.3       Installation

1.1.3.1       Installer Maven

Ce paragraphe est une copie du paragraphe 15.1.1

Tout d’abord, il vous faut installer Maven sur votre poste de travail : http://maven.apache.org/download.html et télécharger la dernière distribution de Maven. Il vous faut ensuite, décompresser cette archive puis :

·         Rajouter la variable d’environnement : M2_HOME en lui indiquant le chemin vers votre dossier décompressé.

·         Rajouter dans votre path system la variable %M2_HOME%\bin

La page http://maven.apache.org/download.html explique en détail les opérations à effectuer (en bas de page).

1.1.3.2       Installer les artifacts Android dans le repository Maven

Un utilitaire est disponible pour effectuer cette opération à l’adresse suivante : http://github.com/mosabua/maven-android-sdk-deployer

Il  faut télécharger les sources et les décompresser sur votre ordinateur. Ensuite, en ligne de commande, il faut se placer dans le dossier décompressé et lancer la commande mvn clean install. Cela installera l’ensemble des jars Android et Google sous votre repository maven .m2/.

1.1.3.3       Mettre à jour votre fichier Maven setting.xml

Il ne reste plus qu’à mettre à jour votre fichier setting.xml pour permettre à Maven d’utiliser le plugin Android-Maven.

Il y a deux fichiers setting.xml (voir n). L'un se trouve %M2_HOME%/conf/setting.xml et l'autre sur User/.m2/setting.xml. Le premier sera visible par tous les utilisateurs de la machine, le second uniquement par l'utilisateur User.

Il est recommandé pour les postes de travail sur lequel ne travaille qu'un utilisateur de le mettre dans %M2_HOME%/conf/setting.xml et surtout de ne pas écrire dans l'un ou dans l'autre à moins d'avoir des raisons vraiment valables.

 Le fichier setting possède la structure suivante:

<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 />

                <interactiveMode />

                <usePluginRegistry />

                <offline />

                <pluginGroups />

                <servers />

                <mirrors />

                <proxies />

                <profiles />

                <activeProfiles />

</settings>

 

Il vous faut rajouter le code suivant dans le bloc pluginGroup :

<pluginGroups>

   <pluginGroup>

     com.jayway.maven.plugins.android.generation2

   </pluginGroup>

</pluginGroups>

1.1.4       Mavenisation de votre projet

1.1.4.1       Mavenisation du projet

Dans Eclipse, faites un clic droit sur votre projet Maven->Enable Depencies. Cela ouvre une boite de dialogue qui vous demande :

·         Le GroupId de votre projet, cela correspond au package root de votre projet ( NomDeDomaineDeLOrganisation.Organisation.PackageRoot, exemple : net.stinfoservices.android.tuto.maven),

·         L’ArtifactId de votre projet, cela correspond à l’identifiant de votre projet au sein des projets appartenant à votre GroupId (si votre group id est suffisamment précis, le nom de votre projet suffit),

·         La version de votre projet,

·         Le packaging de votre projet qui est apk (c’est le packaging pour les projets Android, même si ce type n’est pas listé dans le wizard),

·         Le nom et la description sont des paramètres optionnels.

Il ne vous reste plus qu’à mettre à jour votre fichier Pom :

<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>

   <dependencies>

          <dependency>

              <groupId>android</groupId>

              <artifactId>android</artifactId>

              <version>2.3_r1</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>2.8.3</version>

                  <configuration>

                      <sdk>

                          <platform>2.3</platform>

                      </sdk>

                      <deleteConflictingFiles>

                        true

                      </deleteConflictingFiles>

                  </configuration>

                  <extensions>true</extensions>

              </plugin>

              <plugin>

                               <groupId>org.apache.maven.plugins</groupId>

                               <artifactId>maven-compiler-plugin</artifactId>

                               <version>2.3.2</version>

                  <configuration>

                      <source>1.6</source>

                      <target>1.6</target>

                  </configuration>

              </plugin>

          </plugins>

      </build>

  </project>

Il vous faut remplacer les versions suivantes dans ce fichier Pom : la version de la dépendance Android, la version du plugin jayway.

1.1.4.1.1        Gérer les versions

La dépendance Android doit avoir le même numéro de version que votre projet (suivi de _r1 ou _r2) et pointe soit vers Android soit vers Google. Pour une dépendance vers Google il faut que vous mettiez le bloc :

<dependency>

                <groupId>com.google.android</groupId>

                <artifactId>android</artifactId>

                <version>2.3.1</version>

</dependency>

Dans ce cas, le numéro de version n’est pas suffixé par _r1 ou _r2.

Le lien entre la plateforme et l’API level est le suivant :

Real Name[1]

Target name

Platform (version)

API Level

Google Inc.:Google APIs:3

Google APIs (Google Inc.)

1.5

3

Google Inc.:Google APIs:4

Google APIs (Google Inc.)

1.6

4

Google Inc.:Google APIs:7

Google APIs (Google Inc.)

2.1-update

7

Google Inc.:Google APIs:8

Google APIs (Google Inc.)

2.2

8

Google Inc.:Google APIs:9

Google APIs (Google Inc.)

2.3

9

Google Inc.:Google APIs:10

Google APIs (Google Inc.)

2.3.3

10

Google Inc.:Google APIs:11

Google APIs (Google Inc.)

3.0

11

android-3

Android 1.5

1.5

3

Android-4

Android 1.6

1.6

4

Android-7

Android 2.1-update1

2.1-update

7

Android-8

Android 2.2

2.2

8

Android-9

Android 2.3

2.3

9

Android-10

Android 2.3.3

2.3.3

10

Android-11

Android 3.0

3.0

11

 

La version du plugin Android (com.jayway.maven.plugins.android.generation2) doit être la dernière version de ce plugin. Pour la connaitre, rendez vous sur http://mvnrepository.com/artifact/com.jayway.maven.plugins.android.generation2/maven-android-plugin et recopiez le numéro le plus récent de la liste.

1.1.4.1.2        Modifier le BuildPath au sein d’Eclipse

Il faut que vous rajoutiez à votre build path, le dossier target/generated-source/r en tant que fichier source pour qu’Eclipse puisse retrouver les fichiers de ressources générés et construire le projet.

Ce qui revient à rajouter la ligne suivante au fichier .classpath de votre projet:

<classpathentry kind="src" path="target/generated-sources/r"/>

1.1.4.1.3        Lancer le build

Pour lancer le build, faites, clic droit sur le projet, Run As->Maven Install.

Pour lancer automatiquement un déploiement, il vous faut enregistrer une configuration de Run dans Eclipse qui lance les goals « mvn clean install android:deploy ». Pour cela, clic droit sur le projet, Run As-> Run Configuration…

Dans la fenêtre qui s’ouvre, vous devez sélectionner « Maven Build » puis appuyer sur le bouton new (icône en haut à droite). Mettez le nom de votre configuration, par exemple « Android Deploy  NomDeVotreProjet ». Dans le champ base directory, sélectionnez la racine de votre projet. Dans le champ goal, mettez « clean install android:deploy ».

Dans ce cas, il faut que votre émulateur soit déjà lancé, sinon vous aurez une erreur de type « device not found ».

Enfin, si vous souhaitez pointer vers un Android Sdk spécifique (ou que vous n’avez pas déclaré votre variable d’environnement Android_Home), vous devez ajouter ce chemin dans le bloc de configuration qui déclare la version du SDK Android à utiliser :

<sdk>

            <platform>2.3</platform>

            <path>D:\Eclipse\eclipsex64_Android_Custo\android-sdk_r10-windows\android-sdk-windows</path>

</sdk>

 

1.1.4.2       Ajouter GoogleMap

Il suffit d’ajouter l’une des dépendances suivantes (en fonction de la version du SDK Android que vous utilisez)

<dependency>

    <groupId>com.google.android.maps</groupId>

    <artifactId>maps</artifactId>

    <version>3_r3</version>

    <scope>provided</scope>

</dependency>

 

<dependency>

    <groupId>com.google.android.maps</groupId>

    <artifactId>maps</artifactId>

    <version>4_r1</version>

    <scope>provided</scope>

</dependency>

 

<dependency>

    <groupId>com.google.android.maps</groupId>

    <artifactId>maps</artifactId>

    <version>7_r1</version>

    <scope>provided</scope>

</dependency>

 

<dependency>

    <groupId>com.google.android.maps</groupId>

    <artifactId>maps</artifactId>

    <version>8_r1</version>

    <scope>provided</scope>

</dependency>

 

 

1.1.4.3       Les quelques détails qui feraient que rien ne marche

Si débute une guerre sans fin entre vous et votre tache mvn:install, vérifiez les éléments suivants :

·         La première chose à faire est de vérifier que votre fichier setting.xml est bien à jour.

·         Vous devez aussi  revérifier que vos numéros de versions sont cohérents.

·         Vous devez vérifier que votre variable d’environnement Android_Home est bien positionnée ou que vous avez déclaré votre SDK Android dans votre fichier pom.xml sous la version du SDK Android.

·         Et enfin, essayez de faire clic droit sur votre projet Maven->Updates Dependencies

Enfin, si vous obtenez une erreur du type :

C:\Android\android-sdk_r07-windows\android-sdk-windows/platform-tools/dx.bat [--dex, --output=C:\Users\David\Development Workspace\MartiniLocker\target\classes.dex, C:\Users\David\Development Workspace\MartiniLocker\target\android-classes]
[INFO] =C:\Users\David\Development was unexpected at this time.
Ou
[INFO] =C:\Users\David\Development est inattendu.
 

C’est que votre chemin vers votre fichier Pom possède des espaces, et là, la seule chose qu’il vous reste à faire c’est de pleurer puis de renommer votre chemin en supprimant les espaces (Attention au nom de votre workspace Eclipse) (http://code.google.com/p/maven-android-plugin/issues/detail?id=115&colspec=ID%20Type%20Component%20OpSys%20Status%20Priority%20Milestone%20Owner%20Summary ).

1.1.5       Les « goals » principaux du plugin maven

1.1.5.1       Android:apk

Ce goal permet de générer l’application au format apk.

1.1.5.2        Android:deploy

Ce goal permet de construire l’application et de la déployer sur un émulateur déjà connecté (déjà lancé). Il est lancé automatiquement lors de mvn:install.

1.1.5.3       Android:deploy-dependencies

Ce goal permet de déployer les dépendances de type apk sur l’émulateur. Son utilisation la plus courante est lors des tests, il permet de déployer l’application à tester.

Il est lancé automatiquement lors de mvn:install.

1.1.5.4       Android:emulator-strart Android:emulator-stop

Ce goal permet de lancer l’émulateur ou de l’arrêter. Nous y revenons dans un chapitre dédié au lancement de l’émulateur.

1.1.6       Utilisation des archétypes Android

L’utilisation des archétypes Maven permet de créer des projets pré-structurés. Nous présentons ici les trois archétypes (QuickStart, WithTest et Release) qui permettent de mettre en place un projet Android. L’idée est de commencer sur un projet qui possède déjà toute la structure souhaitée et de pouvoir se concentrer sur le code directement.

Ces archétypes sont donnés à la communauté par akquinet A.G et se trouve à la page suivante :

https://github.com/akquinet/android-archetypes/wiki

Une fois que votre projet est créé, vous pouvez le déplacer dans votre workspace Eclipse et faire menu File ->import->import Maven Project. Votre projet est alors importé dans votre workspace.

1.1.6.1       Important

Pour tous ces archétypes, il vous faut rajouter dans le manifeste de votre projet la ligne spécifiant la version minimale du SDK à utiliser :

<uses-sdk android:minSdkVersion="3" />

1.1.6.2       L’archétype QuickStart

Dans votre shell, taper la commande :

mvn archetype:generate   -DarchetypeArtifactId=android-quickstart   -DarchetypeGroupId=de.akquinet.android.archetypes   -DarchetypeVersion=1.0.4   -DgroupId=your.company   -DartifactId=my-android-application

 

Il crée un projet Maven élémentaire qu’il vous suffit d’importer dans Eclipse pour avoir le squelette d’une application Android mavenisée. Ce projet est créé là où vous avez lancé la commande dans votre shell (si vous êtes sous myPath>, le projet sera créé sous myPath\).

Le projet généré est le suivant :

1.1.6.2.1        Son fichier POM

Le fichier POM de ce projet est le suivant :

<?xml version="1.0" encoding="UTF-8"?>

<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/maven-v4_0_0.xsd">

  <modelVersion>4.0.0</modelVersion>

  <groupId>net.stinfoservices.android.tuto.maven</groupId>

  <artifactId>myQuickStartTuto</artifactId>

  <version>1.0</version>

  <packaging>apk</packaging>

  <name>myQuickStartTuto</name>

 

  <dependencies>

    <dependency>

      <groupId>com.google.android</groupId>

      <artifactId>android</artifactId>

      <version>2.2.1</version>

      <scope>provided</scope>

    </dependency>

  </dependencies>

 

  <build>

    <plugins>

 

      <plugin>

        <!-- Simply read properties from file -->

        <groupId>org.codehaus.mojo</groupId>

        <artifactId>properties-maven-plugin</artifactId>

        <version>1.0-alpha-2</version>

        <executions>

          <execution>

            <phase>initialize</phase>

            <goals>

              <goal>read-project-properties</goal>

            </goals>

            <configuration>

              <files>

                <file>android.properties</file>

              </files>

            </configuration>

          </execution>

        </executions>

      </plugin>

 

      <plugin>

        <groupId>com.jayway.maven.plugins.android.generation2</groupId>

        <artifactId>maven-android-plugin</artifactId>

        <version>2.8.3</version>

        <configuration>

          <androidManifestFile>${project.basedir}/AndroidManifest.xml</androidManifestFile>

          <assetsDirectory>${project.basedir}/assets</assetsDirectory>

          <resourceDirectory>${project.basedir}/res</resourceDirectory>

          <nativeLibrariesDirectory>${project.basedir}/src/main/native</nativeLibrariesDirectory>

          <sdk>

            <!-- Defined in the android.properties file -->

            <platform>7</platform>

          </sdk>

          <deleteConflictingFiles>true</deleteConflictingFiles>

          <undeployBeforeDeploy>true</undeployBeforeDeploy>

        </configuration>

        <extensions>true</extensions>

      </plugin>

 

      <plugin>

        <artifactId>maven-compiler-plugin</artifactId>

        <version>2.3.2</version>

        <configuration>

          <source>1.5</source>

          <target>1.5</target>

        </configuration>

      </plugin>

    </plugins>

  </build>

</project>

Ce fichier POM définit les éléments suivants :

·         Son identité (Son GroupId, son ArtifactID, Sa version, son packaging et son nom)

·         Ses dépendances : ici uniquement le jar Android dans sa version 2.2.1

·         Les plugins utilisés pour la construction de l’apk :

o   Le plugin properties-maven-plugin qui initialise la lecture des propriétés du projet

o   Le plugin maven-android-plugin qui compile le projet en un composant apk. Il utilise la définition des éléments principaux du projet (la localisation du dossier asset, du dossier ressources, du manifeste Android, ainsi que la localisation des libs) et définit la version du SDK Android à utiliser.

o   Le plugin de compilation Java qui définit la version du SDK Java à utiliser.

Si vous souhaitez modifier la version du SDK Android à utiliser, vous devez aussi le modifier dans le fichier android.properties de votre projet.

Par défaut, les librairies à utiliser se trouvent sous ${project.basedir}/libs. En d’autres termes, la valeur de la propriété nativeLibrariesDirectory est ${project.basedir}/libs, celle-ci a été redéfinie, je ne sais pas pourquoi.

 

1.1.6.3       L’archétype Android-With-Test

Dans votre shell, taper la commande :

mvn archetype:generate   -DarchetypeArtifactId=android-with-test   -DarchetypeGroupId=de.akquinet.android.archetypes   -DarchetypeVersion=1.0.4   -DgroupId=your.company   -DartifactId=my-android-application

 

Il crée deux projets Eclipse en tant que projet Maven de type multi-modules. Ces deux projets sont assez étonnants, le projet de test qui apparaît n’est qu’un duplicata (logique) de celui du projet principal. Le projet principal qui contient votre application, possède :

·         Le Pom parent

·         Une arborescence pour le projet de l’application,

·         Une arborescence pour le projet de test.

Ce projet Eclipse est ainsi complet. Le second projet est le projet de tests spécifique externalisé. Il n’est qu’une vue du projet de tests du projet principal. Il pointe vers le Pom parent du projet principal et est un pointeur vers l’arborescence de test du projet principal.

Les projets sont les suivants :

Et le projet de tests uniquement :

Il est important de bien comprendre que le projet Eclipse de test MonProjet-it est une vue du projet de test qui appartient à votre projet principal. Toute modification de l’un modifie l’autre. Cette structure permet de marier les deux philosophies associées aux tests (projet de tests externalisé ou plongé dans le projet principal).

1.1.6.4       L’archétype Android-Release

Dans votre shell, taper la commande :

mvn archetype:generate   -DarchetypeArtifactId=android-release   -DarchetypeGroupId=de.akquinet.android.archetypes   -DarchetypeVersion=1.0.4   -DgroupId=your.company   -DartifactId=my-android-application

Le projet généré est une extension du projet associé à l’archétype Android-With-Test. Il met en plus en place un système de profil permettant la génération de l’application finale prête à être déployée sur le Market (elle est signée et optimisée). La structure des projets générés par ces deux archétypes (with-test et release) est identique.

Pour l’utiliser il faut modifier votre fichier setting.xml associé à Maven et rajouter le code suivant :

<profile>

  <id>android-release</id>

  <properties>

    <sign.keystore>/path/to/keystore</sign.keystore>

    <sign.alias>key alias</sign.alias>

    <sign.storepass>keystore password</sign.storepass>

    <sign.keypass>key password</sign.keypass>

  </properties>

</profile>

Dans ce profil, vous définissez le chemin vers votre KeyStore, l’alias de la clef à utiliser, le mot de passe du KeyStore ainsi que celui de votre clef. Ce profil sera utilisé pour signer votre application lors du build (mvn:install).

1.1.7        Signer son application

Pour signer automatiquement votre application, il suffit d’ajouter dans votre fichier pom.xml le bloc suivant dans la balise <build><pluginManagement><plugins>:

<plugin>

                <groupId>org.apache.maven.plugins</groupId>

                <artifactId>maven-jarsigner-plugin</artifactId>

                <version>1.2</version>

                <executions>

                               <execution>

                                               <id>signing</id>

                                               <goals>

                                                               <goal>sign</goal>

                                               </goals>

                                               <phase>package</phase>

                                               <inherited>true</inherited>

                                               <configuration>

                                                               <includes>

                                                                              <include>

                                               ${project.build.directory}/target/${project.artifactId}-${project.version}.apk

                                                                              </include>

                                                               </includes>

                                                               <keystore>${keystore.location}</keystore>

                                                               <storepass>${keystore.password}</storepass>

                                                               <keypass>${keystore.keypass}</keypass>

                                                              <alias>${keystore.alias}</alias>

                                                               <verbose>true</verbose>

                                               </configuration>

                               </execution>

                </executions>

</plugin>

Ce plugin permet de spécifier que dans la phase package de l’application, il lance le but sign sur l’apk qui vient d’être construit en utilisant la clef dont le nom est keyStore.alias, le mot de passe keystore.keypass qui se trouve dans le keyStore keyStore.location dont le mot de passe est keyStore.password.

Pour que cela fonctionne, il faut modifier votre fichier setting.xml associé à Maven et rajouter le code suivant :

<profile>

  <id>android-release</id>

  <properties>

    <sign.keystore>/path/to/keystore</sign.keystore>

    <sign.alias>key alias</sign.alias>

    <sign.storepass>keystore password</sign.storepass>

    <sign.keypass>key password</sign.keypass>

  </properties>

</profile>

Dans ce profil, vous définissez le chemin vers votre KeyStore, l’alias de la clef à utiliser, le mot de passe du KeyStore ainsi que celui de votre clef. Ce profil sera utilisé pour signer votre application lors du build (mvn:install).

Sinon, vous pouvez aussi remplacer dans votre fichier pom.xml les variables du KeyStore par leurs valeurs, mais dans ce cas, votre projet se construira uniquement sur votre machine, vous pouvez dire au revoir à l’intégration continue.

1.1.8       Lancer l’émulateur

Pour pouvoir lancer l’émulateur lors de la compilation et ainsi mettre en place le déploiement automatique de votre apk lorsque celui-ci est construit, il faut tout d’abord définir l’émulateur cible dans votre fichier pom.xml. Cette déclaration s’effectue dans la partie configuration du plugin maven-android-plugin :

<plugin>

                <groupId>

                 com.jayway.maven.plugins.android.generation2

               </groupId>

                <artifactId>maven-android-plugin</artifactId>

                <version>2.8.3</version>

                <configuration>

                               <sdk>

                                               <platform>2.3</platform>

                                               <path>D:\Eclipse\android-sdk_r08-windows\android-sdk-windows</path>

                               </sdk>

                               <deleteConflictingFiles>

                                               true

                                </deleteConflictingFiles>

                               <emulator>

                                               <avd>Android2Dot3Bis</avd>

                                               <wait>6000</wait>

                               </emulator>

                </configuration>

                <extensions>true</extensions>

</plugin>

L’AVD que vous déclarez est un AVD que vous avez défini dans votre SDK Android, soit via Eclipse (avec le bouton Android SDK and AVD Manager) soit en ligne de commande. La balise wait permet de définir le temps d’attente avant d’essayer de déployer l’apk sur l’émulateur. Ce temps d’attente correspond au temps de lancement de l’émulateur.

Dans l’exemple, celui-ci pointe vers l’AVD Android2Dot3 défini ci-dessous :

Ensuite, vous pouvez utiliser la tache maven « clean install andoird:start-emulator android:deploy » pour effectuer la compilation et le déploiement. En effet la tache mvn android:start-emulator démarre l’émulateur et la tache mvn android:stop-emulator le stoppe.

Ou vous pouvez modifier votre fichier Pom, en lui ajoutant la commande de lancer l’émulateur au démarrage du build :

<plugin>

                <groupId>com.jayway.maven.plugins.android.generation2</groupId>

                <artifactId>maven-android-plugin</artifactId>

                <version>2.8.3</version>

                <configuration>

                               <sdk>

                                               <platform>2.3</platform>

                                               <path>D:\Eclipse\ android-sdk_r08-windows\android-sdk-windows</path>

                               </sdk>

                               <deleteConflictingFiles>

                                               true

                                </deleteConflictingFiles>

                               <emulator>

                                               <avd>Android2Dot3Bis</avd>

                                               <wait>6000</wait>

                               </emulator>

                </configuration>

                <executions>

                               <execution>

                                               <id>startEmulator</id>

                                               <phase>initialize</phase>

                                               <goals>

                                                               <goal>emulator-start</goal>

                                               </goals>

                               </execution>

                </executions>

                <extensions>true</extensions>

</plugin>

Dans ca cadre, votre émulateur sera lancé lors de la phase d’initialisation du cycle de vie de Maven. Vous pouvez aussi vouloir arrêter l’émulateur quand le passage des tests est terminé (la phase « instrumentation tests »), dans ce cas il suffit d’ajouter le bloc :

<executions>

                               <execution>

                                               <id>startEmulator</id>

                                               <phase>initialize</phase>

                                               <goals>

                                                               <goal>emulator-start</goal>

                                               </goals>

                               </execution>

<execution>

                                               <id>stopEmulator</id>

                                               <phase>install</phase>

                                               <goals>

                                                               <goal>emulator-stop</goal>

                                               </goals>

                               </execution>

 

</executions>

 

1.1.9       Utilisation de profil Maven

L’utilisation des profils Maven a pour but :

·         de pouvoir lancer des campagnes de tests sur plusieurs émulateurs de manière automatique avec Hudson,

·         de pouvoir signer ou pas son application et de l’optimiser en fonction du contexte « développement » ou « production »,

·         d’utiliser des variables spécifiques à votre environnement de développement.

 

1.1.9.1       La notion de profil avec Maven

Oublions Android quelques instants et penchons nous sur la notion des profils Maven.

Les profils permettent de spécifier le comportement d'un fichier Pom en fonction d'un profil. Ainsi, dans le fichier POM on peut ajouter des Profils. Chaque Profil surchargera un ou plusieurs blocs du POM qui le contient de manière à spécifier un comportement lors du build. Ce comportement spécifique sera attaché au profil. Chaque profil possède un identifiant unique: son id. Pour lancer un build avec un profil spécifique il suffit d'utiliser la commande :mvn **:** -PmonProfilId. La notion de Profil s'hérite entre fichier POM.

Un exemple typique est l'utilisation d'un profil dev (pour développement) et d'un profil prod (pour production). L'un mappant avec la base de données utilisée pour le développement avec des options de compilation non optimisées en debug, l'autre avec la base de données de production et dont la compilation sera optimisée sans le mode debug.

Ce qui s'implémente (sans mettre les bases de données) dans le fichier Pom de la manière suivante:

 

<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/maven-v4_0_0.xsd">

<modelVersion>4.0.0</modelVersion>

<groupId>monGroupId</groupId>

<artifactId>simple</artifactId>

<packaging>jar</packaging>

<version>1.0</version>

<name>simple</name>

<profiles>

                <profile>

                               <id>prod</id>

                                               <build>

                                               <plugins>

                                                               <plugin>

                                                                              <groupId>org.apache.maven.plugins</groupId>

                                                                              <artifactId>maven-compiler-plugin</artifactId>

                                                                              <configuration>

                                                                                              <debug>false</debug>

                                                                                              <optimize>true</optimize>

                                                                              </configuration>

                                                              </plugin>

                                               </plugins>

                               </build>

                </profile>

                <profile>

                               <id>dev</id>

                               <build>

                                               <plugins>

                                                               <plugin>

                                                                              <groupId>org.apache.maven.plugins</groupId>

                                                                              <artifactId>maven-compiler-plugin</artifactId>

                                                                              <configuration>

                                                                                              <debug>true</debug>

                                                                                              <optimize>false</optimize>

                                                                              </configuration>

                                                               </plugin>

                                               </plugins>

                               </build>

                </profile>

</profiles>

</project>

 

Les profils permettent de surcharger un ensemble de bloc du fichier POM initial, ces blocs sont les suivants:

 

<project>

                <profiles>

                               <profile>

                                               <id>monProfilId</id>

                                               <build>

                                                               <defaultGoal>...</defaultGoal>

                                                               <finalName>...</finalName>

                                                               <resources>...</resources>

                                                               <testResources>...</testResources>

                                                               <plugins>...</plugins>

                                               </build>

                                               <reporting>...</reporting>

                                               <modules>...</modules>

                                               <dependencies>...</dependencies>

                                               <dependencyManagement>...</dependencyManagement>

                                               <distributionManagement>...</distributionManagement>

                                               <repositories>...</repositories>

                                               <pluginRepositories>...</pluginRepositories>

                                               <properties>...</properties>

                               </profile>

                </profiles>

</project>

 

1.1.9.1.1        Externalisé les Profiles du POM

Les profils peuvent être définis dans un fichier profils.xml (qui doit se trouver à côté du fichier Pom). Cela permet de ne pas avoir un fichier Pom trop illisible. Mais le processus est le même, à la lecture du fichier POM, Maven merge les deux documents (ce qui peut avoir des effets déroutants si les profils sont définis dans le fichier POM aussi).

1.1.9.1.2        Activation d'un profil

Un profil peut s'activer (et même s'auto activer) en utilisant des conditions d'activation, ces conditions portent sur:

·         la valeur d'une propriété (JDK, l'os, une propriété spécifiée dans le POM parent...)

·         l'absence de l'existence d'une propriété

·         l'absence ou l'existence d'un fichier

·         la définition des profils actifs définis dans le fichier setting.xml

Ainsi le profil suivant :

<profile>

                <id>jdk16</id>

                <activation>

                               <jdk>1.6</jdk>

                </activation>

                <modules>

                               <module>simple-script</module>

                </modules>

</profile>

 

S’activera automatiquement dès que le jdk1.6 sera détecté par Maven (plus besoin de faire mvn **:** -Pjdk16).

Les propriétés natives qui peuvent être testées par l'activation sont les suivantes:

<activation>

                <activeByDefault>false</activeByDefault>

                <jdk>1.5</jdk>

                <os>

                               <name>Windows XP</name>

                               <family>Windows</family>

                               <arch>x86</arch>

                               <version>5.1.2600</version>

                </os>

                <property>

                               <name>mavenVersion</name>

                               <value>2.0.5</value>

                </property>

                <file>

                               <exists>file2.properties</exists>

                               <missing>file1.properties</missing>

                </file>

</activation>

 

Pour tester l'existence d'une propriété pour l'activation :

<activation>

                <property>

                               <name>!environment.type</name>

                </property>

</activation>

 

1.1.9.1.3        Le fichier setting.xml et les Profils

Comme nous l'avons vu dans le précédent chapitre, le fichier setting permet de centraliser certaines informations qui seront partagées par tous les fichiers POM pour un même utilisateur (ou pour tous les utilisateurs) d'une machine. Parmi ces informations les Profils ont une place importante.

En effet, reprenons l'exemple du profil dev et du profil prod. Il paraît naturel que tous les projets (du poste de travail) partagent ces profils sans avoir à les répéter dans chaque fichier POM. Pour cela, il faut les définir dans le fichier setting.xml. Le problème étant qu’au sein du fichier setting, aucun élément du build ne peut-être redéfini. Il faut donc n’y mettre que des propriétés :

<setting>

                <profiles>

                               <profile>

                                               <id>dev</id>

                                               <properties>

                                                               <environment.type>dev</environment.type>

<compiler.debug>true</compiler.debug>

                                                               <compiler.optimize>false</compiler.optimize>

                                               </properties>

                               </profile>

                               <profile>

                                               <id>prod</id>

                                               <properties>

                                                               <environment.type>dev</environment.type>

<compiler.debug>false</compiler.debug>

                                                               <compiler.optimize>true</compiler.optimize>

                                               </properties>

                               </profile>

</setting>

Ces profils et leurs propriétés sont visibles par tous les projets (de l'utilisateur ou des utilisateurs du poste de travail). Nous utilisons ces propriétés pour spécifier le comportement du build dans chacun des Pom :

<build>

<pluginManagement>

                <plugins>                             

<!-- Plugin de la compilation Java du projet -->

<plugin>

                <artifactId>maven-compiler-plugin</artifactId>

                <version>2.3.2</version>

                <inherited>true</inherited>

                <configuration>

                               <source>${java.source.version}</source>

                               <target>${java.target.version}</target>

                               <debug>${compiler.debug}</debug>

                               <optimize>${compiler.optimize}</optimize>

                </configuration>

</plugin>

 

Pour activer par défaut un profil défini dans le fichier setting, il suffit de mettre:

<activeProfiles>

                <activeProfile>IdDuProfilActif</activeProfile>

</activeProfiles>

Une seconde manière d'activer un profil par défaut est de le faire dans sa définition en utilisant la balise activeByDefault:

<settings>

                <profiles>

                <profile>

                               <id>dev</id>

                               <activation>

                                               <activeByDefault>true</activeByDefault>

                               </activation>

                                              

                               </profile>

                </profiles>

</settings>

 

Ce profil par défaut définira la variable environment.type à dev. Il sera alors facile d'utiliser cette variable pour surcharger le profil dans les fichiers POM des projets (si besoin):

<project>

                ...

                <profiles>

                               <profile>

                                               <id>development</id>

                                               <activation>

                                                               <property>

                                                                              <name>environment.type</name>

                                                                              <value>dev</value>

                                                               </property>

                                               </activation>

                                               <properties>

                                                               <database.driverClassName>com.mysql.jdbc.Driver

</database.driverClassName>

                                                               <database.url>

                                                                              jdbc:mysql://localhost:3306/app_dev

 </database.url>

                                                               <database.user>

development_user

</database.user>

<database.password>

development_password

</database.password>

                                               </properties>

                               </profile>

                </profiles>

</project>

1.1.9.2       Le profil Android courant : production

Dans la même optique que les exemples précédents deux profils typiques apparaissent pour Android : le profil « développement » et le profil « production ». L’un aura pour but de signer (ou pas) votre application avec la clef debug sans optimisation de l’apk et l’autre aura pour but de signer l’application avec votre clef de production en optimisant votre apk.

Quand seulement deux profils de ce type apparaissent, il suffit de déclarer le moins courant des deux en tant que profil (ici nous mettons en place le profil « production »). L’autre profil sera celui du comportement par défaut qui est instancié dans le fichier pom.xml.

<profiles>

        <profile>

            <id>production</id>

            <build>

                <plugins>

                    <plugin>

<groupId>com.jayway.maven.plugins.android.generation2</groupId>

                <artifactId>maven-android-plugin</artifactId>

                <executions>

                               <execution>

                                               <id>alignApk</id>

                                               <phase>install</phase>

                                               <goals>

                                                               <goal>zipalign</goal>

                                               </goals>

                               </execution>

                        </executions>

                    </plugin>

                    <plugin>

                        <groupId>org.apache.maven.plugins</groupId>

                        <artifactId>maven-jarsigner-plugin</artifactId>

                        <version>1.2</version>

                        <executions>

                            <execution>

                                <id>signing</id>

                                <goals>

                                    <goal>sign</goal>

                                </goals>

                                <phase>package</phase>

                                <inherited>true</inherited>

                                <configuration>

                                    <archiveDirectory></archiveDirectory>

                                    <includes>

                                        <include>target/*.apk</include>

                                    </includes>

                                    <keystore>path/to/keystore</keystore>

                                    <storepass>storepasword</storepass>

                                    <keypass>keypassword</keypass>

                                    <alias>key-alias</alias>

                                </configuration>

                            </execution>

                        </executions>

                    </plugin>

                    <plugin>

                        <groupId>com.jayway.maven.plugins.android.generation2</groupId>

                        <artifactId>maven-android-plugin</artifactId>

                        <inherited>true</inherited>

                        <configuration>

                            <sign>

                                <debug>false</debug>

                            </sign>

                        </configuration>

                    </plugin>

                   

                </plugins>

            </build>

        </profile>

    </profiles>

Ce profil surcharge le comportement de 3 plugins :

Le plugin android-maven-plugin mappe la tache ZipAlign, qui permet d’optimiser votre application pour les téléphones, avec la phase d’installation du cycle de vie Maven. Cela permet d’automatiser cette optimisation au niveau de la phase de déploiement de l’apk. Cette méthode n’est applicable qu’à partir de la version 2.5 de l’Android-Maven-Plugin.

Le plugin maven-jar-signer est customiser pour signer votre application en utilisant la clef définie dans le KeyStore dont le mot de passe est storepass pour la clef nommée key-alias dont le mot de passe est keypassword. C’est à vous de renseigner les valeurs correctes de ces 4 variables.

Enfin, le plugin maven-android-plugin est customisé de manière à ne pas signer par défaut votre application avec la clef de debug.

 

1.1.10  Utiliser un autre de ses projets Android comme source d’un projet

 

Imaginons que vous factorisiez du code au sein d’un projet central qui sera utilisés par d’autres projets. Comment mettre en place les dépendances entre ces projets en utilisant Maven ?

Projet Core

Projet A

Projet B

Utilise


 

Dans le fichier POM de votre projet core, il vous faut spécifier :

·         Le packaging de type APK

·         L’inclusion des sources dans votre application finale (cela se configure dans le bloc build/plugin/ maven-android-plugin/configuration).

Pour cela, il vous faut rajouter les lignes en gras suivantes :

  <modelVersion>4.0.0</modelVersion>

  <groupId>Mon.Group.ID</groupId>

  <artifactId>MyArtifactID</artifactId>

  <version>MyVersion</version>

  <packaging>apk</packaging>

  <name>MyApplicationName</name>

<plugin>

        <groupId>com.jayway.maven.plugins.android.generation2</groupId>

        <artifactId>maven-android-plugin</artifactId>

        <version>2.8.3</version>

        <configuration>

                <attachSources>true</attachSources>

                <androidManifestFile>${project.basedir}/AndroidManifest.xml</androidManifestFile>

                <assetsDirectory>${project.basedir}/assets</assetsDirectory>

                <resourceDirectory>${project.basedir}/res</resourceDirectory>

                <nativeLibrariesDirectory>${project.basedir}/src/main/native</nativeLibrariesDirectory>

                <sdk>

                               <!-- Defined in the android.properties file -->

                               <platform>7</platform>

                </sdk>

                <deleteConflictingFiles>true</deleteConflictingFiles>

                <undeployBeforeDeploy>true</undeployBeforeDeploy>

        </configuration>

        <extensions>true</extensions>

      </plugin>

 

Ensuite, il vous suffit de rajouter la dépendance vers ce projet dans les fichiers POM du projet A et du projet B dans le bloc dependencies (lignes en gras) :

<dependencies>

                <dependency>

                               <groupId>com.google.android</groupId>

                               <artifactId>android</artifactId>

                               <version>2.2.1</version>

                               <scope>provided</scope>

                </dependency>

                <dependency>

                                <groupId>TheGroupIdOfTheCoreProject</groupId>

                               <artifactId>TheArtifactIdOfTheCoreProject</artifactId>

                               <type>apksources</type>

                </dependency>

</dependencies>

 

1.1.11  Ajouter un jar à son application :

Cela s’effectue assez simplement, il suffit de rajouter la dépendance dans votre fichier Pom comme toujours avec Maven.

Là où le problème s’envenime est que même si votre application compile, il n’est en aucun cas évident que votre application se lance. En effet, Android possède une JVM légère, Dalvik, qui a été expurgée d’un certain nombre de composants usuels pour le JSE, le JME ou le J2EE (typiquement Swing et AWT). Ainsi, votre Jar peut être dépendant de certains composants Java natifs qui n’existent pas dans la JVM Dalvik d’Android… et là… il n’y a pas de solutions clef en main.

 



[1] Ce nom est celui utilisé par Android pour définir la plateforme cible. Il apparaît dans le fichier default.properties pour spécifier cette cible.