Ant doesn't pick up file modification when build - android

I'm trying to build my android project from command line.
ant debug install && adb shell 'am start -n com.test.example/.MainActivity'
I find, ant doesn't recognise modified files sometimes(or most of times) unless I do ant clean
Is there a workaround to make ant recognise file changes while developing?

This is a known issue:
ant clean
ant debug <-- This result is OK.
change some source code
ant debug
RESULT:
-dex:
[dex] No new compiled code. No need to convert bytecode to dalvik format.
...
-package:
[apkbuilder] No changes. No need to create apk.
you can try a few things things:
Workaround for [dex]: include a <delete> just before the call to <dex /> within the macro "dex-helper":
<delete file="${intermediate.dex.file}"/>
Workaround for [apkbuilder]: include a <delete> into the macro "package-helper":
<macrodef name="package-helper">
<element name="extra-jars" optional="yes" />
<sequential>
<delete failonerror="false" file="${out.packaged.file}"/>
<apkbuilder outfolder="${out.abs.dir}" resourcefile="${res.pkg.file.name}"
...
See HERE for these Workarounds and a long, related, discussion.
these may be useful too:
try ant clean debug: call clean, because otherwise the build system will not detect changes in the configuration, and may not recompile the proper classes. , OR
android update project -p <project-path>: will generate any files and folders that are either missing or need to be updated, as needed for the Android project See HERE

Related

How to generate BuildConfig.DEBUG?

Using an IDE like Eclipse, IntelliJ, Studio, the class BuildConfig is auto generated in the gen folder. But what if you are using makefiles; not using an IDE? Can any of the build tools auto generate this?
When I tried to add android:debuggable attribute to my AndroidManifest.xml
as described in the link below, I got a compiler error that it could not find the field.
http://developer.android.com/tools/publishing/preparing.html
Turn off logging and debugging
Make sure you deactivate logging and disable the debugging option
before you build your application for release. You can deactivate
logging by removing calls to Log methods in your source files. You can
disable debugging by removing the android:debuggable attribute from
the tag in your manifest file, or by setting the
android:debuggable attribute to false in your manifest file. Also,
remove any log files or static test files that were created in your
project.
Yes, the build tools from command can generate BuildConfig.java file for you.
1.create project in command
$ android create project -t android-21 -p . -n AntTest --package com.example.test -a StartupActivity
2.create the makefile
release:
#ant release
debug:
#ant debug
release_install:
#ant installr
debug_install:
#ant installd
3.you can reference BuildConfig in your code, the build tool ant will generate BuildConfig.java for you.
After you invoke any command to build the project, you will see the file is generated gen/com/example/test/BuildConfig.java.
Additional information
BuildConfig.java is handled and generated by ant. We can see it from $ANDROID_SDK_ROOT/tools/ant/build.xml.
<echo level="info">----------</echo>
<echo level="info">Handling BuildConfig class...</echo>
<buildconfig
genFolder="${gen.absolute.dir}"
package="${project.app.package}"
buildType="${build.is.packaging.debug}"
previousBuildType="${build.last.is.packaging.debug}"/>

android libs calculated before libs are populated?

this is a weird one. i have a -pre-compile target in my custom_rules.xml. in here, some JARs get copied into the libs folder.
if i do a clean build, it fails at runtime because those libraries do not get included in the .apk. looking at the output of ant -v ..., Dx is not processing those libs. so, while the project is being compiled against against those libraries, they are not included at the Dx phase.
if i subsequently do a non-clean ant debug, everything is fine, as the JARs copied by -pre-compile were already there at the start of the build.
any ideas what i'm doing wrong?
i eventually figured this out by painstakingly adding echo statements to the .../tools/ant/build.xml from the SDK.
the path that includes the libraries in .../libs for Dx is defined in the -setup task. this is in the chain before -pre-compile or -pre-build, so if you copy JARs into your .../libs folder at either of those points, it's too late.
i ended up overriding the -setup task, as so,
<target name="-setup" depends="-prepare-libs, android_rules.-setup"/>
<target name="-prepare-libs">
... build / copy libs in to .../libs here
</target>
note the syntax for calling through to the overridden -setup task ... the project name defined in the project tag appended with the task name, as defined in the build.xml imported from the SDK.

Multiple automatic build ouputted to single directory

I'm new to automating builds using Ant. I have a bunch of Android project in Eclipse and I've gotten as far as setting up Ant builds I can run from the command line for each project, where a signed APK is generated in the 'bin' directory for whatever project I am running the build on.
If possible, I'd like to setup a single script to build each of my projects and output the signed APK's to one directory on my computer. Not exactly sure how to do that, whether I need to write a batch script or something else.
Any insight would be appreciated.
A batch script could be one option. Another, now that you're working with Ant, would be to create an Ant script that runs all the other Ant scripts and copies the results.
You can use the ant task to run one Ant script from another. You can then use the copy task to copy the resulting APK file to where you want it.
Here is an example that runs the default target of the build.xml file found in the directory path_to_other_project and then copies any APK files found in path_to_other_project/bin to destination_dir.
<ant dir="path_to_other_project"
antfile="build.xml"
inheritAll="false"
inheritRefs="false" />
<copy todir="destination_dir">
<fileset dir="path_to_other_project/bin" includes="*.apk" />
</copy>
If you have several projects, you can replace several similar calls to ant with one call to subant.

Managing android projects from command line

I am managing and running my android app from command line without using ant, I followed these steps:
generate R.java
compile R.java and all .java files in src to .class files
assembling set of class files into dex file using the command below
dx --dex --verbose --output=./bin/classes.dex ./bin
.class files are in bin directory.
But I'm getting the following errors in these steps:
java.lang.Runtime exception:.\bin file not found
at com.android.dx.cf.direct.ClassPathOpener.process
at com.android.dx.command.dexer.Main.processOne
at com.android.dx.command.dexer.Main.processAllFiles
at com.android.dx.command.dexer.Main..run
at com.android.dx.command.dexer.Main.main
at com.android.dx.command.Main.main
Due to this, I'm unable to create the Classes.dex file.
Can someone suggest a solution for this?
[not using eclipse and ant only through command line]
If you need to "manage your Android projects from command line", when you should use Ant build.
Ant's build.xml is a official standardized way to build Android projects. Ant scripts can do anything you may need to build your project.
If you want most modern build tools for Android, you can look at Gradle for Android projects. Note: today it's still in alpha stage.
Try entering the full path instead of the relative path.
Also you must put the class files inside a directory named exactly like it's package name. for example for com.test.me.MyActivity you must use com/test/me/MyActivity.class
And since we are on the topic, remember that dx can only work with class files created using Java6 (or less) so if you are using java7 to compile your code, add "source 1.6 target 1.6" parameters to your command line.

Android – multiple custom versions of the same app

Whats the best way to deploy several customized versions of a Android application?
Currently I have a script to exchange the resource folder for getting a customized version of my app. It works great, but all custom versions still have the same package name in the AndroidManifest.xml. Therefore it is not possible to install two customized versions of the app at the same time.
This is one solution for this problem, but that has to be done by hand
Can you think of a more easy solution, or how this could be built into a skript?
(btw: it is not for a porn/spam/whatever app, not even a paid one)
Perhaps the built-in Android "library" concept was not fully baked at the time of the original post, but it may be the preferred method as of 2011. Follow these steps for an ant build:
Starting from a working app (let's call it directory "myOrigApp", package com.foo.myapp), just add this line to "default.properties" to make it a library:
android.library=true
Now create a new app in a sibling directory in any way you prefer (let's call it directory "sibling", package com.foo.myVariant). Using Intellij Idea, for example, create a project 'from scratch' with directory 'sibling' and it will create all the files/directories you would normally need.
In that new, sibling directory edit "default.properties" to add the dependency:
android.library.reference.1=../myOrigApp
Copy over the Manifest from the original dir:
cd sibling
cp ../myOrigApp/AndroidManifest.xml ../myOrigApp/local.properties ../myOrigApp/build.properties .
Edit that copied Manifest file to change its package name to your new variant, "com.foo.myVarient"; that's the only change.
If you just run the ant build scripts, you may be done. (I had to just set up signing keys.)
If you want to set up an IDE like Idea to have the library project as a dependent of the variant project, follow these steps to add a library project to the variant project (assumes you already have a project set up for both):
Open the original project, bring up Project Settings, select your Facet and check "Is Library Project" and save.
Open the variant project, bring up Project Settings, select Modules
Add a module
Select “Import existing module”
Browse to the Original directory (myOrigApp) and select its .iml file (IntelliJ project source file)
Click "Finish." (The library project is added as a module within the variant project.)
In the modules list click over the Variant project to select it.
On the right hand side select the "Dependencies" tab.
Click "Add…"
Choose "Module dependency…" (A list should appear that includes the name of the module/library you previously added to the project--perhaps the only entry in the list).
Select the library project you added and press OK. (It will be added to the list of dependencies of your project.)
Press OK to finish configuring the project. (You should see 2 modules, with the library's resources and classes available and recognized in the Variant project.)
What I did for something similar to this is to just use an antlib task and then go through all java and xml files to replace my old package string to the new package string. It didn't matter if the files were not in the correct src paths according to the package. Just doing a regex replace for all the files was enough for me to get this working...
For example to replace it in all your java files under the src directory:
<replaceregexp flags="g" byline="false">
<regexp pattern="old.package.string" />
<substitution expression="new.package.string" />
<fileset dir="src" includes="**/*.java" />
</replaceregexp>
You definitely want to use Gradle flavors that comes natively, encouraged even, on Android Studio.
It seems to explain all the basics really well. I just finished converting to Gradle today, and it works great. Custom app icons, names, and strings, etc.
As the website explains, part of the purpose behind this design was to make it more dynamic and more easily allow multiple APKs to be created with essentially the same code, which sounds similar what you're doing.
I probably didn't explain it the best, but that website does a pretty good job.
The linked-to solution does not have to be done by hand. Bear in mind that the package attribute in the <manifest> element does not have to be where the code resides, so long as you spell out the fully-qualified classes elsewhere in the manifest (e.g., activity android:name="com.commonsware.android.MyActivity" rather than activity android:name=".MyActivity"). Script your manifest change and use Ant to build a new APK. AFAIK, that should work.
Support Multiple Partners
Prepare config.xml
Build project for different partner
<!--partner.dir, pkg.name, ver.code, ver.name are input from command line when execute 'ant' -->
<!-- set global properties for this build -->
<property name="build.bin" location="bin"/>
<property name="build.gen" location="gen"/>
<property name="src" location="src"/>
<property name="res" location="res"/>
<target name="preparefiles" description="Prepare files for different partner" >
<delete dir="${build.bin}" />
<delete dir="${build.gen}" />
<copy todir="${res}" overwrite="true" />
<fileset dir="${partner.dir}/res" />
</copy>
<!-- change the import in all Java source files -->
<replaceregexp file="AndroidManifest.xml"
match='android.versionCode="(.*)"'
replace='android.versionCode="${ver.code}"'
byline="false">
<replaceregexp file="AndroidManifest.xml"
match='android.versionName="(.*)"'
replace='android.versionName="${ver.name}"'
byline="false">
<replaceregexp file="AndroidManifest.xml"
match='package="(.*)"'
replace='package="${pkg.name}"'
byline="false">
<!-- change the package name in AndroidManifest -->
<replaceregexp flags="g" byline="false">
<regexp pattern="import(.*)com.myproject.com.R;" />
<substitution expression="import com.${pkg.name}.R;" />
<fileset dir="${src}" includes="**/*.java" />
</replaceregexp>
<replaceregexp flags="g" byline="false">
<regexp pattern="(package com.myproject.com;)" />
<substitution expression="\1
import com.${pkg.name}.R;" />
<fileset dir="${src}" includes="**/*.java" />
</replaceregexp>
</target>
Prepare Files
$ ant -f config.xml -Dpartner.dir="xxx" -Dpkg.name="xxx" -Dver.code="xxx" -Dver.name="xxx" preparefiles
Create build.xml
Build
$ ant debug
or
$ ant release
I'm using the maven-android-plugin to achieve this. Specify one AndroidManifest.xml for the generated-sources goal and another AndroidManifest.xml for the final apk goal. That way the source code project retains the actual source code package name during generation of the R class and the build phase, while the market adapted manifest package name is in the second AndroidManifest.xml which is included in the final apk file.
I wound up with a script that patches the sources; patching the source sounds risky, but in presence of version control the risk is acceptable.
So I made one version, committed the source, made the other version, committed the source, and looking at diffs wrote a patching script in Python.
I am not sure if it is the best solution. (And the code misses some os.path.joins)
The heart of the script is the following function:
# In the file 'fname',
# find the text matching "before oldtext after" (all occurrences) and
# replace 'oldtext' with 'newtext' (all occurrences).
# If 'mandatory' is true, raise an exception if no replacements were made.
def fileReplace(fname,before,newtext,after,mandatory=True):
with open(fname, 'r+') as f:
read_data = f.read()
pattern = r"("+re.escape(before)+r")\w+("+re.escape(after)+r")"
replacement = r"\1"+newtext+r"\2"
new_data,replacements_made = re.subn(pattern,replacement,read_data,flags=re.MULTILINE)
if replacements_made and really:
f.seek(0)
f.truncate()
f.write(new_data)
if verbose:
print "patching ",fname," (",replacements_made," occurrence", "s" if 1!=replacements_made else "",")"
elif replacements_made:
print fname,":"
print new_data
elif mandatory:
raise Exception("cannot patch the file: "+fname)
And you may find the following one of use:
# Change the application resource package name everywhere in the src/ tree.
# Yes, this changes the java files. We hope that if something goes wrong,
# the version control will save us.
def patchResourcePackageNameInSrc(pname):
for root, dirs, files in os.walk('src'):
if '.svn' in dirs:
dirs.remove('.svn')
for fname in files:
fileReplace(os.path.join(root,fname),"import com.xyz.",pname,".R;",mandatory=False)
There is also a function that copies assets from x-assets-cfgname to assets (earlier it turned out that for me it is more convenient to have a subdirectory in assets).
def copyAssets(vname,force=False):
assets_source = "x-assets-"+vname+"/xxx"
assets_target = "assets/xxx"
if not os.path.exists(assets_source):
raise Exception("Invalid variant name: "+vname+" (the assets directory "+assets_source+" does not exist)")
if os.path.exists(assets_target+"/.svn"):
raise Exception("The assets directory must not be under version control! "+assets_target+"/.svn exists!")
if os.path.exists(assets_target):
shutil.rmtree(assets_target)
shutil.copytree(assets_source, assets_target, ignore=shutil.ignore_patterns('.svn'))
Well, you get the idea. Now you can write your own script.
I think the best way is to create a new project and copy the stuff. steps,
- create new android project without a class
- create package (package name should be corresponding to the one in the manifest file), or just copy the package name in the 'gen' folder
- copy the java files
- copy the drawable folders
- copy the layout files
- copy any other file(s) used in ur project
- copy manifest file's data
this has been simpler for me for the task

Categories

Resources