from: http://www.jianshu.com/p/533240d222d3
Recently, there is a requirement to package nine types of App s at a time, and both constants and String.xml have variables. Although variables have always existed before, they are only packaged one at a time. This allowed me to pack nine at a time. If I pack it nine times in the future, I'll be crazy.
According to previous understanding, gradle should be able to solve this problem. So I studied it carefully.
First put a complete multi-channel/multi-environment packaging configuration, and then explain.
Achieved:
- Different environment, different package names;
- Modify different string.xml resource files in different environments.
- Modify the specified constants in different environments.
- Modify channel variables in Android Manifest. XML in different environments
apply plugin: 'com.android.application'
android {
compileSdkVersion 22
buildToolsVersion '22.0.1'
// Signature file
signingConfigs {
config {
keyAlias 'lyl'
keyPassword '123456'
storeFile file('../lyl.jks')
storePassword '123456'
}
}
// Default configuration
defaultConfig {
//applicationId "com.lyl.app"
minSdkVersion 16
targetSdkVersion 22
versionCode 1
versionName "1.0.0"
signingConfig signingConfigs.config
multiDexEnabled true
}
// Different configurations of multi-channel/multi-environment
productFlavors {
dev {
// Each environment package name is different
applicationId "com.lyl.dev"
// Add string.xml field dynamically;
// Note that this is the addition, in string.xml can not have this field, will rename!!!
resValue "string", "app_name", "dev_myapp"
resValue "bool", "isrRank", 'false'
// Dynamic modification of constant fields
buildConfigField "String", "ENVIRONMENT", '"dev"'
// Modify channel variables in Android Manifest. XML
manifestPlaceholders = [UMENG_CHANNEL_VALUE: "dev"]
}
stage {
applicationId "com.lyl.stage"
resValue "string", "app_name", "stage_myapp"
resValue "bool", "isrRank", 'true'
buildConfigField "String", "ENVIRONMENT", '"stage"'
manifestPlaceholders = [UMENG_CHANNEL_VALUE: "stage"]
}
prod {
applicationId "com.lyl.prod"
resValue "string", "app_name", "myapp"
resValue "bool", "isrRank", 'true'
buildConfigField "String", "ENVIRONMENT", '"prod"'
manifestPlaceholders = [UMENG_CHANNEL_VALUE: "prod"]
}
}
//Remove error from lint detection
lintOptions {
abortOnError false
}
def releaseTime() {
return new Date().format("yyyy-MM-dd", TimeZone.getTimeZone("UTC"))
}
buildTypes {
debug {
signingConfig signingConfigs.config
}
release {
buildConfigField("boolean", "LOG_DEBUG", "false")
minifyEnabled false
zipAlignEnabled true
//Remove useless resource files
shrinkResources true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
signingConfig signingConfigs.config
// Batch packing
applicationVariants.all { variant ->
variant.outputs.each { output ->
def outputFile = output.outputFile
if (outputFile != null && outputFile.name.endsWith('.apk')) {
//The output APK name is: channel name_version name_time.apk
def fileName = "${variant.productFlavors[0].name}_v${defaultConfig.versionName}_${releaseTime()}.apk"
output.outputFile = new File(outputFile.parent, fileName)
}
}
}
}
}
}
repositories {
mavenCentral()
}
dependencies {
compile 'com.facebook.android:facebook-android-sdk:4.0.0'
compile project(':qrscan')
compile 'com.android.support:appcompat-v7:22.0.0'
compile 'com.google.code.gson:gson:2.3'
compile files('libs/android-async-http-1.4.6.jar')
compile 'com.google.android.gms:play-services:7.5.0'
compile 'com.android.support:support-annotations:22.1.1'
compile 'com.github.bumptech.glide:glide:3.7.0'
compile 'de.hdodenhof:circleimageview:2.1.0'
}
Next, let's look at modifying specific fields in detail.
The settings of different environments are basically set in product Flavors.
And you can add as many environments as you want.
1. Different environments and package names;
productFlavors {
dev {
applicationId "com.lyl.dev"
}
stage {
applicationId "com.lyl.stage"
}
prod {
applicationId "com.lyl.prod"
}
}
Note here that in defaultConfig, you should all write a default application Id.
After testing, the different environment package names set by product Flavors will override the settings in defaultConfig.
So we can infer that the order of execution should be default first, and then sub-channel. If conflict occurs, it will override processing, which is also very logical.
2. Add string.xml resource files in different environments;
Using resValue to define the value of a resource, as the name implies, the content under res should be created, and finally referenced with R.xxx.xxx.
As follows, different app_name fields are added according to different types, and Boolean values are defined, which can be referenced by R.string.app_name.
Note that here is the addition, which is the addition of a field app_name in string.xml, so you can't have this field in the existing string.xml, otherwise it will be wrong!!!
productFlavors {
dev {
resValue "string", "app_name", "dev_myapp"
resValue "bool", "isrRank", 'false'
}
stage {
resValue "string", "app_name", "stage_myapp"
resValue "bool", "isrRank", 'true'
}
prod {
resValue "string", "app_name", "myapp"
resValue "bool", "isrRank", 'true'
}
}
From the above, we can probably infer that color and dimen can also be added in a similar way.
3. Dynamic modification of specified constants in different environments;
Use BuildConfig variables.
Definition field
When we define the following fields, the compiled files are automatically generated in the app/build/source/BuildConfig/dev/com.lyl.dev/BuildConfig directory.
Open this file and we can see the fields we defined.
productFlavors {
dev {
buildConfigField "String", "ENVIRONMENT", '"dev"'
}
stage {
buildConfigField "String", "ENVIRONMENT", '"stage"'
}
prod {
buildConfigField "String", "ENVIRONMENT", '"prod"'
}
}
(2) Reference fields
In any of our own classes, we can call the fields we defined directly through BuildConfig.
public class Constants {
public static final String ENVIRONMENT = BuildConfig.ENVIRONMENT;
}
Note: Here's a little detail. The third parameter is to use "'" first and then "". This grammar may be unfamiliar in Java, but in many other languages, this usage is very common.
It means "dev" as a whole belongs to a string. As for why you write this, you remove the single quotation marks and go to the file app/build/source/BuildConfig/dev/com.lyl.dev/BuildConfig to see.
4. Modify channel variables in Android Manifest. XML in different environments
(1) Add channel variables to Android Manifest. XML
<application
android:icon="${app_icon}"
android:label="@string/app_name"
android:theme="@style/AppTheme">
...
<meta-data
android:name="UMENG_CHANNEL"
android:value="${ENVIRONMENT}" />
...
</application>
(2) Setting up product Flavors in build.gradle
productFlavors {
dev {
manifestPlaceholders = [ENVIRONMENT: "dev",
app_icon : "@drawable/icon_dev"]
}
stage {
manifestPlaceholders = [ENVIRONMENT: "stage",
app_icon : "@drawable/icon_stage"]
}
prod {
manifestPlaceholders = [ENVIRONMENT: "prod",
app_icon : "@drawable/icon_prod"]
}
}
So we can use different key values in different environments.
Through the above way, we can basically set the application title dynamically through gradle, apply icons, replace constants, set different package names, change channels and so on.
Finally, after all the configurations are completed, the normal packaging operation is performed.
As shown in the figure:
After packaging, you can see the generated apk package in the directory we specified.
Finally, put a project address:
https://github.com/Wing-Li/boon
OK.
If there are any problems in this article, please point out.
O(∩_∩)O