Sign, zipalign and to market, to market with Maven

So you got your Android application building with Maven and the instrumentation tests running on the continuous integration server give you an all green. Features are good on your application and you think it is time to get it on to the Android market and among users to get some feedback. What now? I will show you how you can get your Android package ready for upload…


The first step in your preparation to get your application on to the Android market is probably to create a keystore and key as documented on the Android developer site. You will also want to have all the text you want to use for description and so on and a bunch of nifty screen shots ready. And then you want to get to the build related parts.

Beyond the normal build of you apk you will have to do some further things when preparing the apk for the market. You will need to get the apk signed and zipaligned. The resulting artifact should then also be deployed to your repository (or repository server). Here is how you set it up to happen automatically:

First you want to add a profile to your pom file that will handle the release build. It will start like that

<profiles>
  <profile>
    <id>release</id>
     <!-- via this activation the profile is automatically used when the release is done with the maven release plugin -->
     <activation>
      <property>
        <name>performRelease</name>
        <value>true</value>
      </property>
    </activation>
...

By defining the release profile this way you will be able to call it from the command line with the -P flag and it will be automatically activated by the the maven release plugin.The first thing you want to add in addition to the normal build will be the jar signing process:

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-jarsigner-plugin</artifactId>
            <executions>
                <execution>
                    <id>signing</id>
                    <goals>
                        <goal>sign</goal>
                        <goal>verify</goal>
                    </goals>
                    <phase>package</phase>
                    <inherited>true</inherited>
                    <configuration>
                        <removeExistingSignatures>true</removeExistingSignatures>
                        <archiveDirectory/>
                        <includes>
                            <include>${project.build.directory}/${project.artifactId}.apk</include>
                        </includes>
                        <keystore>${sign.keystore}</keystore>
                        <alias>${sign.alias}</alias>
                        <storepass>${sign.storepass}</storepass>
                        <keypass>${sign.keypass}</keypass>
                        <verbose>true</verbose>
                    </configuration>
                </execution>
            </executions>
        </plugin>

The sign.* properties can be replaced with the actual values for your keystore or you can supply the values in the command line with e.g. -Dsign.alias=youralias or you can define them in your settings.xml file e.g. like that

<settings>
<profiles>
    <profile>
        <activation>
            <activeByDefault>true</activeByDefault>
        </activation>
        <properties>
            <sign.keystore>pathtokeystorefile</sign.keystore>
            <sign.alias>aliasname</sign.alias>
            <sign.keypass>somepassword</sign.keypass>
            <sign.storepass>somotherpassword</sign.storepass>
        </properties>
    </profile>
</profiles>
</settings> 

As you can see the plugin configuration will cause the apk file to be signed and verified in the package phase of the build. After that you will want the apk to be zipaligned, which can be done like that:

<!-- the signed apk then needs to be zipaligned -->
<plugin>
    <groupId>com.jayway.maven.plugins.android.generation2</groupId>
    <artifactId>maven-android-plugin</artifactId>
    <inherited>true</inherited>
    <configuration>
        <sign>
            <debug>false</debug>
        </sign>
        <zipalign>
            <verbose>true</verbose>
            <inputApk>${project.build.directory}/${project.artifactId}.apk</inputApk>
            <outputApk>${project.build.directory}/${project.artifactId}-signed-aligned.apk
            </outputApk>
        </zipalign>
    </configuration>
    <executions>
        <execution>
            <id>alignApk</id>
            <phase>package</phase>
            <goals>
                <goal>zipalign</goal>
            </goals>
        </execution>
    </executions>
</plugin>

As you can see the debug signing of the maven android plugin is deactivated. The apk will have been signed by the above configuration in place. Therefore the zipalign will take the apk as input and produce an outputfile with an modified name.

This already constitutes the final file, but in a well managed environment you will want that file to be published to the repository so that it it backed up and managed properly as well as potentially available for e.g. QA from there. This is where the build helper plugin jumps in:

<plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>build-helper-maven-plugin</artifactId>
    <configuration>
        <artifacts>
            <artifact>
                <file>${project.build.directory}/${project.artifactId}-signed-aligned.apk</file>
                <type>apk</type>
                <classifier>signed-aligned</classifier>
            </artifact>
        </artifacts>
    </configuration>
    <executions>
        <execution>
            <id>attach-signed-aligned</id>
            <phase>package</phase>
            <goals>
                <goal>attach-artifact</goal>
            </goals>
        </execution>
    </executions>
</plugin>

In a multi module build you will either want to do the same configuration for the instrumentation tests or deactivate them via a profile. You could for example do that in the parent pom with two profile following this pattern:

    <profiles>
        <profile>
            <!-- the standard profile runs the instrumentations tests -->
            <id>standard</id>
            <activation>
                <activeByDefault>true</activeByDefault>
            </activation>
            <modules>
                <module>morse-lib</module>
                <module>morseflash-app</module>
                <module>morseflash-instrumentation</module>
            </modules>
        </profile>
        <profile>
            <!-- the release profile does sign, zipalign... but does not run instrumentation tests -->
            <id>release</id>
            <!-- via this activation the profile is automatically used when the release is done with the maven release
            plugin -->
            <activation>
                <property>
                    <name>performRelease</name>
                    <value>true</value>
                </property>
            </activation>
            <modules>
                <module>morse-lib</module>
                <module>morseflash-app</module>
            </modules>
        </profile>
    </profiles>

Once you have all that set up, you can produce your signed and zipaligned apk with the simple command

mvn clean install -P release

and then it is time to go to market, to market.. You will find the file in your target folder or in your local repository. If you run a mvn deploy command the apk will also end up in your remote repository. At this stage this is all manual and not tied to any release process. Going forward you probably want to combine that with the maven release plugin to handle your version control tagging, updates to the versions in the pom and more you will have to wait for my next post.

Oh and as usual the code you see here is replicated to my clone of the maven android plugin samples project on github in the morseflash example.

4 comments » Write a comment

Leave a Reply

Required fields are marked *.