Weitere Details zu ADT und Maven

Da ich bereits mehrfach gefragt wurde, wie man mit Maven und ADT ein Projekt multimandandenfähig macht (d.h. aus einem Sourcebaum entstehen mehrere Apps), fasse ich das hier mal kurz zusammen.

Grundsätzlich benötigt man die Maven-Struktur für ein Android Projekt. Diese sieht wie folgt aus:

<?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>de.egore911.mobile</groupId>
 <artifactId>test</artifactId>
 <version>0.1-SNAPSHOT</version>
 <packaging>apk</packaging>
 <name>${project.artifactId}</name>

 <properties>
  <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
 </properties>

 <dependencies>
  <dependency>
   <groupId>com.google.android</groupId>
   <artifactId>android</artifactId>
   <version>2.2.1</version>
   <scope>provided</scope>
  </dependency>
 </dependencies>

 <build>
  <plugins>
   <plugin>
    <groupId>com.jayway.maven.plugins.android.generation2</groupId>
    <artifactId>android-maven-plugin</artifactId>
    <version>3.0.0-alpha-14</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>
      <platform>8</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.6</source>
     <target>1.6</target>
    </configuration>
   </plugin>

  </plugins>
 </build>

Ich werde an dieser Stelle nicht auf die einzelnen Teile eingehen. Es geht jetzt darum, wie man Resources austauschen kann. Dazu verwendet man in Maven Profile. Ich verwende z.B. ein Profil namens "demo".

<profile>
 <id>demo</id>
 <activation>
  <property>
   <name>config</name>
   <value>demo</value>
  </property>
 </activation>
 <build>
  <plugins>
   <plugin>
    <artifactId>maven-resources-plugin</artifactId>
    <version>2.5</version>
    <executions>
     <execution>
      <id>copy-assets</id>
      <phase>initialize</phase>
      <goals>
       <goal>copy-resources</goal>
      </goals>
      <configuration>
       <outputDirectory>${basedir}/assets</outputDirectory>
       <resources>
        <resource>
         <directory>${basedir}/templates/assets/demo</directory>
         <filtering>false</filtering>
        </resource>
       </resources>
       <overwrite>true</overwrite>
      </configuration>
     </execution>
     <execution>
      <id>copy-res</id>
      <phase>initialize</phase>
      <goals>
       <goal>copy-resources</goal>
      </goals>
      <configuration>
       <outputDirectory>${basedir}/res</outputDirectory>
       <resources>
        <resource>
         <directory>${basedir}/templates/res/demo</directory>
         <filtering>false</filtering>
        </resource>
       </resources>
       <overwrite>true</overwrite>
      </configuration>
     </execution>
    </executions>
   </plugin>
  </plugins>
 </build>
</profile>

Hierbei sind zwei Dinge zu beachten:

  1. Das Kopieren der Ressourcen muss vor der Ausführung das Android-Plugins passieren. Da das Android-Plugin in der Phase "generate-sources" ausgeführt wird, habe ich "initialize" als Phase gewählt (Warum erschließt sich bei der Betrachtung des Maven Livecycle).
  2. Per Default überschreibt das maven-resource-plugin nicht bestehende Resourcen, wenn diese neuer sind. Dies ist für den gegebenen Anwendungsfall natürlich unpraktisch.

Damit kann jetzt jeder seine App auch als Demo ausliefern. Es bleibt dem Entwickler überlassen, ob er die Vollversion in den res und assets-Ordnern pflegt oder diese auch als Profile realisiert. Ich habe letzteres verwendet, damit ich mir nicht aus Versehen teile der Demo in die Vollversion stecke (oder umgekehrt). Man sollte in diesem Fall darauf achten, dass die Daten nicht ins Versionskontrollsystem eingecheckt werden. Dies kann dann allerdings zur Folge haben, dass wenn kein Profil aktiv ist, die Daten fehlen und der Android-Buildprozess fehlschlägt. Als Lösung bietet sich an, entweder ein Profile auf "activeByDefault" zu stellen, oder in der Entwicklungsumgebung das Profil zu aktivieren.

Verfasst von: egore911