When we are developing an app, we are often faced with the need to release different versions. Take two common scenarios for example. Scenario 1: We are developing new functions. After the development is completed, we need to release the test version and submit it to QA testers. Scenario 2: We need to release a free version and a paid version of our app. The paid version will have higher access. In these two cases we need to release four APKs, free QA, free online, paid QA, and paid online, which would complicate the project if hard coded into the code. Build Type can be configured for the QA or online version. Androidstudio defaults to Debug and Release types. Build flavors can be configured for the paid or free version. These two types combined are called build Variant

Build types

In this configuration, we can define what the package name of the application is, whether unreferenced resources are automatically removed, whether obfuscations are enabled, and so on. For details, see the following code

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

When we create a new project or module, the build.gradle file is configured with the release build type by default, the obfuscation function is disabled (minifyEnabled is set to false), and the obfuscation file location is defined. In addition to the release build type, the debug build type is created by default, but it is not shown in the code. If you want to change the configuration in the default debug, you need to declare it separately.

Debug Build Type Sets the debug property to true by default to facilitate debugging

Create build types

When we feel that the default two types are insufficient, we can easily customize the build type. The following code shows how to create a new build type named qa_test

android {
    buildTypes {
        qa_test {
             applicationIdSuffix ".qatest"
            versionNameSuffix "-qatest"
            buildConfigField "String", "API_URL",""http://staging.example.com/api""
          }
    }
}
Copy the code

Qatest is added to the package name, so we can install the same program on the phone, because the package name is different. Add the -qatest suffix to the version name, and then add an API_URL string property to the BuildConfig class.

With buildConfigField, the BuildConfig class adds the constants defined after compilation

When customizing build types, you can also reuse existing build types, as shown in the following code

 android {
       buildTypes {
           qa_test.initWith(buildTypes.debug)
           qa_test {
               applicationIdSuffix ".staging"
               versionNameSuffix "-staging"
               debuggable = false
            } 
        }
}
Copy the code

**initWith()** copies all the properties of the debug type for the qa_test type, but we can also modify the properties and declare them by display.

Build Types Code directory structure Settings

When we create a new build type, Gradle will also specify a directory with the same name in the project by default. However, the directory will not be created automatically, so we need to manually create a directory with the same name. The structure is shown below

This configuration allows us to customize the code in any build type, such as the release type login interface with the official version of the Logo, and the debug version login interface with the test version of the Logo

Tips: When we create different build types and make different changes in different type directories, but use the source code in the main directory. For example, if we want to have different Login interfaces in different types, then we cannot include LoginActivity in the main package. If we add LoginActivity in main, the compiler will prompt dumpllicated file

For Resources, it’s a little different than Java code. For layout, Drawable, and images, if they are defined in different types, they will replace the same resource files in main. In the case of String, the Color of the resource will be merged, as shown in the String

<resources> <string name="app_name">TypesAndFlavors</string> <string name="hello_world">Hello world! </string> </resources>Copy the code

If string.xml in qa_test type is as follows

 <resources>
       <string name="app_name">TypesAndFlavors QA_Test</string>
</resources>
Copy the code

The merged string.xml is shown below

<resources> <string name="app_name">TypesAndFlavors QA_Test</string> <string name="hello_world">Hello world! </string> </resources>Copy the code

If we don’t have a custom string resource file, gradle will default to string in main. If you want to modify the manifest file, just add the code we need to the manifest file in the corresponding build type directory. Gradle will automatically merge. The principles of Gradle merge will be described in more detail in the following sections

Rely on

Each build type may have its own independent dependencies. Gradle automatically recognizes the configuration if it is configured. For example, to add a logging framework to the Debug type, refer to the code below

dependencies { compile fileTree(dir: 'libs', include: [' *. Jar ']) compile 'com. Android. Support: appcompat - v7:22.2.0' debugCompile 'DE. Mindpipe. Android: android logging - log4j: 1.0.3'}Copy the code

DebugCompile indicates that log4j is added to the compile path only in the debug type. For common scope dependencies, see Series 3 :Gradle Dependency Management

Product flavors

Build Type is used to build different types of apps, such as debug or release versions, and Produc flavors is used to create different versions of the same app, such as paid and free versions. One common application scenario is to create an app that offers different bank flavors. Different bank apps have different logos, and produc flavors is an option to create different versions of an app or library based on one set of code.

If you’re not sure when to use build Type and when to use Product flavors, ask yourself a few questions. If you’re building different types for internal use or submitting a new app on Google Palay, build Type is recommended. If your app is going to be distributed on different channels, consider product flavors

To create the product flavors

Creating Product Flavors is very similar to building Types; all you need to do is add the productFlavor block, as shown below

 android {
       productFlavors {
           red {
               applicationId 'com.gradleforandroid.red'
               versionCode 3
            }
         blue {
               applicationId 'com.gradleforandroid.blue'
               minSdkVersion 14
               versionCode 4
            }
      }
}
Copy the code

Product flavors = build types; Product flavors = Product flavors; The defaultConfig added to the build.gradle file is also an instance of the ProductFlavors class.

Product Flavors code directory structure

Similar to build Type, product Flavors can also be configured in the build Type directory.

Multiflavor variants

In some cases, you might want to combine flavors. Let’s say your app has two flavors, a green one and a red one, and then you have two versions, a paid one and a free one. You might want to combine flavors like red free, red paid one, green free one, and green paid one. You can use flavorDimensions to solve flavors combinations

android { flavorDimensions "color", "price" productFlavors { red { flavorDimension "color" } blue { flavorDimension "color" } free { flavorDimension "price"  } paid { flavorDimension "price" } } }Copy the code

When we add flavorDimensions, gradle determines if we have specified the flavorDimensions for the flavor. If not, Gradle will compile an error, and the order in which you set flavorDimensions is important. For example, if the red flavor has the same code change as the paid flavor, Then in the run time to the flavorDimensions configuration sequence shall prevail, according to the above configuration, is the code in the red theme shall prevail.

Assuming that our build types are configured debug and Release, the build variants generated from the above code configuration are as follows

  • BlueFreeDebug and blueFreeRelease
  • BluePaidDebug and bluePaidRelease
  • RedFreeDebug and redFreeRelease
  • RedPaidDebug and redPaidRelease

Build variants

Build flavors are the result of a build Type and product flavors combination. When you create a new build type or Product flavor, the new flavors are created accordingly. For example, if our build types are standard debug and release, then when we create a Product flavor with red theme and blue theme, the corresponding build variants will be automatically generated.

In the above screenshot for Android Studio Build Variants Tool box, the default in Android Studio interface penultimate the edge of the lower left corner, or by the View | Tool Windows | Build Variants to open.

If we don’t configure Product flavors, the models will only include build types. Gradle’s Android plugin will also default to debug build type, so build variants will not be empty.

Tasks

Gradle’s Android plug-in will automatically generate tasks based on the Build Variant we configured. A new Android app project has debug and Release build types by default, so you can run assembleDebug and assembleRelease to generate different APKs. Or run assemble directly to generate two build types of APK. When we add a new build type, we add a new task accordingly. When new flavors product is added and task is generated again, there will be some changes, because each product flavor and build type are combined. So even the simplest combination of a build type and a flavor will generate three corresponding tasks:

AssembleBlue uses the Blue flavor, which is equivalent to running assembleBlueRelease and assembleBlueDebug

Code directory configuration (Source sets)

Build variants are a combination of Build type and Product Flavor. For example, our source code has four directories: Main, Releas, Debug, and Red. Release and Debug are Build type categories. The corresponding build variant is redReleas and redDebug. In other words, the source code used by redReleas is a combination of red and release directories. Similarly, redDebug uses a combination of code from the RED and debug directories.

Merge resource files and manifest files

Different build types and Product flavors have different source directories. When different Build Variant packages are generated, resources need to be merged. For example, we set the permission to store logs in the manifest file of debug Build type. However, the manifest file in the main directory is not required, so when you build the debug build variant, you need to merge the manifest file in the main directory with the manifest file in the debug directory. The priority of the selected resources is as shown in the figure below:

As shown in the preceding figure, if the flavor contains a logo. PNG image, the main directory also contains a logo. PNG image. If the flavor has a higher priority than Main, use logo.png in the flavor

There are a lot of details about merging resources and manifest files that I can’t go into here, but the official documentation gives more details. [Android Developer: manifest-merger](tools.android.com/tech-docs/n… system/user-guide/manifest-merger)

Create build variants

Gradle makes it easy to deal with complex build varinats, even though we create two build types and two Product flavors. The code in the build file is still very clear

android {
       buildTypes {
           debug {
               buildConfigField "String", "API_URL",
               ""http://test.example.com/api""
         }
           staging.initWith(android.buildTypes.debug)
           staging {
               buildConfigField "String", "API_URL",
                 ""http://staging.example.com/api""
               applicationIdSuffix ".staging"
           }
      }
       productFlavors {
           red {
               applicationId "com.gradleforandroid.red"
               resValue "color", "flavor_color", "#ff0000"
           }
           blue {
               applicationId "com.gradleforandroid.blue"
               resValue "color", "flavor_color", "#0000ff"
         }
   }
}
Copy the code

In the code above, we created four build variants: blueDebug, blueStaging, redDebug, redStaging. Each variant defines the API URL and flavor color. Running the program blueDebug might look like the following

RedStaging might look like this

The first screenshot is blueDebug, which uses the URL in the Debug build Type and the color in the Blue Product Flavor. The same can be applied to redStaging

Variant filters

You may not want to use a build variant, for example, build type with debug and release, red and blue flavors, but blue is not an option. We can filter it out and it won’t appear in the BuildGrowth window in Android Studio. We can filter it by adding the following code to the build.gradle file in the app module or library module:

android.variantFilter { variant -> if (variant.buildType.name.equals('release')) { variant.getFlavors().each() { flavor -> if (flavor.name.equals('blue')) { variant.setIgnore(true); }}}}Copy the code

After adding the above code and synchronizing the project, you will see the blue release version in the BuildVariants window of AndroidStudio

Signing Configuration(APK)

Before releasing the app to Google Play or other app markets, we need to sign the apK secret key. If we had both free and paid versions for users, we would need to give each flavor a different signature. The signature configuration code is shown below

 android {
       signingConfigs {
           staging.initWith(signingConfigs.debug)
           release {
               storeFile file("release.keystore")
               storePassword "secretpassword"
               keyAlias "gradleforandroid"
               keyPassword "secretpassword"
            }
        }
}
Copy the code

In the example above, we created two different signature configurations

The debug-type signature configuration is automatically generated by gradle’s Android plugin, and the alias name of the password is the default.

Tips: Do not write the password in the build.gradle file. Instead, write it in the local.properties file

After adding the signature configuration, you can use the signature information. The following code can be referenced

Used in buildType

 android {
       buildTypes {
           release {
               signingConfig signingConfigs.release
            }
        }
}
Copy the code

Use that in flavors

 android {
       buildTypes {
           release {
               productFlavors.red.signingConfig signingConfigs.red
               productFlavors.blue.signingConfig signingConfigs.blue
            } 
        }
}
Copy the code

As you can see from the above code, we cannot configure as follows

 android {
       productFlavors {
           blue {
               signingConfig signingConfigs.release
            } 
        }
}
Copy the code

This is because the flavor overwrites the signature in the TYPE when you merge the build type and flavor

conclusion

In this section, we discuss build Type, Produc flavors, and combinations of the two, as well as the source code and resource file details. Then the configuration of signatures is introduced.