Tretyakov Ilya
Building is the necessary part of Android application development. In the simplest case building is changing the version and acquiring the signed *.apk file. It’s easily done with the popular Eclipse IDE.
This variant is optimal for single programmers who create small applications. Development of the large-scale projects calls the additional requirements, such as:
- Using the automatic building system (and executing tests)
- Adding some special stages to the building process
- Using differently configured builds
It’s nearly impossible to use Eclipse in such cases. But fortunately Android SDK supports Apache Ant.
Apache Ant is a tool for applications build process automatization, widely popular among Java programmers. It can help us in cases when using Eclipse is difficult or impossible. To perform an action in Ant you must write a build script on XML. Build script contains one project and at least one target. The target in the build script is a pack of tasks applied for execution for target call. The task is just some code. Also the important part of build script is properties. They are used to determine the variables in built files.
Software requirements
This manual requires the following software installed on your machine:
To ensure the smooth workflow we should add their directories to environment variables list. In Windows it can be done with the following commands:
set path=%PATH%;E:dev_toolsandroid_sdktools
set path=%PATH%;E:dev_toolsapache_antbin
In this example E:dev_toolsandroid_sdk and E:dev_toolsapache_ant are the directories of Android SDK and Apache Ant consequently.
Creating the build script
Fortunately, there’s no need to write script from the scratch. As mentioned above, Android SDK supports Ant out-of-box. So it’s enough to update the current project with the command:
android update project –path
If update is successful, you’ll see:
E:workspaceTestProject>android update project –path .
Updated local.properties
Added file E:workspaceTestProjectbuild.xml
Updated file E:workspaceTestProjectproguard.cfg
Now we can see the file called build.xml in the project. This is the build script we need to complete our task.
If you create a new project, you can also use the command:
android create project
–target
–name
–path path/to/your/project
–activity
–package
The parameters for the command are:
- Target_ID – corresponds to the Android platform library version used for building. The list of available libraries can be seen by executing the command “android list targets”
- your_project_name – the name of the project
- path/to/your/project – directory to place your project into
- your_activity_name – the name of Activity
- your_package_namespace – the name of application package
Signing the Andriod application
Android OS requires all the applications to be signed with the certificate owned by developer. If the certificate is lost, you become unable to update your application. Also notice that all the builds created throughout the development workflow are signed with the special DEBUG certificate. But you cannot use it to install the build to the device or publish it to Android Market. More information about signing the applications is available in Android OS documentation.[5].
To prepare the build for publishing we need to:
- Create a certificate (only once)
- Create a build
- Sign the build with the certificate
Eclipse includes a special wizard to perform this action (Project Properties -> Android Tools -> Export Signed Application Package…). We need to automatize as more tasks as possible, and steps 2 and 3 are the main target for that. To perform this we should put the certificate information to the ant.properties file (in older Android SDK versions it’s called build.properties). If there’s no such file in the project directory – you must create it.
The properties to add are:
key.store=path_to_keystore
key.alias=mykeystore
key.store.password=password1
key.alias.password=password2
Properties values:
- path_to_keystore – the path to certificate storage file
- mykeystore – certificate nickname
- password1 – the password to certificate storage file
- password2 – the password to certificate nickname
Warning! It may be prohibited to store such information in VCS in your company! So pay attention to corporate standards compliance.
Now check everything for proper functioning:
E:workspaceTestProject>ant release
Buildfile: E:workspaceTestProjectbuild.xml
-set-mode-check:
-set-release-mode:
-release-obfuscation-check:
-setup:
[echo] Gathering info for TestAndroidActivity…
// skip some output
-release-nosign:
release:
[echo] Signing final apk…
[signjar] Signing JAR: E:workspaceTestProjectbinTestAndroidActivity-release-unsigned.apk to E:workspaceTestProjectbinTestAndroidActivity-release-unaligned.apk as test_alias
[zipalign] Running zip align on final apk…
[echo] Release Package: E:workspaceTestProjectbinTestAndroidActivity-release.apk
BUILD SUCCESSFUL
Total time: 16 seconds
Now we can obtain a release build with only one command.
Creating differently configured builds
Usually programmers create a lot of different builds when developing an application: for themselves, for testers, for customer… These builds can differ significantly. For example, the programmer himself wants to get more information to log (logcat for Android), but for release build this is not needed. The build intended for Market may include the statistics-gathering functionality. If the programmers’ and testers’ builds will also gather it, this may distort the statistical data. If the application is published not only in Android Market, but also somewhere else (Amazon AppStore, GetJar etc.), it’s best to add the error-reporting functionality to ensure the fastest bugfixing. But the error-reporting must be disabled in development builds, otherwise all the current (and corrected) mistakes of the programmers will flood the report.
To make things simpler we will shorten all the configuration to the only DEBUG parameter. You can easily add the rest of the parameters by yourself.
Create 2 files containing this parameter for development build:
/**
* This is configuration file for development-builds.
* If you want to change it – edit file <project_root>/dev_config/Configuration.java.
* Then use Ant script for switching between configurations.
*/
public class Configuration {
public final static Boolean DEBUG = true;
}
and for release build:
/**
* This is configuration file for release-builds.
* If you want to change it – edit file <project_root>/release_config/Configuration.java.
* Then use Ant script for switching between configurations.
*/
public class Configuration {
public final static Boolean DEBUG = false;
}
The first file will be placed in “<project_root>/config_dev”, and the other in – “<project_root>/config_release”. Also we need to copy one of them to the source code directory. In my case it’s: <project_root>/src/com/enterra/android/apps/test/settings.
Now we will include the settings-changing code in the script, which will alter the settings depending on the task.
<property name="config-target-dir-path" value="com/enterra/android/apps/test/settings" />
<target name="switch-config">
<echo>Configuration file: ${config.filename}</echo>
<property name="config-target-path" value="${source.dir}/${config-target-dir-path}" />
<copy file="${config.filename}" todir="${config-target-path}" overwrite="true" encoding="utf-8">
</copy>
</target>
<target name="release-dev">
<echo>Selected developer configuration</echo>
<antcall target="switch-config">
<param name="config.filename" value="config_dev/Configuration.java" />
</antcall>
<antcall target="release" />
</target>
<target name="release-public">
<echo>Selected release configuration</echo>
<antcall target="switch-config">
<param name="config.filename" value="config_release/Configuration.java" />
</antcall>
<antcall target="release" />
</target>
Since this moment we need to use only the ant release-public (for release build) and ant release-dev (for development build) command.
This script substitutes the config file in the code routine with the required one and initiates the standard assembling procedure. Here’s the example of console in the case of proper script working:
E:workspaceTestProject>ant release-public
Buildfile: E:workspaceTestProjectbuild.xml
release-public:
[echo] Selected release configuration
switch-config:
[echo] Configuration file: config_release/Configuration.java
[copy] Copying 1 file to E:workspaceTestProjectsrccomenterraandroidappstestsettings
-set-mode-check:
-set-release-mode:
-release-obfuscation-check:
-setup:
// skip some output
release:
[echo] Signing final apk…
[signjar] Signing JAR: E:workspaceTestProjectbinTestAndroidActivity-release-unsigned.apk to E: workspaceTestProjectbinTestAndroidActivity-release-unaligned.apk as test_alias
[zipalign] Running zip align on final apk…
[echo] Release Package: E:workspaceTestProjectbinTestAndroidActivity-release.apk
BUILD SUCCESSFUL
This way can also be used to add one more configuration for testers. Moreover, it’s quite easy to use additional parameters for statistics gathering, error-reporting etc.
Application version
In Android 2 parameters from manifest (AndroidManifest.xml file) are responsible for indicating the version:
- android:versionName – string version number. Intended for end-user only.
- android:versionCode – inner version number (integer value). Used to determine the latest version available. It must be increased with every released version. In Android OS it can be seen only through Application Manager
So we need to make android:versionCode increase by one with every release version. As for android:versionName, we will generate the version number from 2 parts: major and minor. The major part will always be changed by developer. The minor part is to be increased by one with every build.
To make this possible we will create a <project_root>/version.properties, file containing the current version information:
app.version.code=10
app.version.major=1.0.
app.version.minor=4
Then we will add the task to the build script:
<propertyfile file="version.properties">
<entry key="app.version.code" type="int" operation="+" value="1" />
<entry key="app.version.minor" type="int" operation="+" value="1" />
</propertyfile>
<property file="version.properties" />
<echo>Version code: ${app.version.code}</echo>
<echo>Version name: ${app.version.major}${app.version.minor}</echo>
<property name="match.end" value='"' />
<property name="matchVersionCode.start" value='android:versionCode="' />
<replaceregexp file="AndroidManifest.xml" match='${matchVersionCode.start}[^"]*${match.end}' replace="${matchVersionCode.start}${app.version.code}${match.end}" />
<property name="matchVersionName.start" value='android:versionName="' />
<replaceregexp file="AndroidManifest.xml" match='${matchVersionName.start}[^"]*${match.end}' replace="${matchVersionName.start}${app.version.major}${app.version.minor}${match.end}" />
</target>
This script takes app.version.code and app.version.minor properties from <project_root>/version.properties, , increases them by one and saves. Then it refreshes android:versionName and android:versionCode attributes in the AndroidManifest.xml file.
This task can be executed separately to ensure the proper functioning:
E:workspaceTestProject>ant increase-version
Buildfile: E:workspaceTestProjectbuild.xml
increase-version:
[propertyfile] Updating property file: E:workspaceTestProjectversion.properties
[propertyfile] Updating property file: E:workspaceTestProjectversion.properties
[echo] Version code: 11
[echo] Version name: 1.0.5
BUILD SUCCESSFUL
The final step is adding this script to the release-public task:
<echo>Selected release configuration</echo>
<antcall target="switch-config">
<param name="config.filename" value="config_release/Configuration.java" />
</antcall>
<antcall target="release" />
</target>
Interaction with VCS (version control system)
The final important thing to point out is the rules of interaction with VCS and created files.
- The local.properties file must not be placed into the VCS
- It’s necessary to add ant.properties, version.properties, default.properties and build.xml files to the VCS
- It’s also necessary to add the configuration files (config_dev/Configuration.java, config_release/Configuration.java).
- The developers must not include local config file (/src/…/Configuration.java) changes into the VCS. This is not applicable to new parameters adding.
- After creating the release build it’s necessary to create a tag for it. This is to make errors tracking easier when receiving error-reports.
Conclusion
In this article we described the creation of a script which helps to reduce the amount of time needed to build a project. Regarding a fact that building process may include a large amount of stages, we not only gain time economy, but also reduce the risk of errors (which can be implied on every stage). The described functionality is applicable for virtually every project. The further development of build script depends on the project. Using this information you shouldn’t experience any difficulties in adding new steps to the build script.
Links
Want to benefit by our experience in mobile application development for Android? Start with your project estimation right now!
This entry was posted on Thursday, December 22nd, 2011 at 4:50 am and is filed under Android.