Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Gradle swap jniLibs resources based on build flavor

I am trying to swap some resources in the res/raw folder and the jniLibs/armeabi folder based on whether its a release buildType or a debug buildType. I currently have two product flavors as well.

The build.gradle file:

apply plugin: 'com.android.application'

android {
    dexOptions {
        preDexLibraries = false
    }

    compileSdkVersion 21
    buildToolsVersion "22.0.1"

    defaultConfig {
        applicationId "com.example.test"
        minSdkVersion 17
        targetSdkVersion 22
        compileOptions {
            sourceCompatibility JavaVersion.VERSION_1_7
            targetCompatibility JavaVersion.VERSION_1_7
        }
    }

    productFlavors{
        phone{
            applicationId "com.example.testPhone"
        }
        tablet{
            applicationId "com.example.testTablet"
        }
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
        }
    }

    sourceSets{
        release{
            res.srcDirs = ['androidRelease/res/raw']
        }
    }
}

dependencies {
    compile project(':facebook')

}

Is using sourceSet the right way to do so? If it is, what folder should be created so that it swaps the appropriate resources based on the buildType only and irrespective of the productFlavors?

EDIT: Is it even possible to swap jniLibs and raw folder resources?

Folder Structure:

src/main/jniLibs/armeabi
phoneRelease/jniLibs/armeabi
tabletRelease/jniLibs/armeabi 

Is the folder structure correct.?

EDIT 2: Based on Xavier's answer should the gradle look like this:

android {

      sourcesets {
        phone {
          jniLibs.srcDirs = ['phoneRelease/jniLibs/']
          res.srcDirs = ['androidRelease/res/raw']
        }
        tablet {
          jniLibs.srcDirs = ['tabletRelease/jniLibs/']
          res.srcDirs = ['androidRelease/res/raw']
        }
      }
    }

I keep reading lot of conflicting answers, some of them mention that you just need separate folders based on build variant and some mention about having to use sourceSet? Thanks!

like image 348
user2511882 Avatar asked Jul 28 '15 21:07

user2511882


People also ask

Can I create a new source set in Gradle?

However, you can create new source sets to control exactly what files Gradle compiles and packages for specific build types, product flavors (and combinations of product flavors when using flavor dimensions ), and build variants.

What is a Gradle build variant?

Build variants are the result of Gradle using a specific set of rules to combine settings, code, and resources configured in your build types and product flavors. Although you do not configure build variants directly, you do configure the build types and product flavors that form them.

How do I create multiple flavors in Gradle?

To do this, the Android plugin for Gradle allows you to create multiple groups of product flavors as flavor dimensions. When building your app, Gradle combines a product flavor configuration from each flavor dimension you define, along with a build type configuration, to create the final build variant.

What is productflavours in Gradle?

Till Gradle introduced ProductFlavours we were only able to build application with the a single configuration or default configuration. Since the introduction of ProductFlavours, we are able to create variables based on build types.


2 Answers

some of them mention that you just need separate folders based on build variant and some mention about having to use sourceSet?

Gradle/Gradle for Android has an expected structure for a sourceset:

  • Android resources in res/
  • Java source tree in java/
  • Pre-compiled JNI libraries in jniLibs/
  • Assets in assets/
  • Etc.

Where the sourceSets closure comes into play is if, for a given sourceset, you want a different structure:

  • Android resources in foo/
  • Java source tree in bar/
  • Pre-compiled JNI libraries in ickyNativeStuff/
  • Assets in assetsBecauseThatSeemsLikeADecentName/
  • Etc.

Each build type, product flavor, and build variant can have a separate sourceset (as can androidTest for instrumentation testing), to go along with main. They are named the same as the build type/product flavor/build variant. These will be in the stock structure, unless you use sourceSets to change things.

So, to roll all the way back to:

I am trying to swap some resources in the res/raw folder and the jniLibs/armeabi folder based on whether its a release buildType or a debug buildType

In the case of resources, other sourcesets overlay main. So, if you have src/main/res/... and src/main/debug/... and src/main/release/..., and you are doing a debug build, whatever is in src/main/release/... is ignored (as we aren't doing release) and whatever is in src/main/res/... and src/main/debug/... will be used. If there is the same resource in both (src/main/res/raw/boom.ogg and src/debug/res/raw/boom.ogg), the debug one trumps the main one.

I have not experimented with varying jniLibs/ by build variant. My guess is that it will behave more like Java code, where you cannot have conflicts between what is in a build variant's sourceset and what is in main, but that's just a guess. So, you can have the debug version of your compiled JNI code in src/debug/jniLibs/ and the release version of your compiled JNI code in src/release/jniLibs/. Only have in src/main/jniLibs/ any libraries that are not varying. That being said, as I mentioned, I haven't tried this, and so there may be hiccups here.

So, I would expect you to not have a sourcesets closure in build.gradle, and to just use the stock sourcesets structure, for your various bits:

src/
  main/
    ...
  debug/
    jniLibs/
    res/
      raw/
  release
    jniLibs/
    res/
      raw/
like image 151
CommonsWare Avatar answered Sep 18 '22 11:09

CommonsWare


Anything that's normally under src/main/ can be put in a different folder:

src/<element>/AndroidManifest.xml
src/<element>/java
src/<element>/res
src/<element>/assets
src/<element>/resources
src/<element>/jni
src/<element>/jniLibs
src/<element>/aidl
src/<element>/rs

Where element is the name of a build type or a product flavor. If your variant includes such a element (build type or flavor), then that source set is also used in addition to src/main

Note that the location is really not relevant if you have configured it. What matters is that there is a android.sourcesets.main element that contains the sources common to all variants, and each variant has a set of sourcesets.

For instance if you have a flavor phoneRelease it's really using the following sourcesets:

android.sourcesets.main
android.sourcesets.phone
android.sourcesets.release
android.sourcesets.phoneRelease

If you have another variant tabletRelease, it'll use the following:

android.sourcesets.main
android.sourcesets.tablet
android.sourcesets.release
android.sourcesets.phoneRelease

So the phone/tablet sourceset is different and is where you'd put the variant specific sources, unless you want to be even more specific and use the phoneRelease/tabletRelease sourcesets (though those are less used generally.) By default these would be src/phone/... and src/tablet/... (or src/phoneRelease/...) but you can change that however you want and as long as it's connected to the android.sourcesets.* objects it'll be fine.

for example, doing:

android {
  sourcesets {
    phone {
      jniLibs.srcDirs = ['phoneRelease/jniLibs/']
    }
    tablet {
      jniLibs.srcDirs = ['tabletRelease/jniLibs/']
    }
  }
}

is fine. But do be aware that you only changed the jniLibs folder and not the other source elements (java, res, etc...)

If you kept the default location for the main sourcesets, I'd just keep everything under src/

You can see more info about sourcesets and how multiple sourcesets are combined here: http://tools.android.com/tech-docs/new-build-system/user-guide#TOC-Sourcesets-and-Dependencies

like image 39
Xavier Ducrohet Avatar answered Sep 20 '22 11:09

Xavier Ducrohet