Passing properties to Android library project build file - android

I have an Android app project that is split into a free and a paid version. Everything that is common to both projects resides in an Android library project called "core". Then I have actual Android app projects for both the paid and the free version.
I'm using Ant scripts for building these two APKs. The paid version sets a property that tells the "core" project that the paid version is building. The free version tells the core project that the free version is building.
That used to work perfectly fine until Google decided to release ADT 22. Now the "core" project doesn't pick up these build properties anymore.
I suspect that library projects are built in a separate Ant build environment / process now.
So here's my question: how do I define properties for referenced Android library projects within an app project's build.xml file? How to pass over properties to these library project builds?
And where in the SDK's build.xml file are library projects actually compiled? I guess that would be the right spot to look into.
Thanks for your time.

EDIT for clarification
You have to create a modified copy of the original build.xml file from the Android SDK (see SDK-Folder/tools/ant) and also keep it up to date every now and again when Google releases an ADT update by merging the differences (and keeping the own modifications of course).
The build.xml file builds library projects using a <subant> task, which basically starts a separate build environment that does not automatically see any properties of the calling scope (which would be the app project's build environment).
However, within that subant tag you can export properties of the caller's scope to the library's build XML using a <propertyset> tag. Look for the following code block in your copy of build.xml and make a modification as shown below:
....
<echo level="info">Building Libraries with '${project.libraries.target}'...</echo>
<!-- no need to build the deps as we have already
the full list of libraries -->
<subant failonerror="true" buildpathref="project.library.folder.path" antfile="build.xml">
<!-- *** ADD THIS: *** -->
<propertyset id="project.library.buildargs">
<propertyref prefix="project.library.buildargs" />
</propertyset>
<target name="nodeps" />
<target name="${project.libraries.target}" />
<property name="emma.coverage.absolute.file" location="${out.absolute.dir}/coverage.em" />
</subant>
....
Above example makes all app project build.xml properties that are prefixed with project.library.buildargs. visible to all referenced Android library build scripts.

An alternative solution I have found to provide different values for my free version vs my paid version is to use [resources]. The Android build chain allows application projects to override the resource values set in the shared library project.
So for example, you can have a boolean resource in any XML file in res/values:
<bool name="paid_version">false</bool>
Of course, the paid version has the same resource in its own res/values subdirectory with a value of true.
Then from an Activity subclass or any other class with a Context, you can do the following:
if (getResources().getBoolean(R.id.paid_version)) {
// Do the paid version code here
}
This has the advantage that it is fairly easy to implement. On the down side, this is a run-time check based on dynamic code. This means that the code cannot be optimized away by the compiler or any other static analysis tool when the resource value is set to false.

Related

Where does gradle store all compiled classes for an ANDROID project?

Migrating from eclipse to Android Studio. Here is AS's build dir structure
Question 1. Where does gradle put all the compiled .class files? Is it the projectRoot/build/intermediates/classes directory?
The purpose of this question is a Java class is generated at build time (eg: CustomBuildInfo.java) and needs to added to the complied dir so that other src files can use it and packaged correctly within APK.
Note:Previously in Eclipse this generated file use to reside inside projectRoot/gen/<package> directory.
Question 2. Whats the correct location for custom generated Java files? Is it build/generated/r/<buildType>/<package> ? (this is where R.java resides)
Note But this custom generated Java file CustomBuildInfo.java belongs to common source i.e., used by all build types and all flavors
Any help will be appreciated.
To answer my own question when using GRADLE build system
Java Byte Code location (post-compilation) <projectroot>/build/intermediates/classes/<build-type>/....
assets
<projectroot>/build/intermediates/assets/<build-type>/....
res
<projectroot>/build/intermediates/res/merged/<build-type>/....
JNI libs (configurable)
<projectroot>/build/intermediates/jniLibs/<build-type>/....
Manifests
<projectroot>/build/intermediates/manifests/full/<build-type>/....
Java class generated from AIDL
<projectroot>/build/generated/source/aidl/<build-type>/....
R.java
<projectroot>/build/generated/source/r/<build-type>/....
BuildConfig.java
<projectroot>/build/generated/source/buildConfig/<build-type>/....
Test reports HTML
<projectroot>/build/reports/tests/<build-type>/index.html
APK output files
<projectroot>/build/outputs/apk/...
Lint Results
<projectroot>/build/outputs/...
Manifest Merger Report (if using multi-module build)
<projectroot>/build/outputs/logs/...
Test Results
<projectroot>/build/test-results/...
Intermediate classes can sometimes be stored at "../build/intermediates/javac/debug/compileDebugJavaWithJavac/classes" for the debug build classes and at "../build/intermediates/javac/relese/compileReleaseJavaWithJavac/classes" for the release build classes. And sometimes they can be stored at "../build/debug" for debug classes and at "../build/release" for release build classes.
I'm not sure what causes them to be in one place or the other. If you look at the ".impl" file (which contains xml) for the module your interested in you will find an entry like this:
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_7">
<output url="file://$MODULE_DIR$/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes" />
or an enty like this:
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_7">
<output url="file://$MODULE_DIR$/build/intermediates/classes/debug" />
That's what determines where the intermediate classes will be stored for the module. Why it's sometimes in the 'build/intermediate/classes' directory and sometimes in the 'build/intermediate/java' directory has me baffled. I've look for various reasons such as 1.) is it affected by the manisfest, 2.) manifest merging 3.) jdk version 4.) module type (application, android library, java library), 5.) use of instance run. In all my attempts to see what causes it to choice one or the other, I've not been able to determine how that decision is made. If someone knows what factor determines the directory scheme choice , please add the reason.
If you're like me and have a reason want to get access to the intermediate java classes produced, the easiest work around is to see which directory exist. You'll have one or the other, but not both!

Android library project custom Ant build

I have a library project that serves as the backend for a number of other projects. It does the web connection and parsing etc. Then I have other front end projects that build on this.
For development and server environments I wrote an ANT build script that replaces certain values in the code bases on the build type.
So I have two targets buildDev and buildProd.
Is there a way for me to have the values set correctly while building the dependent (non-library projects). E.g. if I do ant debug on the project it builds the backend with ant buildDev and if I do ant release it does it with ant buildProd.
I'm pretty sure that's not possible, so what are the alternatives.
For the curious, the custom builds just replaces a file that has static variables that are assigned different values based on the type of build. Nothing too complex.
In ant, there are a variety of different tasks that can be used to edit properties in a file.
I'm sure you're aware of property files, so if you use the documentation here:
http://ant.apache.org/manual/index.html
It could probably help you.
If you set your variables in an ant-style property file, then for certain builds you could have separate files for separate builds, and then therefore have the variables set correctly.
If you're talking about having variables set in your source, try the copy task:
http://ant.apache.org/manual/index.html
Filterchains on a copy task will allow you to replace certain lines of code out of a file. So if you have a variable named server_ip or something like that, you can use a filterchain to change that value and re-copy that source file back into your tree.
I hope this answers your questions. If not, be gentle. I'm kinda new at answering stuff and I got slightly chewed out on an Android post haha.
I found the solution. The default Android Ant build.xml passes the release name to the child library project script while calling it. The following lines and the code that follows details it.
<!-- figure out which target must be used to build the library projects.
If emma is enabled, then use 'instrument' otherwise, use 'debug' -->
<condition property="project.libraries.target" value="instrument" else="${build.target}">
<istrue value="${build.is.instrumented}" />
</condition>
Then it's just a matter of having the same targets in all the interdependent projects.

Building an android project referencing android library project using ant / teamcity

I got a android project say project A ..now this project project A depends on a Android lib project say LibX. Now LibX depends on another android library project LibY. How can I build my project using ant.
Here is the android documentation I am referencing to -
http://developer.android.com/guide/developing/projects/projects-cmdline.html
Here's what it says
At build time, the libraries are merged with the application one at a time, starting from the lowest priority to the highest. Note that a library cannot itself reference another library and that, at build time, libraries are not merged with each other before being merged with the application.
Is there a way around this?
by Android Developer site: source in http://developer.android.com/tools/projects/index.html , section at Library Projects:
"... Structurally, a library project is similar to a standard Android
application project. For example, it includes a manifest file at the
project root, as well as src/, res/ and similar directories. The
project can contain the same types of source code and resources as a
standard Android project, stored in the same way. For example, source
code in the library project can access its own resources through its R
class.
However, a library project differs from a standard Android application
project in that you cannot compile it directly to its own .apk and run
it on an Android device. Similarly, you cannot export the library
project to a self-contained JAR file, as you would do for a true
library. Instead, you must compile the library indirectly, by
referencing the library in the dependent application and building that
application.
When you build an application that depends on a library project, the
SDK tools compile the library into a temporary JAR file and uses it in
the main project, then uses the result to generate the .apk. In cases
where a resource ID is defined in both the application and the
library, the tools ensure that the resource declared in the
application gets priority and that the resource in the library project
is not compiled into the application .apk. This gives your application
the flexibility to either use or redefine any resource behaviors or
values that are defined in any library.
To organize your code further, your application can add references to
multiple library projects, then specify the relative priority of the
resources in each library. This lets you build up the resources
actually used in your application in a cumulative manner. When two
libraries referenced from an application define the same resource ID,
the tools select the resource from the library with higher priority
and discard the other.
Once you have added references to library projects to your Android
project, you can set their relative priority. At build time, the
libraries are merged with the application one at a time, starting from
the lowest priority to the highest.
Library projects can reference other library projects and can import
an external library (JAR) in the normal way. ..."
I went through a similar problem when using the library Rajawali (version 0.9). There was a need to distribute a file. Single jar and applications would use this JAR to display 3D screens. The problem was that our library was a customization that used library resources Rajawali. So two project structures were created (such as library project). When generating. JAR application that used the resources did not work for the reasons you explain above), this because the library uses Rajawali features of images to be loaded with IDs that were not recognized in the version of the target application.
The solution of the single JAR can be validated by modifying the code to not use the Rajawali resources via R.raw.X (Android approach) to go to use the folder assets / , and make the component use Rajawali AsseptManager to open resources. The solution was exported JAR folder with the internal assets / and the bytecode (. Class) and our LIB Rajawali.
By Fat-JAR Eclipse PlugIn (or 0.0.31 +) [update site http://kuruczgrafika.de/fatjar] could generate a single JAR and use it in the target application. The ANT script was used to run the XML below and a JAR file was generated. The file "lib3d_NAME_HERE.jar" (.JAR) will be generated in the /build/lib3d_NAME_HERE.jar
<?xml version="1.0"?>
<project name="lib3d_NAME_HERE" default="main" basedir=".">
<property name="projectPath" value="D:\Development\lib3d_NAME_HERE"/>
<!-- this file was created by Fat-Jar Eclipse Plug-in -->
<!-- the ANT-Export is in a very early stage, so this -->
<!-- is only experimental, ANT 1.6 or above is -->
<!-- required, feedback is always welcome: -->
<!-- http://sourceforge.net/projects/fjep -->
<!-- uncomment the following lines if using ANT outside Eclipse -->
<!--
<property name="fjepPath" value="reference:file:plugins/net.sf.fjep.fatjar_0.0.31/fatjar.jar"/>
<taskdef name="fatjar.build" classname="net.sf.fjep.anttask.FJBuildTask" classpath="${fjepPath}"/>
<typedef name="fatjar.manifest" classname="net.sf.fjep.anttask.FJManifestType" classpath="${fjepPath}"/>
<typedef name="fatjar.exclude" classname="net.sf.fjep.anttask.FJExcludeType" classpath="${fjepPath}"/>
<typedef name="fatjar.jarsource" classname="net.sf.fjep.anttask.FJJarSourceType" classpath="${fjepPath}"/>
<typedef name="fatjar.filesource" classname="net.sf.fjep.anttask.FJFileSourceType" classpath="${fjepPath}"/>
-->
<!-- uncomment the above lines to use ANT outside of Eclipse -->
<target name="main">
<fatjar.build output="build/lib3d_NAME_HERE.jar">
<fatjar.manifest/>
<fatjar.filesource path="${projectPath}/bin/classes" relpath=""/>
<fatjar.filesource path="${projectPath}/assets/" relpath="assets"/>
</fatjar.build>
</target>
</project>

How to filter files in the generated test coverage report by EMMA, using Ant in Android

I have an Android project and I am correctly generating test coverage reports using Ant and EMMA (I did it by following the instructions here: https://wiki.jenkins-ci.org/display/JENKINS/Building+an+Android+app+and+test+project)
What I would like to know is how can I filter the files that appear in the report generated by EMMA (for example, the R generated classes, files in an already tested library...).
I included both ${sdk.dir}/tools/ant/test_rules.xml and ${sdk.dir}/tools/ant/main_rules.xml in my own build.xml file and there I tried to change the "-emma-instrument" target to look like that:
<target name="-emma-instrument" depends="compile">
<echo>Instrumenting classes from ${out.absolute.dir}/classes...</echo>
<!-- It only instruments class files, not any external libs -->
<emma enabled="true">
<instr verbosity="${verbosity}"
mode="overwrite"
instrpath="${out.absolute.dir}/classes"
outdir="${out.absolute.dir}/classes">
<filter excludes="*R*" />
</instr>
<!-- TODO: exclusion filters on R*.class and allowing custom exclusion from
user defined file -->
</emma>
</target>
I also tried to apply another variations of EMMA coverage filters specified here http://emma.sourceforge.net/reference_single/reference.html#instrset.filters, but that does not work either, and the R generated files still appear in the coverage report.
Anybody knows how to solve this?
Update: Filtering is built in as of revision r18 of the android SDK, just see my answer to the linked question.
There is another question asking for this, where you've been already the half way down the road. To solve your issue just make sure, that you do not modify the test projects build file, but the one of the target project. I've got really no clue what kind of ant magic is involved in the android app build files, but of course to some extend your target projects build file must play an important role, so it's kinda logical that you've got to specify the coverage modification within the target project.
It took me the whole morning to sort this thing out, so I hope it's of some value for other developers.
As a side note, this functionality should be built-in as of revision 16 of the SDK tools.

How to create multiple Android apps from one code base

I have an Android code base which uses APIs with settings to get different data for several apps. All apps use the same code base but with one or two design tweaks. So how do I re-use the main code base without having to copy the whole Android project each time?
iPhone uses multiple targets in the same project which works well. If android cant do this do I need to compile binaries of the code base in one project and then import into each new app project? If so how? I'm using Eclipse and am an intermediate Java developer.
Any help much appreciated!
Doug
Check out "Working With Library Projects" from the Android documentation. This should be just what you're looking for: http://developer.android.com/tools/projects/projects-eclipse.html#SettingUpLibraryProject
The current way to approach this issue if you are using Android Studio with Gradle is by using Gradle, Build Type + Product Flavor
http://tools.android.com/tech-docs/new-build-system/user-guide#TOC-Build-Variants
Build Variants
One goal of the new build system is to enable creating different versions of the same application.
There are two main use cases:
Different versions of the same application
For instance, a free/demo version vs the “pro” paid application.
Same application packaged differently for multi-apk in Google Play Store.
This new concept is designed to help when the differences are very minimum. If the answer to “Is this the same application?” is yes, then this is probably the way to go over Library Projects.
Note: This answer is basically obsolete now that one can create .aar libraries with resources. It still works, though, and there may be times when the portability of a .jar is desirable, so I'm leaving it here.
Blumer's answer is a good one, and you should definitely look into Android's idea of library projects. However, there is another alternative. If you have a module that contains only Java code, but no resources of any kind (images, layouts, etc.), you can compile it to a .jar file separately and use the resulting .jar in multiple application projects. It works like this:
Create a new Java project in Eclipse (not an Android project) and move the source code of your module there.
If your module references any classes from the SDK, you'll need to add the Android SDK .jar to the project's classpath (Project > Properties > Java Build Path > Libraries > Add JAR).
When your module is ready to use, bundle up its .class files into a .jar. You can do this manually, or you can look around to figure out how to get Eclipse to do it for you.
Copy your module .jar file into the "libs" directory of your app's main project.
Add the module .jar to the project's classpath (again, Project > Properties > Java Build Path > Libraries > Add JAR).
Now you should be able to build multiple apps using the same .jar, while maintaining only one copy of the module's source code.
Depending on your particular situation, this may or may not work any better for you than the standard Android library mechanism. But it's worth considering as an alternative.
The Android documentation recommends another approach if there aren't too many "different APIs" used.
The idea is to use reflection instead of making direction references to the code. Make sure to use optimized reflection instead of lookups every time.
References
http://developer.android.com/training/multiple-apks/api.html
http://developer.android.com/google/play/publishing/multiple-apks.html#ApiLevelOptions
You might want to consider using a source control system like Subversion (or GIT). Keep your most feature complete version in the trunk, and make branches for your separate versions that use different data sources or require minor layout changes, etc.

Categories

Resources