4
votes

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.

2
Can you describe what these properties are for? Perhaps there is an alternative solution...(p.s. I feel your pain. I have been struggling with the exact same situation trying to build two versions of an app without duplicating too much code.) - Code-Apprentice
@Code-Guru I agree, it's painful. And I remember having struggled with that half a year ago and every time when ADT gets a major update you have to rework that build script. To answer your question: these properties are used to create a dynamically generated Java class file with static boolean flags. These flags are used for switching on / off code portions in the core project. These two flags are "IS_PAID_VERSION" for activating the licensing validation code and the other one "IS_DEBUG" for activating very verbose logging. - tiguchi
I have got the same problem, any recent solution? - nish1013
@nish1013 I edited my answer below to make it a little clearer how to solve that problem. - tiguchi

2 Answers

3
votes

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.

1
votes

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.