I am honored if this article has helped you, and sorry if I have wasted your time. I hope to use the simplest plain words to help people like me. If there is any mistake, please do point out, so as not to mislead you, also mislead me. This article from: www.jianshu.com/users/320f9… Thank you for your attention.

There was a recent requirement to package nine types of App at a time, and both constants and string.xml have variables. There have always been variables, but only one at a time. So that allows me to change the quantity and pack nine at a time. I’ll go crazy if I pack it nine times every time. Based on previous knowledge, Gradle should be able to solve this problem. So I looked into it.


Let’s start with a complete multi-channel/multi-environment packaging configuration, and then we’ll talk about it.

Implementation:

  1. Different environment, different package name;
  2. Modify different string. XML resource files in different environments.
  3. Different environment, modify the specified constant;
  4. Modify channel variables in Androidmanifest.xml for different environments;
  5. Reference different modules for different environments.

First put a complete configuration, you can refer to:

apply plugin: Application 'android {compileSdkVersion 22 buildToolsVersion '22.0.1' signingConfigs {config {com.android.application' android {compileSdkVersion 22 buildToolsVersion '22.0.1' keyAlias 'lyl' keyPassword '123456' storeFile file('.. /lyl.jks') storePassword '123456'}} // defaultConfig {//applicationId "com.lyl.app" minSdkVersion 16 TargetSdkVersion 22 versionCode 1 versionName "1.0.0" signingConfig SigningConfigs. config multiDexEnabled true // gradle // flavorDimensions "app"} // Multi-channels/multi-environment configuration productFlavors {dev {// gradle 3.0.0 needs this // dimension "App" // Each environment package name is different. ApplicationId "com.lyl.dev" // Dynamically add string. // Note that this is an add. in string. XML, this field cannot have the same name!! ResValue "string", "app_name", "dev_myApp" resValue "bool", "isrRank", 'false' // Manifestplaceholder = [UMENG_CHANNEL_VALUE: "Dev "]} stage {// Dimension "app" applicationId "com.lyl. Stage" resValue "string", "app_name", "stage_myapp" resValue "bool", "isrRank", 'true' buildConfigField "String", "ENVIRONMENT", '"stage"' manifestPlaceholders = [UMENG_CHANNEL_VALUE: // Dimension "app" applicationId "com.lyl. Prod "resValue "string", "app_name", "myapp" resValue "bool", "isrRank", 'true' buildConfigField "String", "ENVIRONMENT", '"prod"' manifestPlaceholders = [UMENG_CHANNEL_VALUE: Incremental true // javaMaxHeapSize "4g"} // Remove error 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'), Variants -> 'proguard-rules.pro' signingConfig signingConfigs.config // variants. variant.outputs.each { output -> def outputFile = output.outputFile if (outputFile ! = null && outputfile.name.endswith ('.apk')) { Channel name version _ a _ time. Apk def fileName = "${variant. ProductFlavors [0]. Name} _v ${defaultConfig. VersionName} _ ${releaseTime ()}. The apk." " output.outputFile = new File(outputFile.parent, FileName)}}} / / bulk packaging (gradle 3.0.0 above) / / android applicationVariants. All {variant - > / / variant. Outputs. All {/ / outputFileName = // "${variant.productFlavors[0].name}_v${defaultConfig.versionName}_${releaseTime()}.apk" // } } } } } Dependencies repositories {mavenCentral ()} {the compile 'com. Facebook. Android: facebook -- android SDK: 4.0.0' compile The compile project (' : qrscan ' '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 '), the compile 'com. Google. Android. GMS: play - services: 7.5.0' compile 'com. Android. Support: support - annotations: 22.1.1' compile 'com. Making. Bumptech. Glide: glide: 3.7.0' compile 'DE. Hdodenhof: circleimageview: 2.1.0'}Copy the code

Let’s take a closer look at modifying specific fields.

The options are based on productFlavors, and you can add as many environments as you want.

1. Different package names in different environments;

productFlavors {
	dev {
		applicationId "com.lyl.dev"
	}

	stage {
		applicationId "com.lyl.stage"
	}

	prod {
		applicationId "com.lyl.prod"
	}
}
Copy the code

Note that in defaultConfig, you should have written a default applicationId. The productFlavors environment package names override the options in defaultConfig, so we can guess that the options are executed in the order of the default, then the subchannel, and override the options if they conflict.


2. Add string. XML resource files in different environments.

Use resValue to define the value of the resource. As the name suggests, everything under res should be created and referenced by r.xx.xxx. Here we add different app_name fields and define Boolean values for different types, which can be referenced by r.string.app_name.

Notice, this is thetaaddApp_name = app_name = app_name = app_name = app_name = app_name = app_name
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'
	}
}
Copy the code

From the above, we can probably infer that color and dimen can also be added through a similar method.


3. Dynamically modify the specified constant in different environments;

Use the BuildConfig variable.

① Define a field

When we define the following fields, compiled automatically generated file, in the app/build/source/BuildConfig/dev/com. Lyl. Dev/BuildConfig directory, open the file, we can see our defined fields.

productFlavors {
	dev {
		buildConfigField "String", "ENVIRONMENT", '"dev"'
	}
	stage {
		buildConfigField "String", "ENVIRONMENT", '"stage"'
	}
	prod {
		buildConfigField "String", "ENVIRONMENT", '"prod"'
	}
}
Copy the code
② Reference field

In any of our own classes, we can call our defined fields directly with BuildConfig.

public class Constants {
	public static final String ENVIRONMENT = BuildConfig.ENVIRONMENT;

}
Copy the code

Note: the third argument is “‘” and then “”. This syntax may be unfamiliar in Java, but it is common in many other languages. It means the whole “dev” belongs to a string, as to why to write, you remove the single quotation marks, and then go to the app/build/source/BuildConfig/dev/com. Lyl. Dev/BuildConfig take a look at this file.


4. Modify channel variables in Androidmanifest.xml for different environments

Add channel variables to androidmanifest.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>
Copy the code
Create productFlavors on 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"]
	}
}
Copy the code

This allows us to use different keys in different environments.


5. Reference different Modules in different environments

This is powerful enough to refer to the corresponding Module, depending on the environment. You can replace a large number of images, string, color, vaule, etc.

First, create the module corresponding to the channel, and then reference it. The reference is as follows:

dependencies { compile fileTree(dir: 'libs', include: DevCompile Project (':devModule') stageCompile project(':stageModule') prodCompile Project (':prodModule') // Can also channel references to the network. Because it's the same here, DevCompile 'com.roughike:bottom-bar:2.0.2' stageCompile 'com.roughike:bottom-bar:2.0.2' prodCompile 'com. Roughike: bottom - bar: 2.0.2'}Copy the code

XxxCompile represents the name of each channel. Then put the files that need to be channeled into different modules and delete the main project files. ** Do note: ** If you do this, you must place the file in each channel module every time you need to reference it, otherwise you will not find the resource. This way you can replace a whole set of story resources, depending on the project requirements.





Gradle allows you to dynamically set app titles, app ICONS, constants, different package names, channels, and more.


Package compiled

Finally, with all the configuration done, it’s time to pack.

Package one (daily build)

Because there are two in buildTypes, there are two modes for each channel.

Package everything, that’s the normal package process

As shown in the figure:



Use local.properties to store private configuration

This is basically gradle setup, but if you want to upload your project to Github, or send it to someone else. There’s something private on it that people can see. For example, the password of the.jks file. In the project directory, there is a file called local.properties. You can use it to store private properties and read them from Gradle. Local. properties file with the following Settings:

sdk.dir=D\:\\Android\\android-sdk

gaodeKey=e348025dd034d1c347dd0345e34802

keyPassword=123456
Copy the code

Read the local.properties field in build.gradle

Properties = new Properties() InputStream InputStream = project.rootProject.file('local.properties').newDataInputStream() ; properties.load( inputStream ) android { ... SigningConfigs {config {keyAlias 'lyl' 'keyPassword' ) storeFile file('.. /lyl.jks') storePassword properties.getProperty( 'keyPassword' ) } } ... }Copy the code

This way you can hide some of the data you want to hide.


Possible ways to speed up Android Studio compilation

1. Add the following code to the root directory build.gradle:
Allprojects {// Add this tasks.withType(JavaCompile) {// make options.fork = true // incremental = compile options.incremental = in a separate daemon true } repositories { jcenter() } }Copy the code
2. Add it to build. Gradle at app level
android {
    dexOptions {
        incremental true
    }
}
Copy the code

Finally put a multi-channel project address, you can refer to: github.com/Wing-Li/boo…

OK. Please be sure to point out any problems with this article. O O (studying studying)