`ant` is looking for `aapt` in project directory? - android

I am lately having problems with a build process that has been working for months now - I may have updated the Android build tools since the last working build, but I am not sure.
In any case
ant -Dsdk.dir=$ANDROID_HOME -Djava.source=7 -Djava.target=7 clean release
is failing with the following message:
/home/dmta/development/android-sdk-linux/tools/ant/build.xml:694: Execute failed: java.io.IOException:
Cannot run program "/home/dmta/EclipseProjects/MyProject/Hawk/${aapt}"
(in directory "/home/dmta/EclipseProjects/MyProject/Hawk"): error=2,
No such file or directory
Where Hawk is a library project I am using.
What could be wrong here?
I can build the program from Eclipse but I need to use the ant build for proguard.

the AAPt location is changed in the latest update. Copy the lib/dx and aapt : these two files back to platform-tools.
Also try adding the tools path if not there already, example:
<!-- tools location -->
<property name="android.tools.dir" location="${sdk.dir}/tools" />
<property name="android.platform.tools.dir" location="${sdk.dir}/platform-tools" />
<property name="android.buildtools.dir" location="${sdk.dir}/build-tools/22.0.1" />
<condition property="exe" value=".exe" else=""> <os family="windows" /> </condition>
<condition property="bat" value=".bat" else=""> <os family="windows" /> </condition>
<property name="adb" location="${android.platform.tools.dir}/adb${exe}" />
<property name="lint" location="${android.tools.dir}/lint${bat}" />
<property name="zipalign" location="${android.buildtools.dir}/zipalign${exe}" />
<property name="aidl" location="${android.platform.tools.dir}/aidl${exe}" />
<property name="aapt" location="${android.buildtools.dir}/aapt${exe}" />
<property name="dx" location="${android.buildtools.dir}/dx${bat}" />
<property name="renderscript" location="${android.buildtools.dir}/llvm-rs-cc${exe}"/>
<property name="lint" location="${android.tools.dir}/lint${bat}" />

With the help of S P's initial answer I was able to get this to work.
It is worth noting that my question, or at least the question title is misleading: At first I thought that ant was actually looking for the executable aapt inside the project folder.
However, on closer inspection it actually is looking for ${aapt}. This indicates that ant is trying to use the value of a property called "aapt", which is however not set. So instead of building any sensible executable path it just appends the name to it's current working directory - or something like that.
In any case, all I needed to to was insert the following lines into my ~/development/android-sdk-linux/tools/ant/build.xml file:
<property name="android.buildtools.dir" location="${sdk.dir}/build-tools/22.0.1" />
<property name="aapt" location="${android.buildtools.dir}/aapt" />
<property name="aidl" location="${android.buildtools.dir}/aidl" />
<property name="dx" location="${android.buildtools.dir}/dx" />
<property name="zipalign" location="${android.buildtools.dir}/zipalign" />
That's because as soon as I told ant where to find aapt it complained about aidl, dx and zipalign.

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

Debug and production resources

Some Android libraries such as Google Analytics use resources for configuration purposes (e.g. ga_trackingId).
In these cases, I have different values for debug and production. What I currently do is manually comment the production values when I'm debugging, and viceversa. It looks like this:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- DEBUG -->
<string name="ga_trackingId">UA-12345678-1</string>
<integer name="ga_dispatchPeriod">1</integer>
<bool name="ga_debug">true</bool>
<!-- PRODUCTION -->
<!--string name="ga_trackingId">UA-87654321-1</string>
<integer name="ga_dispatchPeriod">120</integer>
<bool name="ga_debug">false</bool-->
</resources>
This way of switching configuration is tedious and error-prone, and generates unnecessary repository changes if I'm not careful. Is there a better way?
(e.g.: on iOS I use conditional compilation with the IF DEBUG macro)
Under the src folder you probably have a main folder where you store all shared stuff. But you can have specific resources for flavours or build types.
Put a folder named debug under the src folder where you will place a copy of your xml file but with with proper content. You have to maintain the folder structure under debug so the global_tracker.xml needs to be placed in ../src/debug/res/xml
Your folder structure should look like this:
Android Studio will notice that this xml file have multiple versions.
This is what you should see in AS:
You can use this for all kind of resources, i.e., have multiple versions of the same file and it will be "magically" chosen properly.
I had a similar issue with Google Maps keys where they depend on the signature. What I did was to use the ant script which generates/copies resources to the project conditionally. You can include the ant script in Eclipse under the Project>Properties>Builders
If you need to use the DEBUG value in the code, you can create a java file with static values that will be included conditionally too.
Please comment if ant environment variables worked properly (you can see the "Build type: " message in console after execution of the script).
<project name="build-res">
<property name="conditional.resources.dir" value="myresources" />
<property name="keys_file" value="res/values/keys.xml" />
<target name="copy-release" if="${build.mode.release}" >
<property name="build.type" value="Release" />
<echo message="Build type: ${build.type}" />
<property name="google.maps.key" value="nanana-value-for-release" />
<copy file="${conditional.resources.dir}/Release.java" tofile="gen/com/example/project/BuildInfo.java" />
</target>
<target name="copy-debug" if="${build.mode.debug}">
<property name="build.type" value="Debug" />
<echo message="Build type: ${build.type}" />
<property name="google.maps.key" value="lalala-value-for-debug" />
<copy file="${conditional.resources.dir}/Debug.java" tofile="gen/com/example/project/BuildInfo.java" />
</target>
<target name="build-res" depends="copy-debug,copy-release">
<echo file="${keys_file}" message="<?xml version='1.0' encoding='utf-8'?><resources><string name='google_maps_key'>${google.maps.key}</string></resources>" />
</target>
</project>

Jenkins mobile air android packaging error

I've searched google and SO for solutions, but could not find any. I'm developing a mobile AIR app for android, and i use Jenkins as a local CI system. My project compiles fine, however, during the ADT packaging something goes wrong. I've copied the ADT packaging targets from the following examples:
http://blog.terrenceryan.com/using-ant-to-package-the-same-air-app-to-multiple-devices/
and
https://gist.github.com/630170
However, i am getting this output in Jenkins: http://d.pr/i/y2gJ
This is the packaging part in my build.xml file (with important property names and values used):
...
...
<property name="APP_NAME" value="Hightide"/>
<property name="ANDROID_HOME" value="${user.home}/../../../Supermaggel/SDKS/android-sdk-macosx" />
<property name="APP_DESCRIPTOR" value="${SOURCE_DIR}/${APP_NAME}-app.xml" />
<property name="SWF_FILE" value="${APP_NAME}.swf" />
<property name="OUTPUT_LOCATION_ANDROID" location="${BUILD_DIR}/android" />
<property name="OUTPUT_SWF_ANDROID" location="${OUTPUT_LOCATION_ANDROID}/${SWF_FILE}" />
<property name="OUTPUT_APK_ANDROID" value="OUTPUT_LOCATION_ANDROID/${APP_NAME}.apk" />
...
...
<!-- PACKAGE ANDROID -->
<target name="package-android">
<echo message="Packaging for Android"/>
<exec executable="${ADT}" dir="${OUTPUT_LOCATION_ANDROID}">
<arg line="-package"/>
<arg line="-target apk"/>
<arg line="-storetype pkcs12"/>
<arg line="-keystore ${KEYSTORE_ANDROID}" />
<arg line="-storepass ${STOREPASS_ANDROID}" />
<arg line="${APP_NAME}"/> <!-- output .APK -->
<arg line="${APP_DESCRIPTOR}"/> <!-- app descriptor location -->
<arg line="${OUTPUT_SWF_ANDROID}"/> <!-- output -->
</exec>
</target>
I am using Jenkins ver. 1.486, Flash Builder 4.6, AIR 3.3.
Can anyone point out what is going wrong during the packaging? any arguments missing or interpreted wrong?
I found out what caused it. The ADT cli tool gives exit code 2, which means something is wrong with the parameters... i spent hours looking at it, trying to figure out what was wrong. for ADT you need to pass in relative paths, not 'absolute' ones (or, relative from the project root.) so instead of ${PROJECT_ROOT}/packagedir/${APPNAME}.apk just use packagedir/${APPNAME}.apk or something similar, for all paths.

Android - Proguard obfuscate not able to find android classes

I am unable to run obfuscate on my android project. I keep getting a 100 errors each saying the similar thing -
[javac] /MyPath/LocationReceiver.java:34: cannot find symbol
[javac] symbol : class Intent
[javac] location: class com.myPath.LocationReceiver
[javac] public final void onHandleIntent(Intent intent) {
Where would I need to look? My build.xml file has all the correct android paths specified.
My build file -
<property name="src.dir" value="src/com"/>
<property name="build.dir" value="build"/>
<property name="classes.dir" value="${build.dir}/classes"/>
<property name="input.jar.file" value="${build.dir}/temp.jar"/>
<property name="obfuscated_sdk.jar.file" value="${build.dir}/MyName.jar"/>
<property name="proguard-home" value="/MyPath/proguard4.6" />
<property name="android-home" value="/MyPath/android-sdk" />
<property name="android-version" value="8" />
<property name="android-platform-specific" value="${android-home}/platforms/android-${android-version}" />
<property name="android-jar" value="${android-platform-specific}/android.jar" />
<target name="clean">
<delete dir="${build.dir}"/>
</target>
<target name="build-sdk" depends="clean" description="compiles the sdk java files">
<mkdir dir="${classes.dir}"/>
<javac srcdir="${src.dir}"
destdir="${classes.dir}"
source="1.6"
debuglevel="lines">
<classpath>
<path>
<pathelement location="${android-jar}" />
</path>
</classpath>
</javac>
</target>
<target name="create.input.jar" depends="build-sdk">
<jar destfile="${input.jar.file}" basedir="${classes.dir}">
<manifest>
<attribute name="MyName" value="v1.0"/>
</manifest>
</jar>
</target>
<target name="Obfuscate" depends="create.input.jar" description="shrink compiled classes">
<taskdef resource="proguard/ant/task.properties" classpath="/MyPath/proguard4.6/lib/proguard.jar" />
<proguard>
-libraryjars "/System/Library/Frameworks/JavaVM.framework/Versions/1.6.0/Classes/classes.jar"
-libraryjars "/MyPath/android-sdk/platforms/android-8/android.jar"
-injars ${input.jar.file}
-outjars ${obfuscated_sdk.jar.file}
</proguard>
<delete file="${input.jar.file}"/>
<delete dir="${classes.dir}"/>
<delete dir="bin"/>
</target>
This sounds like a classpath problem. It probably doesn't have anything to do with ProGuard, since the Android build system only invokes that when exporting a signed .apk file. Also, I believe that Eclipse uses its own build system and does not rely on build.xml.
Things to try:
Make sure that you created your project as an Android project. If not, start over again.
Right click on the project name in the package explorer and select Android Tools > Fix Project Properties.
Open the project properties, select Android and make sure you have a Project Build Target selected. Then select Java Build Path, and make sure that an Android library shows up in the Libraries pane.

ANT build for Android Proguard obfuscation

Can anyone share with sample/simple obfuscation ANT task for Android? Provided that I do have complete APK and I need just pass *class hru Proguard and then prepare *.dex to build APK
I have found solution:
Get Proguard - copy proguard.jar into known directory (say MyProject/proguard)
Prepare proguard.cfg -describing what and how optimize/obfuscate. This process thoroughly described in Proguard's manual
Prepare following ANT's build.xml (or smth like this one) - great thanx to this guy
UPDATE complete build.xml
<?xml version="1.0" encoding="UTF-8"?>
<project name="MyProject" default="zipalign" basedir=".">
<property name="target" value="android-8"/>
<!--property file="default.properties" /-->
<property name="encoding" value="UTF-8"/>
<!-- dirs -->
<property name="sdk.dir" location="Location of Android SDK"/>
<property name="proguard.dir" value="proguard" />
<property name="src.dir" value="src"/>
<property name="gen.dir" value="gen"/>
<property name="res.dir" value="res"/>
<property name="assets.dir" value="assets"/>
<property name="libs.dir" value="libs"/>
<property name="out.classes.unoptimized.dir" value="out"/>
<property name="out.classes.optimized.dir" value="out/optimized"/>
<!-- files -->
<property name="manifest.file" value="AndroidManifest.xml"/>
<property name="signed.apk" value="${ant.project.name}-signed.apk"/>
<property name="unsigned.apk" value="${ant.project.name}-unsigned.apk"/>
<property name="final.apk" value="${ant.project.name}.apk"/>
<property name="android.jar" value="${sdk.dir}/tools/platforms/${target}/android.jar"/>
<property name="unoptimized" value="unoptimized.jar" />
<property name="optimized" value="optimized.jar" />
<property name="proguard.config" value="${proguard.dir}/proguard.cfg"/>
<!-- tools -->
<property name="dx.jar" value="${sdk.dir}/platform-tools/lib/dx.jar"/>
<property name="aapt" value="${sdk.dir}/platforms/${target}/tools/aapt.exe"/>
<property name="zipalign" value="${sdk.dir}/tools/zipalign.exe"/>
<property name="jarsign" value="jarsigner.exe location is here"/>
<property name="keystore" value="Your key store is here"/>
<property name="keyalias" value="Your key alias is here"/>
<path id="android.antlibs">
<pathelement path="${sdk.dir}/tools/lib/anttasks.jar" />
<pathelement path="${sdk.dir}/tools/lib/sdklib.jar" />
<pathelement path="${sdk.dir}/tools/lib/androidprefs.jar" />
<pathelement path="${sdk.dir}/tools/lib/apkbuilder.jar" />
<pathelement path="${sdk.dir}/tools/lib/jarutils.jar" />
</path>
<taskdef name="setup"
classname="com.android.ant.SetupTask"
classpathref="android.antlibs" />
<setup import="false"/>
<!--taskdef name="aaptexec"
classname="com.android.ant.AaptExecLoopTask"
classpathref="android.antlibs" /-->
<target name="clean" description="Removes output files created by other targets.">
<echo>Cleaning...</echo>
<delete dir="${out.classes.unoptimized.dir}" verbose="true" />
<delete dir="${out.classes.optimized.dir}" verbose="true" />
</target>
<target name="dirs">
<echo>Creating output directories if needed...</echo>
<mkdir dir="${out.classes.unoptimized.dir}" />
<mkdir dir="${out.classes.optimized.dir}" />
</target>
<!-- Compiles this project's .java files into .class files. -->
<target name="compile" depends="dirs"
description="Compiles project's .java files into .class files">
<echo>Compiling sources...</echo>
<javac encoding="${encoding}" target="1.6" debug="true" extdirs=""
destdir="${out.classes.unoptimized.dir}"
bootclasspathref="android.target.classpath"
includeantruntime="true">
<src path="${src.dir}" />
<src path="${gen.dir}" />
<classpath>
<fileset dir="${libs.dir}" includes="*.jar" />
</classpath>
</javac>
</target>
<target name="preobfuscate" depends="compile">
<echo>Preparing to obfuscation...</echo>
<jar destfile="${unoptimized}"
basedir="${out.classes.unoptimized.dir}"
includes="**/**"
excludes="optimized/**"
/>
</target>
<!-- Obfuscation with ProGuard -->
<target name="optimize" unless="nooptimize" depends="preobfuscate">
<echo>Proguard obfuscation...</echo>
<java jar="${proguard.dir}/proguard.jar" fork="true" failonerror="true">
<jvmarg value="-Dmaximum.inlined.code.length=16" />
<arg value="#${proguard.dir}/proguard.cfg" />
<arg value="-injars ${unoptimized}" />
<arg value="-outjars ${optimized}" />
<arg value="-libraryjars ${android.jar}" />
</java>
<unzip src="${optimized}" dest="${out.classes.optimized.dir}" />
<!-- Delete optimized jar (now unzipped into bin directory) -->
<delete file="${optimized}"/>
<delete file="${unoptimized}"/>
</target>
<target name="dex" description="Converting JVM bytecodes into Dalvik bytecodes" depends="optimize">
<echo>Converting bytecodes to Dalvik VM bytecodes...</echo>
<java jar="${dx.jar}" fork="true">
<arg line="--dex --verbose --output=${out.classes.optimized.dir}/classes.dex ${out.classes.optimized.dir}"/>
</java>
</target>
<target name="aapt" depends="dex" description="compile resources">
<echo>Packing resources...</echo>
<exec executable="${aapt}" logerror="true" osfamily="windows">
<arg line="p
-f
-M ${manifest.file}
-I ${android.jar}
-S ${res.dir}
-A ${assets.dir}
-F ${out.classes.optimized.dir}/${unsigned.apk}
-m -J ${gen.dir}"/>
</exec>
</target>
<target name="sign" depends="aapt" description="sign apk">
<input message="Please enter keystore password (store:${keystore}):"
addproperty="keystore.password" />
<echo>Signing apk...</echo>
<exec executable="${jarsign}" logerror="true" osfamily="windows">
<arg line="-verbose
-keystore ${keystore}
-storepass ${keystore.password}
-signedjar ${out.classes.optimized.dir}/${signed.apk}
${out.classes.optimized.dir}/${unsigned.apk} ${keyalias}"/>
</exec>
</target>
<target name="zipalign" depends="sign" description="zip align">
<echo>Aligning apk...</echo>
<exec executable="${zipalign}" logerror="true" osfamily="windows">
<arg line="-f
-v
4
${out.classes.optimized.dir}/${signed.apk}
${final.apk}"/>
</exec>
</target>
</project>
This ANT task has to be added to Eclipse's builders (Properties/Builders) tasks after Java builder and before Android package builder.
Press "Build All" (it's better to off Automatic Build check in Eclipse menu)
The Android build process first compiles Java source files (.java) to Java class files (.class), then converts these class files into Dalvik code (classes.dex), and finally packages this Dalvik code in an APK file.
ProGuard reads and writes Java class files, so it has to be inserted into this pipeline between the compilation step and the conversion step. It doesn't read or write Dalvik code itself, so it can't work on the APK file.
The Android SDK documentation on ProGuard discusses how to enable the obfuscation step in the Ant build for android-9. In short, you have to add a line "proguard.config=proguard.cfg" to the file default.properties, and then run "ant release".
Attention: barmaley's reply is from year 2011, and seem to be valid for Android SDK Tools version either 8 or 10.
I tried adapting this solution using Android SDK Tools version 18.1.1, but kept failing on the error:taskdef class com.android.ant.SetupTask cannot be found
Eventually, what I did was this:
rm build.xml
android update project -p .
If you don't have the SDK Tools in your PATH, you'll need to use the full path to the android tool, for example on Windows: C:\Android\sdk\tools
This created a fresh build.xml which is compliant with the current SDK Tools, and seem to automate a lot of the manual work that is described in barmaley's reply.
After that I was able to run ant release, which took care of building and obfuscating the result .apk file out of the box.
In order to automate obfuscation via ant, you'll need to:
Enable Proguard obfuscator (obviously)
Create an ant.properties file and fill it with the appropriate key.store params (see this SO reply for details).
The proGuard obfuscation process needs .class files so you can't launch an Ant before IDE build (.java) or after (.dex packed).
Have a look on this post where it's explained how add the proGuard step in your global Ant build:
http://www.androidengineer.com/2010/07/optimizing-obfuscating-and-shrinking.html
If you really want to use the IDEA build, you can try the following.
After the IDEA build unpack the apk with apktool.
Convert the .dex files to .class with dex2jar
Run proGuard as the previous post show you
Sorry that I don't attach you the links of apktool and dexjar but as I'm newbie I can't post more than one hyperlink.

Categories

Resources