How does gradle execute an ant build file - android

Ive been driving myself crazy trying to rebuild my custom_rules.xml into something in gradle and its proving to be quite difficult. So my next step is Im trying to just import the last few things I cant do in gradle as an build.xml.
However this doesnt seem to do anything. When I try using
ant.importBuild 'build.xml'
I get no feed back or no echos from my script. Ive read through gradles documentation a lot especially on ant and for the life of me I cant figure out what Im supposed to do once the build gets imported. How does the script get executed?
This is my build.xml
<?xml version="1.0" encoding="UTF-8"?>
<project>
<target name="postPackage" >
<property name="config_path" location="${cert.dir}" />
<property name="out.pre.widevine.signed.file" location="release-pre-widevine-sign.apk" />
<property name="out.widevine.signed.file" location="release-widevine-signed.apk" />
<echo>sign with widevine certificate</echo>
<touch file="res/raw/wv.properties"/>
<copy file="${out.packaged.file}" tofile="${out.pre.widevine.signed.file}"/>
<java jar="apksigtool.jar" failonerror="true" fork="true">
<arg value="${out.packaged.file}"/>
<arg value="private_key.der" />
<arg value="my.crt" />
</java>
<copy file="${out.packaged.file}" tofile="${out.widevine.signed.file}"/>
</target>
</project>

I was able to accomplish this by using the following snippet in a method
ant.importBuild 'build.xml'
postPackage.doFirst{println("Im starting")}
postPackage.execute()

ant.importBuild will create an equally named Gradle task for each Ant target found in the Ant build. You can then invoke those tasks from the command line and/or make other tasks depend on them. For more information, see "16.2. Importing an Ant build" in the Gradle User Guide,

Hmm I think this Kotlin is working for me;
val t : Task = tasks.named("war").get()
t.actions.forEach { a -> a.execute(t) }

Related

Ant build in Eclipse

I am trying to use custom build file in order to display the current git version in my Android application. I haven't used ant before and I have not really an idea how to use it. I read plenty of topics in SO and searched quite a lot in Google but I cannot figure it out. I don't really have the time to learn everything about ant but I need this thing running. At the bottom, you can find the code.
Current status
The file custom_rules.xml is imported in the build.xml created by Eclipse. The macrodef part is invoked but the targets not. I tried to change the External Tools Configurations, tab Targets but whenever I check a target (no matter in which ant file), I get a message:
Unknown argument: -pre-build
for example (when I put checkmark on -pre-build). I tried adding this line:
<import file="${sdk.dir}/tools/ant/build.xml" />
and defining sdk.dir but that doesn't change anything. What am I missing? As I said, I have no idea about ant and the only tutorial that helped me was this one.
Current code (custom_rules.xml)
<?xml version="1.0" encoding="UTF-8"?>
<?eclipse.ant.import ?>
<project name="Custom build">
<macrodef name="git" taskname="#{taskname}">
<attribute name="command" />
<attribute name="dir" default="" />
<attribute name="property" default="" />
<attribute name="taskname" default="" />
<attribute name="failonerror" default="on" />
<element name="args" optional="true" />
<sequential>
<exec executable="git" dir="#{dir}" outputproperty="#{property}"
failifexecutionfails="#{failonerror}" failonerror="#{failonerror}">
<arg value="#{command}" />
<args/>
</exec>
</sequential>
</macrodef>
<target name="-pre-build">
<git command="rev-list" property="versioning.code" taskname="versioning">
<args>
<arg value="master" />
<arg value="--first-parent" />
<arg value="--count" />
</args>
</git>
<git command="describe" property="versioning.name" taskname="versioning">
<args>
<arg value="--always" />
</args>
</git>
<echo level="info" taskname="versioning">${versioning.code}, ${versioning.name}</echo>
<replaceregexp file="AndroidManifest.xml" match='android:versionCode=".*"' replace='android:versionCode="${versioning.code}"' />
<replaceregexp file="AndroidManifest.xml" match='android:versionName=".*"' replace='android:versionName="${versioning.name}"' />
</target>
<target name="-post-build" >
<replaceregexp file="AndroidManifest.xml" match='android:versionCode=".*"' replace='android:versionCode="0"' />
<replaceregexp file="AndroidManifest.xml" match='android:versionName=".*"' replace='android:versionName="0"' />
</target>
</project>
I just figured it out.
I renamed the targets to pre-build and post-build without -.
I went to External Tools Configurations and selected build.xml to the left. On the right, I went to the tab Targets, checked my two targets (in addition to the build target which already had a checkmark) and set the order to be pre-build, build, post-build.
I went to the project properties and I selected Builders on the left. I created a new builder using the build.xml file and having the three targets from the previous bullet point, in the same order. I placed this builder before the Java builder.
I removed the post-build target as it puts the version back to 0 and seems to do that earlier than I would like.
I am still not sure that this is the optimal solution. Also, the solution fails when there is no git versioning. I tried using this code for solving the issue but it didn't worked. Nevertheless, it is the best I could do and it helps me getting the info I need in the app.
Use Git executable with Argument --version and catch the output in a property for further usage, f.e. :
<project>
<exec executable="git" outputproperty="gitversion">
<arg value="--version"/>
</exec>
<echo>$${gitversion} => ${gitversion}</echo>
</project>
output :
[echo] ${gitversion} => git version 1.8.3.msysgit.0

Using Ant how can I dex a directory of jars?

I have a directory full of jars (felix bundles). I want to iterate through all of these jars and create dex'd versions. My intent is to deploy each of these dex'd jars as standalone apk's since they are bundles. Feel free to straighten me out if I am approaching this from the wrong direction.
This first part is just to try and create a corresponding .dex file for each jar. However when I run this I am getting a "no resources specified" error coming out of Ant.
Is this the right approach, or is there a simpler approach to just input a jar and output a dex'd version of that jar? The ${file} is valid as it is spitting out the name of the file in the echo command.
<target name="dexBundles" description="Run dex on all the bundles">
<taskdef resource="net/sf/antcontrib/antlib.xml" classpath="${basedir}/libs/ant-contrib.jar" />
<echo>Starting</echo>
<for param="file">
<path>
<fileset dir="${pre.dex.dir}">
<include name="**/*.jar" />
</fileset>
</path>
<sequential>
<echo message="#{file}" />
<echo>Converting jar file #{file} into ${post.dex.dir}/#{file}.class...</echo>
<apply executable="${dx}" failonerror="true" parallel="true" verbose="true">
<arg value="--dex" />
<arg value="--output=${post.dex.dir}/${file}.dex" />
<arg path="#{file}" />
</apply>
</sequential>
</for>
<echo>Finished</echo>
</target>
Give this a go:
<target name="dexBundles" description="Run dex on all the bundles">
<apply executable="${exec.dx}" dest="${post.dex.dir}/" parallel="false">
<arg value="--dex"/>
<arg value="--output="/>
<targetfile/>
<srcfile/>
<fileset dir="${pre.dex.dir}" includes="**/*.jar"/>
<mapper type="glob" from="*.jar" to="*.dex"/>
</apply>
</target>
It looks like the ant apply task allows you to iterate over a file set without need for ant-contrib (specifically that page has an example that looks for *.c in a directory, compiles them, and renames them to *.o in a specified directory that should be directly applicable). Unfortunately, it looks like you'll lose the traceability provided by your echo messages.
For the record, I believe the error message is actually being generated by dx.bat not ant directly, but I am not certain, and I don't know why.
Hope that helps.
see the document of the "Ant apply task",it's said:“At least one fileset or filelist is required”
so,this line "no resources specified" is printed to notify u that to write some fileset or filelist.....
use "exec" instead.

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";
}
?>

Findbugs for Android project with libraries in ant build

Findbugs is a great software and my team uses it while working on our Android project. In Eclipse everything is nice and shiny, however now we're trying to automate our builds with ant and generate Findbugs results automatically for each build.
It's seems not that difficult. I followed this tutorial:
https://wiki.jenkins-ci.org/display/JENKINS/Building+an+Android+app+and+test+project#BuildinganAndroidappandtestproject-FindBugs
One minor issue is that I had to change ${android.jar} to ${project.target.android.jar}.
The worse part are The following classes needed for analysis were missing: warnings for classes that come form library projects we use. Some of them are our own and we would like to scan them with Findbugs, too. To make matters more complicated, one of these libs uses another lib (also our own and needs scanning), so it looks like this:
Project A --uses--> Library B --uses--> Library C
Here I thought that since Android SDK can handle all these dependencies (Library C is compiled when I issue ant debug for Project A), I can somehow make use of it, get the list of libs my project depends on and provide it to the findbugs task. Unfortunately I haven't managed to do that.
For now I settled with manually entering all libs, some into class property of findbugs task, some into auxClasspath, which has the upside that I can only analyse some of the libraries the project depends on. Still I hope that what I originally tried to do is possible. Can anybody show me how to extract a path-element
I've finally found that part of SDK build script that puts together a "classpath" of all the jars (classes.jar-s of all the libraries, including Library C from the "diagram" and jars from the libs/ folder of the project and all the libs).
My final custom-rules.xml with findbugs target looks like this:
<?xml version="1.0" encoding="UTF-8"?>
<project name="Project_custom" default="findbugs">
<taskdef name="findbugs" classname="edu.umd.cs.findbugs.anttask.FindBugsTask"/>
<target name="findbugs">
<gettarget
androidJarFileOut="project.target.android.jar"
androidAidlFileOut="project.target.framework.aidl"
bootClassPathOut="project.target.class.path"
targetApiOut="project.target.apilevel"
minSdkVersionOut="project.minSdkVersion" />
<dependency
libraryFolderPathOut="project.library.folder.path"
libraryPackagesOut="project.library.packages"
libraryManifestFilePathOut="project.library.manifest.file.path"
libraryResFolderPathOut="project.library.res.folder.path"
libraryBinAidlFolderPathOut="project.library.bin.aidl.folder.path"
libraryNativeFolderPathOut="project.library.native.folder.path"
jarLibraryPathOut="project.all.jars.path"
targetApi="${project.target.apilevel}"
verbose="${verbose}" />
<findbugs home="${findbugs.home}" output="xml" outputFile="findbugs-results.xml">
<auxClasspath>
<pathelement location="${project.target.android.jar}" />
<path refid="project.all.jars.path" />
</auxClasspath>
<class location="${out.dir}" />
</findbugs>
</target>
</project>
Edit: I've upgraded the target to run indepent of the build targets, i.e. now you can run just ant findbugs not ant debug findbugs.
I added some extra definition and worked. Thank you
<target name="findbugs">
<mkdir dir="reports" />
<gettarget
androidJarFileOut="project.target.android.jar"
androidAidlFileOut="project.target.framework.aidl"
bootClassPathOut="project.target.class.path"
targetApiOut="project.target.apilevel"
minSdkVersionOut="project.minSdkVersion" />
<dependency
libraryFolderPathOut="project.library.folder.path"
libraryPackagesOut="project.library.packages"
libraryManifestFilePathOut="project.library.manifest.file.path"
libraryResFolderPathOut="project.library.res.folder.path"
libraryBinAidlFolderPathOut="project.library.bin.aidl.folder.path"
libraryNativeFolderPathOut="project.library.native.folder.path"
jarLibraryPathOut="project.all.jars.path"
libraryRFilePathOut="project.library.rfile.path"
buildToolsFolder="${sdk.dir}/build-tools"
renderscriptSupportLibsOut="project.rs.support.libs.path"
renderscriptSupportMode="${renderscript.support.mode}"
targetApi="${project.target.apilevel}"
verbose="${verbose}" />
<findbugs home="${findbugs.home}" output="xml:withMessages" outputFile="reports/findbugs.xml" excludeFilter="findbugs-exclude.xml" maxRank="9">
<!-- auxClasspath path="${project.target.android.jar}" / -->
<auxClasspath>
<pathelement location="${project.target.android.jar}" />
<path refid="project.all.jars.path" />
</auxClasspath>
<sourcePath path="${basedir}/src/" />
<class location="${basedir}/bin/classes/" />
</findbugs>
</target>

Android - How do I dynamically set the package name at build time for an Open-source project?

I'm working on an Open-source project. As it is intended that anyone can download the source and build it themselves, I do not want to hard-code the package name anywhere - including the directory structure.
I use ant for building. Apparently I can modify build.xml, but I believe this is overwritten by android update. Whatever is used will be committed to the Git repo, and it should not be too complicated.
Currently the process to build the code straight from the Git repo is fairly simple. Here's an excerpt from the README file:
$ cd ~/src/isokeys/IsoKeys
$ android list targets # I build against API level 10.
$ android update project --name IsoKeys --target 1 --path ./ # Only needed first time.
$ ant debug && adb -d install -r bin/IsoKeys-debug.apk
To me, it makes sense to put the package name in local.properties, because this is .gitignore'd. As the package name won't be anywhere else, the build will fail without doing this. So there needs to be at least 1 extra step in the README, but I want to keep it to a minimum.
Edit: Of course, another requirement is that diffs make sense - which they don't if you manually rename the package name.
I did something similar (but not for this reason) which required updating the manifest at build time. The way I accomplished this was by making a second AndroidManifest and putting it under a directory named config.
So in config/AndroidManifest you could have something like this:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="#CONFIG.APP_PACKAGE_NAME#"
android:versionCode="#CONFIG.APP_VERSION_CODE#"
android:versionName="#CONFIG.APP_VERSION#">
<!-- EVERYTHING ELSE GOES HERE -->
</manifest>
Then you can use the regular bare bones build.xml ant script with just a few modifications (no need to copy the whole script from the android build system as they added some hooks for you to use without reinventing the wheel).
The build script should be reading local.properties by default, but if not add (or uncomment) a line like this:
<property file="local.properties" />
In your build script you should see a task called "-pre-build", change it like this:
<target name="-pre-build">
<copy file="config/AndroidManifest.xml" todir="." overwrite="true" encoding="utf-8">
<filterset>
<filter token="CONFIG.APP_PACKAGE_NAME" value="${app.packagename}" />
<filter token="CONFIG.APP_VERSION" value="${app.version}" />
<filter token="CONFIG.APP_VERSION_CODE" value="${app.versioncode}" />
</filterset>
</copy>
</target>
Then your local.properties file you would put the package name, version name/code like so:
app.version=1.0
app.versioncode=1
app.packagename=com.mypackage.name
Now you just need to make sure in your manifest that you fully qualify all of your activities/services/broadcast listeners etc.. That means you always specify the full package of your source code. If you want the package for your own source code to be dynamic you could replace out each of the prefixes to each class.. But that seems kind of silly.. It is easy enough to package your code up under your own package name and they can use it from any project by simply including the source or a jar in their project.
-- UPDATE --
Oh and one other thing you can do to notify the user that they must define a package name is use the fail tag in your build xml like this:
<fail message="app.packagename is missing. This must be defined in your local.properties file" unless="app.packagename" />
Put this after the line which reads the local.properties file
With thanks to Matt Wolfe for his help, I'm posting a partial answer with my efforts so far.
I noticed that the default barebones build.xml would also import custom_rules.xml:
<import file="custom_rules.xml" optional="true" />
So I created this file and started tinkering. This is what I have come up with so far:
<?xml version="1.0" encoding="UTF-8"?>
<project name="custom_rules" default="debug">
<target name="-pre-build">
<fail message="Please define app.packagename in your local.properties file." unless="app.packagename" />
<taskdef resource="net/sf/antcontrib/antcontrib.properties">
<classpath>
<pathelement location="/usr/share/java/ant-contrib.jar"/>
</classpath>
</taskdef>
<!-- How do I check for propertyregex?
<fail message="Depends on ant-contrib's propertyregex for app.packagename.path." unless="propertyregex" />
-->
<propertyregex property="app.packagename.path"
input="${app.packagename}/"
regexp="\."
replace="/"
global="true"
/>
<copy todir="build/" overwrite="true" encoding="utf-8">
<fileset dir="./">
<include name="AndroidManifest.xml" />
<include name="res/**" />
<include name="lib/**" />
</fileset>
<filterset>
<filter token="CONFIG.APP_PACKAGE_NAME" value="${app.packagename}" />
</filterset>
</copy>
<copy todir="build/src/${app.packagename.path}" overwrite="true" encoding="utf-8">
<fileset dir="./src/isokeys/">
<include name="**" />
</fileset>
<filterset>
<filter token="CONFIG.APP_PACKAGE_NAME" value="${app.packagename}" />
</filterset>
</copy>
</target>
<target name="-pre-clean" description="Removes output files created by -pre-build.">
<delete file="build/AndroidManifest.xml" verbose="${verbose}" />
<delete dir="build/res/" verbose="${verbose}" />
<delete dir="build/lib/" verbose="${verbose}" />
<delete dir="build/src/" verbose="${verbose}" />
</target>
<!-- NOW CHANGE DIRECTORY TO build/ BEFORE HANDING BACK OVER TO build.xml!!! -->
</project>
This sets everything up in build/ (which has the added bonus of keeping things neat and tidy), now the intention is for the sdk tools build.xml to run from this build/ directory. However, I can't find any way of cd'ing.
Easiest way might be replace the package name as late as possible. This way, you don't even have to touch your code. There is a nice article named Renaming the Android Manifest package(http://www.piwai.info/renaming-android-manifest-package/). Summary:
You can use aapt --rename-manifest-package to modify the package name
Alternatively, if you want package name replacement to be a part of the ant build process, you can override the -package-resources target:
copy the -package-resources target from SDK's build.xml
add manifestpackage parameter

Categories

Resources