20

Is there any way to add custom attributes to productFlavor or buildType in android plugin for gradle? I'd like to have such additional flexibility in configuration of buildVariants, so that I can check my custom property when specifying tasks for buildVariants.

productFlavors {
    flavorGroups "drm", "storeType"
    googlePlay {
        flavorGroup "storeType"
        buildConfig "public static final String TARGET_STORE = \"google\";"
    }
    samsungApps {
        flavorGroup "storeType"
        buildConfig "public static final String TARGET_STORE = \"samsung\";"
    }

    platformDrm {
        flavorGroup "drm"
    }

    widevineAppDrm {
        flavorGroup "drm"
        minSdkVersion 9
        useWidevineAppDrmLib true
    }

}

so here you can see I've added custom attribute "useWidevineAppDrmLib" to build flavor. It would be nice to see the same attribute in buildVariant.mergedFlavor, so that I can check that attribute value and do build additional tasks, such as package additional .so files when the attribute is set to true:

android.applicationVariants.each { variant -> if(variant.mergedFlavor.useWidevineAppDrmLib ) { ... // add copy .so task } }

maybe there is a way to do that already but I didn't find out yet... checking build variant name for substring (flavor name) works for me, but it looks dirty.

Ideally I'd like to have a map of custom attributes of different types for buildType and productFlavor.

blackdigger
  • 289
  • 4
  • 9

2 Answers2

21

You can extend an object to add a property dynamically. So you could do it on flavor object when they get added, using something like this:

// First declare a class that holds a boolean
class BooleanExtension {
  boolean value
  BooleanExtension(boolean value) {
    this.value = value
  }

  public void setValue(boolean value) {
    this.value = value
  }

  public boolean getValue() {
    return value
  }
}

android {
  // add the boolean extension to all flavor object when they are created.
  productFlavors.whenObjectAdded { flavor ->
    flavor.extensions.create("useWidevineAppDrmLib", BooleanExtension, false)
  }

  // then we can set the value on the extension of any flavor object
  productFlavors {
    widevineAppDrm {
      useWidevineAppDrmLib.value true
    }
  }
}

However this won't get passed to the merged flavor. So you'd have to do

android.applicationVariants.each { variant ->
  if (variant.productFlavors.get(0).useWidevineAppDrmLib.value) {
    ...
  }
}

Edited to make the code actually work from @blackdigger's feedback.

Xavier Ducrohet
  • 28,383
  • 5
  • 88
  • 64
  • 1
    I managed to do it the following way: define extension class above "android" section - otherwise it gives compile error: class BooleanExtension { Boolean value BooleanExtension(Boolean value) { this.value = value } public void setValue(Boolean value) { this.value = value } public Boolean getValue() { return value } } then write: widevineAppDrm { ... useWidevineAppDrmLib.value true ... } ....and: if (variant.productFlavors.get(0).useWidevineAppDrmLib.value) {...} – blackdigger Jul 18 '13 at 09:48
  • 1
    and one more thing, to add flavor extension I had to do: productFlavors.whenObjectAdded { flavor -> flavor.extensions.create("useWidevineAppDrmLib", BooleanExtension, false) } – blackdigger Jul 18 '13 at 10:10
  • 1
    You might want to have your BooleanExtension use boolean instead of Boolean – Xavier Ducrohet Jul 18 '13 at 17:40
  • @XavierDucrohet thanks for this helpful answer! I was wondering: Is there some API documentation regarding product flavors? Because I'd love to see the documentation for the flavor.extensions.create Method in order to figure out what that "false" at the end is for : ) . Because I am creating a StringProperty, so I'd like to figure out, if that "false" is a default value for the BooleanProperty or something else. – AgentKnopf Feb 02 '15 at 08:58
  • @XavierDucrohet I am also not quite clear about the purpose of the last snippet: android.applicationVariants.each { variant -> if (variant.productFlavors.get(0).useWidevineAppDrmLib.value) { ... } } ? And about what you are supposed to do in that if-clause? And does productFlavors.get(0) return the product flavor googlePlay? Or which flavors are stored in that productFlavors property/object? – AgentKnopf Feb 02 '15 at 09:06
17

There's an alternative solution which doesn't require the creation of your own custom class. You can utilize the already existing extras property which is already attached to the 'productFlavors' class. This was specifically designed to allow custom user defined variables.

android {
  // We can add any custom variable so long as it's prefaced with ext
  productFlavors {
    widevineAppDrm {
      ext.useWidevineAppDrmLib = true
    }
  }
}

Then you can later reference like so. Note, if you didn't add the custom variable to other productFlavors you'll need to be sure to check for it first, else gradle will complain about not finding the property.

android.applicationVariants.each { variant ->
    if (variant.productFlavors[0].ext.has("useWidevineAppDrmLib")) {
        if (variant.productFlavors.get(0).ext.useWidevineAppDrmLib) {
            ...
        }
    }
}
ATom
  • 15,960
  • 6
  • 46
  • 50
Ifrit
  • 6,791
  • 8
  • 50
  • 79