Automating android application signing and zipaligning with maven

Code rage

This is something that has had me tearing my hair out for a few days now, I was pretty much border-line braveheart-ing my screen….

Code rage

I’ve recently been on a little drive to try to maven-ize my projects. All had been going well until I needed to sign and zipalign my APKs. This post will help you conquer that barrier with the use of some maven plugins.

When using ant, I was able to simply enter keystore details into build.properties and just call “ant release”. Unfortunately that approach doesn’t carry across to maven, and you have to provide some more configuration.

Firstly, before we go any further, I’m going to assume that you already have a maven android project setup, so you have a pom.xml, you’ve configured the maven-android-plugin and you can run “mvn clean install” to build your APK, and “mvn android:deploy” to deploy it to an emulator. If you haven’t got that far, I’d suggest you have a look at one of my previous posts to help get you up to speed.

So, when you want to build your application with maven, you’d run “mvn install”. That will, by default, use a debug key to sign your APK. When we want to build a releasable APK we still want to execute the same install goal, however we’ll want to use a proper key. Luckily, maven provides something called profiles.

In short, maven profiles allow you to still perform the same standard goals, yet they behave slightly different, in the manner of binding extra steps to them, all will come clearer in a moment.

This has already been covered, in a useful post by the guys at Novoda, and various other blog posts scattered around the web. I’ve followed at least 10 tutorials and each time I was unable to get the signing process to work correctly, each time I encountered the following error :

INFO] jarsigner: attempt to rename C:\android-projects\jameselsey_andsam_branch_mavenbranch\target\LanguageSelection-1.0.0-SNAPSHOT.jar to C:\android-projects\jameselsey_ands
am_branch_mavenbranch\target\LanguageSelection-1.0.0-SNAPSHOT.jar.orig failed
[INFO] ------------------------------------------------------------------------
[ERROR] BUILD ERROR
[INFO] ------------------------------------------------------------------------
[INFO] Failed executing 'cmd.exe /X /C "C:\development\tools\Java\jdk1.6.0_20\jre\..\bin\jarsigner.exe -verbose -keystore my-release-key.keystore -storepass '*****' -keypass '
*****' C:\android-projects\jameselsey_andsam_branch_mavenbranch\target\LanguageSelection-1.0.0-SNAPSHOT.jar mykeystore"' - exitcode 1
[INFO] ------------------------------------------------------------------------

I’d tried everything, even copying out the command and pasting into a command window worked, but I could not get it to work from maven. Unfortunately it seems there may be an issue with the maven-jarsigner-plugin (as suggested in the comments on the Novoda post). However fear not, for there is an alternative, the maven-jar-plugin.

The maven-jar-plugin is a similar plugin to the jarsigner plugin, however the signing APIs are now deprecated and it points you to use the (apparently) broken maven-jarsigner-plugin. Using a deprecated API doesn’t particulary concern me in this instance, as its just signing artefacts.

Take a look at my profiles section, copy this into your pom.xml :

<profiles>
<profile><!-- release profile. uses keystore defined in keystore.* properties. signs and zipaligns the app to the target folder-->
            <id>release</id>
            <activation>
                <activeByDefault>false</activeByDefault>
            </activation>
            <build>
                <defaultGoal>install</defaultGoal>
                <finalName>${project.artifactId}-${project.version}</finalName>
                <plugins>
                    <plugin>
                        <groupId>org.apache.maven.plugins</groupId>
                        <artifactId>maven-jar-plugin</artifactId>
                        <version>2.2</version>
                        <executions>
                            <execution>
                                <id>signing</id>
                                <goals>
                                    <goal>sign</goal>
                                </goals>
                                <phase>package</phase>
                                <inherited>true</inherited>

                                <configuration>
                                    <keystore>
                                        my-release-key.keystore
                                    </keystore>
                                    <storepass>mypassword</storepass>
                                    <keypass>mypassword</keypass>
                                    <alias>mykeystore</alias>
                                    <verbose>true</verbose>
                                    <verify>true</verify>
                                </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>

                    <plugin>
                        <groupId>com.jayway.maven.plugins.android.generation2</groupId>
                        <artifactId>maven-android-plugin</artifactId>
                        <configuration>
                            <zipalign>
                                <verbose>true</verbose>
                                <skip>false</skip>
                                <!-- defaults to true -->
                                <inputApk>${project.build.directory}/${project.artifactId}-${project.version}.apk</inputApk>
                                <outputApk>${project.build.directory}/${project.artifactId}-${project.version}-RELEASE.apk
                                </outputApk>
                            </zipalign>

                        </configuration>
                        <executions>
                            <execution>
                                <id>zipalign</id>
                                <phase>install</phase>
                                <goals>
                                    <goal>zipalign</goal>
                                </goals>
                            </execution>
                        </executions>
                    </plugin>
                </plugins>
            </build>
        </profile>
</profiles>

OK, so lets walk through what the above profile does. Firstly, the “id” of the profile is “release”, so when you want to apply this profile, you’d run “mvn install -Prelease”. The “activeByDefault” is set to false, which means you need to use the above arguement, if you flip that over, you won’t need the P flag.

The execution goal is to “sign”, which is the API on the plugin, documented here. We bind this execution on to the standard “package” goal. Then we provide the configuration elements which specify the details of the keystore.

In pure English, this binds the plugin phase onto the package goal of maven, so anytime we run using this profile it’ll execute the jar signing of our artefacts. The “verify” tag gives us extra piece of mind by verifying that the signing was successful afterwards.

I’ve also setup a zipalign profile that will take the APK, zipalign it, and rename it to “*-RELEASE.apk”, so I know that particular APK is the one which I’ll release to market.

So thats it, once more a success, and its just one small step on the ladder to android glory!

Phhew!! Done, finally I was able to shutdown the laptop and go to sleep at 3am….on a school night!!!

Good luck, feel free to comment!

Peace.

How to quickly and easily convert a formatted XML into a single line…

So you’ve got a nicely formatted XML object, with all your indentation setup so that it is easy to read. However there may come a time when you need that lovely XML to be formatted to a single line.

You could post it into notepad and manually format it, however this becomes quite a chore when your XML object grows. There is a much simpler method!

All you need to do is to copy your XML, and paste it into the Google search bar in the top right hand corner of your Firefox browser (this may also work in other browsers). Then re-copy it and paste it into notepad, voila, it should be all on one line.

No need for complex scripts, just throw it into the search bar and re-copy it back out.

Simples.

Android or Standard Java; Mapping your XML onto POJOs easily, and vice versa

I’ve listed this post under Android, but to be honest this could apply to both J2SE and J2EE, its not really specific to Android but it was part of a requirement I was working with for a recent Android project.

The problem I had, was that I was getting an XML String as a response from a web service call. The String contained one long String representation of an XML object and I needed to get some data out of that. I could have manipulated the String manually and substring’d out what I required, but that would be incredibly poor and I would likely face verbal punishment from my peers.

Fortunately, XStream comes to the rescue. Of course there are better methods such as SAX Parsing and DOM, but when you need a quick and dirty way of casting an XML String to an Object, and vice versa, this works nicely.

First off, you need to go to the XStream website and download the jar, then whack it on your class path so its available to you.

Then you need to do two things, it doesnt really matter which order, but you’ll need to :

  1. Create the POJO that you wish to use. This will be a Java object representation of your data, your XML will get transformed to this
  2. Create an XML Document that defines your data.

Lets have a look at the POJO first

public class Person
{
  private String firstname;
  private String lastname;
  private Integer phone;
  private Integer fax;

  public String getFirstname()
  {
	  return firstname;
  }
  public void setFirstname(String firstname)
  {
	  this.firstname = firstname;
  }

  public String getLastname()
  {
	  return lastname;
  }
  public void setLastname(String lastname)
  {
	  this.lastname = lastname;
  }

  public Integer getPhone()
  {
	  return phone;
  }
  public void setPhone(Integer phone)
  {
	  this.phone = phone;
  }

  public Integer getFax()
  {
	  return fax;
  }
  public void setFax(Integer fax)
  {
	  this.fax = fax;
  }

}

And now look at the XML

<person>
  <firstname>Joe</firstname>
  <lastname>Walnes</lastname>
  <phone>778</phone>
  <fax>9000</fax>
</person>

Then, all you need to do is to convert between the two. I’ll show you a few examples in this little demo below, you should be able to just copy and paste it into an IDE such as Eclipse, IntelliJ or Netbeans.

public class XStreamTest {

/**
* @param args
*/
public static void main(String[] args) {
//
XStream xstream = new XStream();
xstream.alias("person", Person.class);

Person joe = new Person();
joe.setFirstname("Joe");
joe.setLastname("Walnes");
joe.setPhone(1234-456);
joe.setFax(9999-999);

String xml = xstream.toXML(joe);
System.out.println(xml);

}

}

XStream is a great little utility class to let you get stuck in with XML and POJOs, but of course it does have its limitations. For a start you would need to include the XStream library in your Android application, increasing your APK file size, might not be an issue for small applications but could potentially cause problems.

If you need to quickly map a very simple POJO onto an xml then XStream may be your best choice, but if you want a more robust solution, its better to do it yourself and use DOM or SAX.