Shark
Shark

Reputation: 6620

How to make Gradle accomplish a simple makefile thing

my situation is this: i have a project, which uses some generated code. In the generated code, a certain URI is hardcoded in pretty much all files.

So, at some point i got to two generated codebases: one targeting DEVELOPMENT, another targeting STAGING.

I want to solve that via Gradle just as I would via Makefiles.

So, at first i made a new Module in the root of my project named SOAP-DEV and SOAP-STAGE, defined two new variables in gradle.properties called

# Make sure only one of these is set to 'true' and *do* set the other one to 'false'. Please.
USE_STAGING_SOAP=
USE_DEVELOPMENT_SOAP=1

I ended up using 1 and blank, because true and false didn't seem to do the trick and both counted as true.

So, once the building issue was done with and only one of them seemed to be building (both actually, but I was getting only one using <dev/stage> soap pack line, i think that was actually ok and that the proper one was being built.

then I hit another roadblock - it seems my project's main module - app can't see files outside it's folder, which makes sense.

Now I'm trying with a different approach - to have SOAP-STAGE and SOAP-DEV be subfolders of ProjectName/app instead of ProjectName so the #import line can actually see the sources it needs to see to build properly.

Yet, that's not happening :/

What is the proper way of setting a configurable choice of which folder to build for only a part of the project's codebase, but so that they are seen by the project's #import in the classes?

I would gladly revert to the old idea of having both SOAP folders as modules in my project, if I could get the classes inside the project to see the related-module's classes, namely the soap classes.

To better illustrate what I'm trying to do, here's my main module's gradle.build file. I hope you'll understand what I'm trying to do with this.

import java.text.SimpleDateFormat

apply plugin: 'com.android.application'

android {
    signingConfigs {
        hockeyApp {
            keyAlias 'myKeyAlias'
            keyPassword 'myKeyAliasHA'
            storeFile file('../myKeystore.jks')
            storePassword 'myKeyAliasHA'
        }
    }
    compileSdkVersion 21
    buildToolsVersion "21.1.2"
    defaultConfig {
        applicationId "com.my.application"
        minSdkVersion 15
        targetSdkVersion 21
        versionCode 1
        versionName getVersion()
    }
    buildTypes {
        hockeyApp {
            signingConfig signingConfigs.hockeyApp
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }

    android.enforceUniquePackageName=false
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    compile 'com.android.support:appcompat-v7:22.0.0'
    compile 'com.facebook.android:facebook-android-sdk:4.0.0'
    compile 'com.google.android.gms:play-services:7.0.0'
    compile 'com.android.support:recyclerview-v7:21.0.0'
    compile 'com.daimajia.swipelayout:library:1.1.9@aar'
    compile files('libs/dpdsoaplib.jar')
    compile project (':androidNeoReaderSDK')

    if(USE_STAGING_SOAP == 1)
    {
        compile {
            source = 'SOAP-STAGE/src/main/java'
        }
    }
    if(USE_DEVELOPMENT_SOAP == 1)
    {
        compile {
            source = 'SOAP-DEV/src/main/java'
        }
    }
    compile "com.android.support:support-v4:21.0.+"
    compile 'com.google.maps.android:android-maps-utils:0.3+'
}

def getVersion() {
    def Calendar cal = Calendar.getInstance();
    def SimpleDateFormat dateFormat = new SimpleDateFormat("MMddHHmmss");

    def StringBuilder sb = new StringBuilder("v");
    sb.append("0.2");
    sb.append(".");
    sb.append(dateFormat.format(cal.getTimeInMillis()));
    sb.append("a");

    return sb.toString();

}

However, if I can actually get both of these folders (SOAP-DEV and SOAP-STAGE) to be added as source folders to the project/module, I think that would resolve the problem of not being able to import proper classes, which was only caused by the classes being moved from the ProjectName/app/src/java folder, to the ProjectName/SOAP-DEV/src/java and ProjectName/SOAP-STAGE/src/java folders.

The two folders do have identical packagenames and contain classes of the same name which only point to a different soap server.

So, people, any ideas? I thought this Gradle was supposed to introduce some build system / makefile functionalities to android studio, but so far it does not seem to be the case.

Right now i'm trying something in between - to have both folders as Modules in the root of the project but also have one or the other's code visible in my app module's import statements.

Upvotes: 3

Views: 2473

Answers (2)

Shark
Shark

Reputation: 6620

So, the answer (in the end) came down to this:

The structure was altered a bit, and two new subfolders were added at the "main module" (main module = app) level.

ProjectRoot/app/src/main/my/package/name/...
ProjectRoot/app/src/soap_dev/my/package/name/...
ProjectRoot/app/src/soap_stage/my/package/name/...

Then, the generated code got moved from

ProjectRoot/app/src/main/my/package/name/backend/soap/generated

to

ProjectRoot/app/src/SOAP_DEV_/my/package/name/backend/soap/generated
ProjectRoot/app/src/SOAP_STAGE_/my/package/name/backend/soap/generated

Two new build flavors were made in the module "app"

   productFlavors {
       SOAP_DEV_ {
       }
       SOAP_STAGE_ {
       }
    }

And that resulted in the flavors applying to all current build configurations available to the project.

Upvotes: 0

ben75
ben75

Reputation: 28706

Your initial idea of having 2 modules in your root directory with both version of your generated code is a good start. Now, using a variable to dynamically changing the content of your app is not supported by gradle.

The philosophy behind this limitation is that it MUST be possible to evaluate the need of executing a gradle task simply by looking at it's inputs and outputs. (i.e. input didn't change ==> no need to re-execute the task).

Fortunately, gradle offers alternative ways of writing flexible builds:

You can use flavors (i.e. variations of the same product).

Define 2 flavors :

android {
    ...
    productFlavors {
       dev{}
       staging{}
    }
}


dependencies {
    devCompile project(':SOAP-DEV')
    stagingCompile project(':SOAP-STAGE')
    ...
}

Note that the prefix in dependencies is exactly the name of the flavors.

This will produce 2 apks : MyApp-dev.apk and MyApp-staging.apk

Upvotes: 1

Related Questions