How to have two build flavors inherit from a root flavor in Android Studio?

后端 未结 1 1248
无人及你
无人及你 2020-12-09 04:21

I used to have the following project flavors:

  1. Apple
  2. Orange

Originally the only difference was the applicationId/packageName

相关标签:
1条回答
  • 2020-12-09 05:16

    There are many possible solutions to your problem. The most native-Gradle solution would be to use Flavor Dimensions, as documented in http://tools.android.com/tech-docs/new-build-system/user-guide#TOC-Multi-flavor-variants

    This is also similar to what you were thinking about with Solution 2.

    It would work something like this:

    flavorDimensions 'fruit', 'paid'
    
    productFlavors {
        apple {
            dimension 'fruit'
        }
        orange {
            dimension 'fruit'
        }
        free {
            dimension 'paid'
        }
        premium {
            dimension 'paid'
        }
    }
    

    This will give you build variants (and source folders) where it does the combination of all possibilities out of each flavor dimension, maintaining the same order as how the groups are specified in your flavorDimensions statement (i.e. it's appleFree, not freeApple), thus:

    * appleFree
    * applePremium
    * orangeFree
    * orangePremium
    

    in your src/ folder, you can have these possibilities:

    * src/main
    * src/apple
    * src/orange
    * src/free
    * src/premium
    * src/appleFree
    * src/applePremium
    * src/orangeFree
    * src/orangePremium
    

    Solution 3

    You can use the buildConfigField to specify constants that go in the BuildConfig class on a flavor-by-flavor basis:

    productFlavors {
        appleFree {
            buildConfigField 'String', 'MY_URL', 'value1'
        }
        applePremium {
            buildConfigField 'String', 'MY_URL', 'value2'
        }
        orangeFree {
            buildConfigField 'String', 'MY_URL', 'value3'
        }
        orangePremium {
            buildConfigField 'String', 'MY_URL', 'value4'
        }
    

    Solution 1

    I was trying to work up something along the lines of Solution 1, but it won't work well for your exact use case. If you have an if condition in Java that tests against a boolean that's declared static final then the compiler can determine statically whether the code is reachable or not, and it will strip it if it's not. Thus:

    static final boolean DEBUG = false;
    
    ...
    
    if (DEBUG) {
        // do something
    }
    

    The code in // do something won't get compiled at all. This is an intentional and documented behavior on the part of the Java compiler, and allows you to write expensive debug code that won't get compiled into your release binary. BuildConfig.DEBUG is declared as static final for this exact reason.

    There's a BuildConfig.FLAVOR, but it's defined as String, and you don't get the same benefit:

    static final String FLAVOR = "orange";
    
    ...
    
    if (FLAVOR.equals("apple")) {
        // do something
    }
    

    The compiler isn't smart enough to do static analysis, see that // do something is unreachable, and not compile it. Note that it will work fine at runtime, but that dead code will be included in your binary.

    If it suits you, though, you could steal the buildConfigField approach from above and define an extra boolean variable in some variants that could allow code to be conditionally compiled in. This is more complex than defining the string directly as in Solution 3, but if you find yourself wanting to differentiate behavior without going through the trouble of making flavor-specific subclasses, you could go this route.

    0 讨论(0)
提交回复
热议问题