How to set strings.xml values at build time? - android

I'm building my Android application with Ant, and would like to set one of the values in my strings.xml at build time. For example, I could use
<string name="app_name">MyApp-DEBUG</string>
with a debug build, or I could use
<string name="app_name">MyApp<string>
for a release build. Is this possible?

There are two tasks in Ant that can help:
First is the <replace>. You give it a file name that contains parameters that can be replaced, and you give the <replace> task the values for those parameters. It replaces them in the file. I don't like this task because it's used to replace stuff that is under version control, and if you're not careful, you can end up changing the file without meaning to.
settings.xml
<settings>
<properties>
<property name="server" value="#SERVER#"/>
</properties>'
</settings>
Replace Task
<replace file="settings.xml">
<replacetoken token="#SERVER#" value="google.com"/>
</replace>
I've seen plenty of version control repositories where revision #3 of the replaced file was an accidental checkin of the the file with the replaced parameters (and not realizing it until the next release when the parameters didn't get changed). Then version #4 is a duplicate of version #2 which had the replacement parameters. Followed by a bad version #5, followed by a version #6 which restores the file, and on and on.
My preferred method is to copy the file over to another directory, and use <filterset>/<filter> tokens to change the file while being copied:
<copy todir="${target.dir}"
file="settings.xml">
<filterset>
<filter token="SERVER" value="google"/>
</filterset>
</copy>
Both can use a property file instead of specifying individual tokens. The <copy>/<filterset> pair can take a fileset of files and replace a bunch of tokens at once. (Be careful not to pass it a binary file!).

try this code, it works for me
<target name="app-name-debug">
<replaceregexp file="res/values/strings.xml" match='name="app_name"(.*)'
replace='name="app_name">MyApp-DEBUG<\/string>'/>
</target>
<target name="app-name-release">
<replaceregexp file="res/values/strings.xml" match='name="app_name"(.*)'
replace='name="app_name">MyApp<\/string>'/>
</target>

Related

How to Auto Increment versionCode when exporting Android apps in Eclipse?

I want to auto-increment the versionCode and versionName of the manifest file of the android app when I click on Export (to export a new version of the app)
I found the second answer here (Auto increment version code in Android app) extremely useful (comment include .exe programs to auto increment Android versionCode) , however, they made it run on Build, I want it to run when I click on File -> Export , see image please
You might consider modifying the File -> Export button to execute a builder to increment the version code (as shown in the post you mentioned) in addition to that button's usual functionality. The org.eclipse.ui.menus extension point seems like a good starting point. (Disclaimer: I haven't tried this.)
However, it might be good to keep the following xkcd in mind here:
I have done this with a ton of custom ant steps.
First, you need to extract the build number into a properties file. Let's call it version.properties
Then, the step to increment the version code is:
<target name="increment-version-code">
<propertyfile file="version.properties">
<entry key="versionCode" type="int" default="0" operation="+" value="1" />
</propertyfile>
</target>
This will read the entry versionCode, increment it and save it back to version.properties.
So far, so good. The last step is to get that versionCode into the AndroidManifest.xml file and unfortunately now it gets messy.
The way I solved it was to regenerate the manifest from a template on every build using the filtering functionality in ant.
<target name="generate-manifest">
<filter filtersfile="version.properties"/>
<copy todir="${source.dir}" overwrite="true" verbose="true" filtering="true">
<fileset dir="${source.dir}" casesensitive="false">
<include name="**/*.base"/>
</fileset>
<mapper type="glob" from="*.base" to="*" />
</copy>
</target>
Then, all you have left to do is move your AndroidManifest.xml to AndroidManifest.xml.base and replace your versionCode attribute to read android:versionCode="#versionCode#" . You can then run the increment-version-code target to bump the versionCode in version.properties and the generate-manifest target to convert the .base template into the final manifest.
These can then be easily added as build steps to your Eclipse project or as dependencies to exported ant builds. Unfortunately, there's no easy hook for the Export functionality (though, there is for "After Clean", which I find good enough).
Of course, with Gradle on the horizon, all of this would have to be rewritten soon. :(

How to Automatically Modify versionName in Manifest during Build?

So far I have been focusing on my application's programming and paid little attention to making the build process smarter. Thus I have been doing things pretty much manually (the "dumb way"), including updating by hand android:versionCode and android:versionName in AndroidManifest.xml.
I would like now to automatically (i.e. upon Build or upon Export):
Fetch from git the latest tag/branch containing build and version codes.
Parse them so that I can assign them to the respective fields in AndroidManifest.xml.
Modify AndroidManifest.xml accordingly.
Proceed with the normal build process (Eclipse+ADT, no Ant whatsoever), as if I did 1-2-3 by hand...
I found a few clues about a "pre-build step", builders and build.xml, but I have no idea where to find those and where to start.
Any tips or pointers on where I could find more information on the subject? (a step-by-step tutorial would be ideal)
Update 1: I found this thread to be suggesting that I:
Right-click on the project, Properties > Builders
Add a builder that points to the project's Ant build file.
Order that builder to be invoked before the Java builder
Fine, but where is the project's Ant build file? Where do I find it?
Update 2: Apparently, it's possible to export the entire project into an Ant file. But I am not sure that's I want. Must a pre-build step always include an Ant build file?
Update 3: Is building an Ant file, only for the pre-build step, the right approach?
Here's what I use to dynamically assign a versionCode and versionName to AndroidManifest.xml. It works only when building with ant, so you'll have to install it first. Then go to the project directory in your command line and execute "android update project -p .", which will create the necessary files for building with ant, like local.properties and build.xml.
Then open build.xml and place this inside:
<target name="-pre-build" depends="-custom-git-version,-custom-manifest-version">
</target>
<!-- Packages the application. -->
<target name="-post-build">
<antcall target="-custom-restore-manifest"/>
<property name="suffix" value="${git.commits}-${git.version}.apk" />
<exec executable="sed" inputstring="${out.final.file}" outputproperty="out.final.renamedfile">
<arg value="s/\.apk/-${suffix}/" />
</exec>
<copy file="${out.final.file}" tofile="${out.final.renamedfile}" />
<echo>Final file copied to: ${out.final.renamedfile}</echo>
</target>
<!-- Custom targets -->
<target name="-custom-git-version">
<exec executable="sh" outputproperty="git.commits">
<arg value="-c" />
<arg value="git log --pretty=format:'' | wc -l" />
</exec>
<echo>git.commits: ${git.commits}</echo>
<exec executable="git" outputproperty="git.version">
<arg value="describe" />
<arg value="--tags" />
<arg value="--long" />
</exec>
<echo>git.version: ${git.version}</echo>
</target>
<target name="-custom-manifest-version">
<echo>Creating backup of AndroidManifest.xml</echo>
<copy file="AndroidManifest.xml" tofile="AndroidManifest.xml.antbak" preservelastmodified="true" />
<replaceregexp
file="AndroidManifest.xml"
match='android:versionCode="(\d+)"'
replace='android:versionCode="${git.commits}"' />
<replaceregexp
file="AndroidManifest.xml"
match='android:versionName="(\d+\.\d+)\.\d+"'
replace='android:versionName="\1.${git.commits}"' />
</target>
<target name="-custom-restore-manifest">
<echo>Restoring backup of AndroidManifest.xml</echo>
<move file="AndroidManifest.xml.antbak"
tofile="AndroidManifest.xml"
preservelastmodified="true"
overwrite="true" />
</target>
The output of this is not exactly what you want, but it is a start - feel free to modify it :) The result is something like "yourapp--.apk
Using this you'll build your application with executing "ant clean debug", or "ant clean release", depending on what you want. You can also create "ant.properties" file with this content:
key.store=keystore_file
key.store.password=some_password
key.alias=some_alias
key.alias.password=some_other_password
to enable automatic signing of your app.
You should also read this: http://developer.android.com/tools/building/building-cmdline.html
You are on the right track with setting up a pre-build step, but the ant build file is something you'll create yourself from scratch. Eclipse has some ant scripts that it uses externally that handle the automated compilation, packaging and stuff, but you want to create a separate one that just does these extra steps you want.
So, you're going to have to learn a bit about ant scripting to get this done. Some of those links you found give you the basic idea of how to create a simple ant file. To add to that, some of the ant tasks you will probably need to use are:
Exec - You will need this to execute your git command that gets your version info. It has an argument called resultProperty you can use to store the output of the command into a property that ant can access. (or you can just have the command output to a file and ant can access that.)
ReplaceRegExp - You will need this to replace tokens (maybe #VERSIONCODE# and #VERSIONNAME# ) you place in your AndroidManifest.xml where the values should eventually go, with the values returned by the exec.
You will probably also want to execute an exec task at the beginning to restore your AndroidManifest.xml file to it's original state (with the tokens in place) so it's repeatable without manual cleanup. I would provide more info on the git commands you need to run within these exec tasks, but I'm afraid all my experience is with Subversion, so you'll have to fill in the gaps there.
You should consider building with maven-android. Once you have your project building cleanly, use the version-update plugin to automatically increment your version number.
Writing a build script with maven-android can't be described as easy - but the payoff is worth the effort and you should consider this avenue.
Also, this tutorial might come in handy (I use a variant of the technique described here for my own builds)
EDIT (2014):
Consider migrating to Android Studio and using Gradle. See: How to autoincrement versionCode in Android Gradle
The way I managed to achieve this: build > execute shell (we needed some php code to receive some info from a db) and the string replacement happens in php:
#!/usr/bin/php
<?php
$filename = $WORKSPACE."/src/com/me/myapp/MyActivity.java";
$file = #file_get_contents($filename);
if($file) {
$repl = preg_replace("OriginalString", "NewString", $file);
file_put_contents($filename, $repl);
echo "\n\nReplaced some stuff in $filename";
}
?>

Use JAXB (xjc) generated classes in android

I am using a Rest-Webservice in Android. The Web Service could handle JSON and XML, the API is described as an XSD. So I used JAXB to generate classes from the XSD and then I used jackson JSON processor to generate JSON from my instances.
The problem is, that JAXB (xjc) generates classes with JAXB annotations and Android can't handle those. I tried to add the jaxb-api.jar to my android project but the Dalvik won't use core classes.
For my first implementation I manually removed the annotations. But now the XSD was updated and I don't want to do this every time this happens.
Do you have any idea how to handle this problem in a better way? Is there a possibility to use jaxb/xjc without annotations or is there another code generater that could do this? Do you know an easy way to remove annotations from java classes (even if they are printed in multiple lines)? Is there a project setting for Android Eclipse projects, that makes the dalvik to allow core libs?
thx, cathixx
I had to do some extra researching to make cathixx's answer work since I'm new to Ant, so I'll share this to help others.
These instructions will take Java files with code like:
import javax.xml.bind.annotation.XmlElement;
#XmlRootElement
public class Response {...
...and comment these occurrences out, so it looks like:
/*import javax.xml.bind.annotation.XmlElement;*/
/*#XmlRootElement*/
public class Response {...
First, create a file build.xml (or whatever you want to call it - must be .xml) in a new Eclipse project (a "General" project is fine).
Then, add the following text to the build.xml file:
<?xml version="1.0"?>
<project
name="CommentOutXmlAnnotations"
basedir="."
default="commentOutXmlAnnotations" >
<!-- This Ant script comments out the following lines from the Java files in this directory:
import javax.xml.bind.annotation.*;
#Xml*
-->
<target
name="commentOutXmlAnnotations"
description="Run" >
<replaceregexp
byline="false"
flags="g" >
<regexp pattern="(#Xml[A-Za-z0-9]+(\([^)]+\))?|import javax\.xml\.bind\.annotation\.[A-Za-z0-9.]+;)[ \t]*(\r?\n)" />
<substitution expression="/*\1*/\3" />
<fileset dir="." >
<include name="*.java" />
</fileset>
</replaceregexp>
</target>
</project>
Put the *.java files you want to comment out the XML imports and annotations for in the same directory as the build.xml file.
Right-click on the build.xml file in Eclipse, and click "Run As->Ant Build".
You should see output like:
Buildfile: D:\Eclipse_Projects\StripAnnotations\build.xml
commentOutXmlAnnotations:
BUILD SUCCESSFUL
Total time: 403 milliseconds
...and the XML imports and annotations should be commented out of your files.
Done!
Note: if you want to include all *.java files in all subdirectories of the build.xml file (for example, to comment out all XML annotations/imports generated for a bunch of JAXB classes in multiple packages), change the fileset tag to:
<fileset dir="." >
<include name="**/*.java" />
</fileset>
now, I solved it by myself by commenting all annotations with the following ant script:
<replaceregexp flags="g" byline="false">
<regexp pattern="(#Xml[A-Za-z0-9]+(\([^)]+\))?|import javax\.xml\.bind\.annotation\.[A-Za-z0-9.]+;)[ \t]*(\r?\n)"/>
<substitution expression="/*\1*/\3"/>
<fileset dir="path/to/files">
<include name="*.java"/>
</fileset>
</replaceregexp>

How to auto-increment build number of Android project in Eclipse (prefer portable solution)

Getting an IDE to automatically increment build numbers is a long discussed issue - I'm always surprised that something that seems so basic (to me) is so much work.
The highest scored question and answer (by quite a bit) for this topic are here:
https://stackoverflow.com/a/8156809/150016
My problem is that the solution depends on .net and I'd prefer to avoid a .net dependency for Eclipse solution. I also want to avoid any dependency on VCS.
So, I'm looking for a solution that is portable and 'Eclipse-ish'. I think the best candidates are an Ant solution (which I will post) or a Java app similar to the dotNet app in the linked answer above.
(I didn't add my answer to that question because it has an accepted answer and is already a very long post. If the moderators prefer I will delete this question and add my answer to the question above.)
I was hoping for something comparatively simple but I don't think any solution to this problem really is simple.
In the project's properties dialog, under Builders, you can configure a script to run prior to building your apk.
In the properties dialog, select Builders from the list on the left. Click New to add a new script. On the dialog that pops up, select Program. On the ensuing dialog, call your Builder Program what you like in the Name field. Put the path to the script in the Location field. Give it a working directory in the Working Directory field. Note that you can specify variables in these fields (e.g., we use ${build_project:/libs/update_version.sh} to reference a script in the project's lib directory).
You'll want this to run before any of the other builders, so move it to the top of the list using the Up button.
On the Build Options tab of the Dialog (it's right under the Name field towards the top), you can select options for when you want this program to run.
I'm assuming something like Linux, Unix, or MacOS here. In those systems you can use grep or its variants to get the current versionCode, increment it, and then awk or similar to modify the file accordingly. Or, you could write a Ruby, Python, Perl, etc. script to replace the versionCode in the AndroidManifest.xml file. I suppose there are equivalent tools on Windows, but I'm not very familiar with that environment.
Have you tried to 'Maven-ise' your android project build ?
If you use the "maven-android-plugin", you can keep track of your project build with pom.xml's "version" tag.
In pom.xml you can increment the build version by using "versions-maven-plugin"
To reflect the incremented build number to to your AndroidManifest.xml you can use the Synchronizing Version technique within your pom file.
This way you can auto-increment the android project build number by running the "versions-maven-plugin" every time the app builds. The solution is also portable in the same way the Ant solution is.
I hope this can also solve the problem you have mentioned (and what I have understand). Please correct me if something is missing.
Here is a solution that uses Ant. I must admit that getting Ant setup was a bit of a hassle, but it seems to be a widely used and powerful adjunct to Eclipse, so I believe it will turn out to be valuable for me in other ways.
Ant is the preferred solution for building Android SDK apps without Eclipse (as described here), but is not part of the ADT so you probably won't have it if you have just been using Eclipse.
So, the first step is to download and install Ant from here.
Next add Ant to your path and make sure that your path also points to the JDK (rather then the JRE). On Windows I found that I also had to create JAVA_HOME and point it to the root of the JDK.
We only need Ant for the auto-increment step - the intention is not to replace Eclipse and use it for the whole build - but it is useful to do a few steps in that direction to ensure that Ant is working. So, go to the root of your project and type
> android update project --path .
This creates a build.xml for your project. Once I had done that I was able to do
> ant release
and Ant built my project. If you want to keep going in that direction I found this article useful.
Next, I edited my project's new build.xml and added the following task (it can go anywhere, just not in the middle of another task/target)
<target name="update.buildnum">
<buildnumber/>
<!-- this task creates (and increments) Ant property 'build.number' which I use below -->
<echo>Current build number:${build.number}</echo>
<echoxml file="res/values/buildnum.xml">
<resources>
<string name="buildnum">${build.number}</string>
</resources>
</echoxml>
</target>
The task used above auto-increments a build number in a file (which it will create) called 'build.number' in your project's root. The rest of the task above puts the current build number into a resource string so that your application can retrieve it with this code:
String build = context.getString( com.your.app.R.string. buildnum );
int appBuild = ( int ) Integer.parseInt( build );
Some people will prefer a solution that writes the build number to the application code in the AndroidManifest.xml. Here is an answer that includes a task to do that, but it requires a 3rd party Ant task (xmltask), and I'm a bit hesitant to have a 3rd party task modifying my manifest (which is now pretty huge) on every build. If you do decide to use that task then the corresponding Android code to get the build number would be:
String packageName = ctx.getPackageName();
PackageInfo pInfo = ctx.getPackageManager().getPackageInfo( packageName, 0);
int appVer = pInfo.versionCode;
Finally, you need to get Eclipse to run this Ant task every time you do a build.
Go to your project's properties, find the Builders, and click the button to add a new Builder. There are tons of options here but you only need to specify a few.
Give the builder some name by setting the Name: field.
Select the Buildfile:. I used the 'browse workspace' option to select it, and then it filled the field with "${workspace_loc:/appname/build.xml}"
Select targets from a list on the targets tab. In my case I had to remove the 'help' task (the default task in the build.mxl generated above), and then add the 'build.number' task. I suggest you only set a target for Manual Build:.
I moved the new Builder to be the first build step.
One issue with this solution is that every time you get Eclipse to deploy (run) your application it is considered to be a new manual build, even if the project hasn't changed. So, if you deploy your application to several devices, each device will have a different build with its own build number. One thing that will ameliorate this problem a bit is that Google says that a future ADT will allow for mutiple deployments in one operation.
This (above) was tested with Ant 1.8.4, Eclipse Indigo SR2 (3.7.2), ADT 20 preview 2 and SDK Tools 20, on Win7 32bit.
My solution is based on using Ant (without XMLTask)
<property name="version.file" value="version.properties"/>
<property name="manifest.file" value="AndroidManifest.xml"/>
<!--build.slot: 0.1.2.3.4.5-->
<property name="build.slot" value="2"/>
<target name="all">
<antcall target="increment.build"/>
<antcall target="update.manifest"/>
</target>
<target name="increment.build">
<propertyfile file="${version.file}">
<entry key="build.no" type="int" default="0" operation="+" value="1" />
</propertyfile>
</target>
<scriptdef name="setBuildNo" language="javascript">
<attribute name="verName" />
<attribute name="buildNo" />
<attribute name="buildSlot" />
<attribute name="property" />
<![CDATA[
var verNums = attributes.get("vername").split(".");
var buildNo = attributes.get("buildno");
var buildSlot = attributes.get("buildslot");
if (!(buildSlot > 1 && buildSlot < 10))
buildSlot = 2;
var newVer = "";
for (var i = 0; i < Math.min(verNums.length, buildSlot); i++)
newVer += (verNums[i].trim() || "0") + ".";
for (var i = verNums.length; i < buildSlot; i++)
newVer += "0" + ".";
project.setProperty(attributes.get("property"), newVer + buildNo);
]]>
</scriptdef>
<target name="debug">
<setBuildNo verName="1" buildNo="999" property="a"/>
<setBuildNo verName="2." buildNo="999" property="b"/>
<setBuildNo verName="3.3" buildNo="999" property="c"/>
<setBuildNo verName="4.4." buildNo="999" property="d"/>
<setBuildNo verName="5.5.5" buildNo="999" property="e"/>
<setBuildNo verName="6.6.6." buildNo="999" property="f"/>
<setBuildNo verName="7.7.7.7" buildNo="999" property="g"/>
<echo>1 => ${a}</echo>
<echo>2. => ${b}</echo>
<echo>3.3 => ${c}</echo>
<echo>4.4. => ${d}</echo>
<echo>5.5.5 => ${e}</echo>
<echo>6.6.6. => ${f}</echo>
<echo>7.7.7.7 => ${g}</echo>
</target>
<target name="update.manifest">
<fail message="File not found: "${manifest.file}"" status="1">
<condition>
<not>
<available file="${manifest.file}" />
</not>
</condition>
</fail>
<!-- Reads build version -->
<loadproperties srcfile="${version.file}">
<filterchain>
<linecontains>
<contains value="build.no="/>
</linecontains>
</filterchain>
</loadproperties>
<!-- Reads versionName from AndroidManifest -->
<xmlproperty file="${manifest.file}" collapseAttributes="true"/>
<fail unless="manifest.android:versionName" message="Attribute "android:versionName" undefined into "${manifest.file}"" status="1"/>
<property name="version.name" value="${manifest.android:versionName}"/>
<!-- Create a new version -->
<setBuildNo verName="${version.name}" buildNo="${build.no}" buildSlot="${build.slot}" property="new.version.name"/>
<!-- Replaces using regexp -->
<replaceregexp
file="${manifest.file}"
match="android:versionName.*=.*".*${version.name}.*""
replace="android:versionName="${new.version.name}""/>
<!-- Replaces for check and generates a exception (if not found version) -->
<replace
file="${manifest.file}"
token="android:versionName="${new.version.name}""
value="android:versionName="${new.version.name}""
failOnNoReplacements="true"/>
<!--<echo>${version.file}</echo>
<echo>${manifest.file}</echo>-->
<echo>Auto Increment Build: ${version.name} => ${new.version.name}</echo>
</target>
Using
ant [-Dmanifest.file=<file>] [-Dversion.file=<file>] [-Dbuild.slot=<number>]
-Dmanifest.file - path and filename AndroidManifest.xml. Default: AndroidManifest.xml in a folder with build.xml
-Dversion.file - path and file name in which to store the number Build version. Default: version.properties folder with build.xml
-Dbuild.slot - position of build number in version array. Default: 2, ie X.X.build.
Auto Increment Build in Eclipse
Project | Properties | Builders | New | Ant Build
Main
Build file
<path>/build.xml
Arguments
-Dmanifest.file=${workspace_loc://AndroidManifest.xml} -Dversion.file=${workspace_loc://version.properties}
Refresh
[x] Refresh resources upon completion
(*) Specify resources
[Specify resources]
<Project>
[x] AndroidManifest.xml
Build Options
[x] Specify working set of relevant resources
[Specify resources]
<Project>
[x] res
[x] src
[x] AndroidManifest.xml
My solution used some of the code found in other answers, XMLTask, and Groovy to automatically increment the build number. I also included a rule to do a git commit and tag to link the build number to a specific point in the version control - useful for bug tracking.
<taskdef name="xmltask" classname="com.oopsconsultancy.xmltask.ant.XmlTask"/>
<path id="groovy.classpath">
<fileset dir="/Users/deepwinter1/.gvm/groovy/current/lib/">
<include name="*.jar"/>
</fileset>
</path>
<taskdef name="groovy" classname="org.codehaus.groovy.ant.Groovy">
<classpath refid="groovy.classpath"/>
</taskdef>
<target name="update.build.number">
<xmltask source="AndroidManifest.xml">
<copy path="manifest/#android:versionCode" property="buildNum"/>
</xmltask>
<groovy>
buildNum = Integer.valueOf(properties["buildNum"])
properties["buildNum"] = buildNum + 1
</groovy>
<xmltask source="AndroidManifest.xml" dest="AndroidManifest.xml">
<replace path="manifest/#android:versionCode"
withText="${buildNum}"/>
</xmltask>
<antcall target="commit.and.tag.build">
<param name="buildNum" value="${buildNum}"/>
</antcall>
</target>
<target name="commit.and.tag.build">
<exec executable="git">
<arg value="commit"/>
<arg value="-a"/>
<arg value="-m"/>
<arg value="Build Number ${buildNum}"/>
</exec>
<exec executable="git">
<arg value="tag"/>
<arg value="b${buildNum}"/>
</exec>
</target>
a "bit" better workaround answer you can find here...
https://stackoverflow.com/a/8156809/304270
Tiny c# tool which will execute before everynew new build and increase appropriate value in manifest file..

Build multiple (test/prod) versions of Android APKs in Eclipse

I'm looking to optimize generating of slightly different APKs of the same Android app, the only difference being the http API server it's using (dev/staging/prod).
Ideally, I'd just want my Eclipse to build 2 APKs, one with the prod server and one with the dev one.
I'm even OK with having 2 Run configurations, but I haven't been able to figure out how to pass parameters to the app and read them from the code.
I want to target 1.5, BTW, and I'd like to use Eclipse auto-build tools, so I'm looking for the most generic solution.
Thank you.
I think using ant build script would be the easiest solution. Eclipse supports ant build, so you can run ant command in eclipse.
You can solve your problem with ant like this.
prepare two xml android resource file.
build a package with resource #1
overwrite resource #1 with content of resource #2
build another package
xml would be like this:
resource #1:
<resources>
<string name="target">dev</string>
</resources>
resource #2:
<resources>
<string name="target">staging</string>
</resources>
and ant script would be like this:
<project>
<target name="build_all">
<copy file="res1.xml" to="res/values/target.xml"/>
<ant antfile="build.xml" target="debug"/>
<copy file="res2.xml" to="res/values/target.xml"/>
<ant antfile="build.xml" target="debug"/>
</target>
</project>
Move all you code to a library project see
http://developer.android.com/guide/developing/projects/projects-eclipse.html#SettingUpLibraryProject
Then create separate projects in eclipse for test and production each with a unique package name. You can then use the package name to distinguish between versions.
Something like:
public static boolean isProductionVersion(){
return context.getPackageName().toLowerCase().contains("production");
}
This may seem like overkill for managing different http end points but it will make the code more manageable. You can also do useful things like:
flag the test version with a different application icon
run test and production versions side by side on one device
This can all be done in eclipse without using and third party tools.
Its not really what you want:
private static Boolean isSignedWithDebugKey = null;
protected boolean signedWithDebug() {
if(isSignedWithDebugKey == null) {
PackageManager pm = getPackageManager();
try {
PackageInfo pi = pm.getPackageInfo(getPackageName(), 0);
isSignedWithDebugKey = (pi.applicationInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
}
catch(NameNotFoundException nnfe) {
nnfe.printStackTrace();
isSignedWithDebugKey = false;
}
}
return isSignedWithDebugKey;
}
You could then hit a dev/staging server if the app is signed with a debug key, and production with a release certificate.
For passing parameters, you could always create a file in android's directory system and have your code read it from it.
In my case I just wanted to change a few values in strings.xml between different versions.
First I have to load the ant-contrib library, to define the for loop task:
<taskdef resource="net/sf/antcontrib/antcontrib.properties">
<classpath>
<pathelement location="lib/ant-contrib-1.0b5-SNAPSHOT.jar" />
</classpath>
</taskdef>
I put my list of configurations, config.names, in a properties file:
config.url.root=http://projectserver.aptivate.org/
config.names=student-production, teacher-production, student-testing, teacher-testing
And define a build-all target, that loops over the config.names:
<target name="build-all">
<for param="config.name" trim="true" list="${config.names}">
<sequential>
Defining a custom resources directory for each one, saving the directory name in the config.resources property:
<var name="config.resources" unset="true" />
<property name="config.resources" value="bin/res-generated/#{config.name}" />
Delete it, and copy the global resources from res into it:
<delete dir="${config.resources}" />
<copy todir="${config.resources}">
<fileset dir="res"/>
</copy>
Change - to / in the config name, to make it a path in the URL parameter:
<var name="config.path" unset="true" />
<propertyregex property="config.path"
input="#{config.name}" regexp="-"
replace="/" casesensitive="true" />
Run an XSLT transform to modify the strings.xml file:
<xslt in="res/values/strings.xml"
out="${config.resources}/values/strings.xml"
style="ant/create_xml_configs.xslt"
force="true">
<param name="config.url.root" expression="${config.url.root}" />
<param name="config.name" expression="#{config.name}" />
<param name="config.path" expression="${config.path}" />
</xslt>
This is the XSLT stylesheet that I use:
<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:param name="config.url.root" />
<xsl:param name="config.name" />
<xsl:param name="config.path" />
<!-- http://my.safaribooksonline.com/book/xml/9780596527211/creating-output/xslt-id-4.6 -->
<xsl:template match="/">
<!--
This file is automatically generated from res/values/strings.xml
by ant/custom_rules.xml using ant/create_xml_configs.xslt.
Do not modify it by hand; your changes will be overwritten.
-->
<xsl:apply-templates select="*"/>
</xsl:template>
<xsl:template match="*">
<xsl:copy>
<xsl:for-each select="#*">
<xsl:copy/>
</xsl:for-each>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
<!-- the value of update_server_url must end with a slash! -->
<xsl:template match="string[#name='update_server_url']/text()">
<xsl:value-of select="$config.url.root" /><xsl:value-of select="$config.path" />/
</xsl:template>
<xsl:template match="string[#name='app_version']/text()">
<xsl:value-of select="." />-<xsl:value-of select="$config.name" />
</xsl:template>
</xsl:stylesheet>
And back to custom_rules.xml where I then extract the app_version from the original (unmodified) res/values/strings.xml:
<xpath input="res/values/strings.xml"
expression="/resources/string[#name='app_version']"
output="resources.strings.app_version" />
And use the antcall task to call the debug build:
<antcall target="debug">
<param name="resource.absolute.dir" value="${config.resources}" />
<param name="out.final.file" value="${out.absolute.dir}/${ant.project.name}-${resources.strings.app_version}-#{config.name}.apk" />
</antcall>
with two changed property values:
resource.absolute.dir tells the debug target to use my modified res directory, defined in the config.resources property above;
out.final.file tells it to produce an APK with a different name, including the configuration name (e.g. student-testing) and the version number extracted from strings.xml.
And then, finally, I can run ant build-all from the command line and build all four targets. A little bit more script, just before the end of the build-all target, lists the compiled APK files together for reference:
<echo message="Output packages:" />
<for param="config.name" trim="true" list="${config.names}">
<sequential>
<echo message="${out.absolute.dir}/${ant.project.name}-${resources.strings.app_version}-#{config.name}.apk" />
</sequential>
</for>

Categories

Resources