1. Gradle
Other modules
1.1 Settings
class
This Setting
class may not have seen before us, but settings.gradle
we have seen many times
that this setttings.gradle
and our Settings.java
so what does it matter? We recall our previous Project
, it contains a default file name is called build.gradle
, that is, each of us Project
by this initialization is build.gradle
to initialize the Project
entity object, here we are this settings.gradle
and Settings
class is the same, by settings.gradle
the configuration to Settings
initialize, their core function is to decide which projects need to be gradle
treated
Settings
like the most important is this inclue
Method, through this method we can introduce our new project. This settings,gradle
is very simple for our developers, but it is not simple in this province. It takes up gradle
one third of the entire life cycle, which is the `initialization phase.
1.2 SourceSet
Class
We know that our engineers src/main/java
write source code in the directory and finally compile it into bytecode files, and src/main/res
our resource files are stored in the directory. This is our gradle
default agreement, which is also our sourceSet
biggest role. Manage our source code, resources, libraries, etc. Where to store it. Since there is a default, can we change it? The answer is yes. First AndroidSourceSet
, let's take a look at the source code of this class and see what we can change
public interface AndroidSourceSet {
/**
* Configures the Java resources for this set.
*
* <p>The given closure is used to configure the {@link AndroidSourceDirectorySet} which
* contains the java resources.
*
* @param configureClosure The closure to use to configure the javaResources.
* @return this
*/
@NonNull
AndroidSourceSet resources(Closure configureClosure);
/**
* Configures the Java source for this set.
*
* <p>The given closure is used to configure the {@link AndroidSourceDirectorySet} which
* contains the Java source.
*
* @param configureClosure The closure to use to configure the Java source.
* @return this
*/
@NonNull
AndroidSourceSet java(Closure configureClosure);
/**
* Configures the location of the Android Manifest for this set.
*
* <p>The given closure is used to configure the {@link AndroidSourceFile} which contains the
* manifest.
*
* @param configureClosure The closure to use to configure the Android Manifest.
* @return this
*/
@NonNull
AndroidSourceSet manifest(Closure configureClosure);
/**
* Configures the location of the Android Resources for this set.
*
* <p>The given closure is used to configure the {@link AndroidSourceDirectorySet}
* which contains the resources.
*
* @param configureClosure The closure to use to configure the Resources.
* @return this
*/
@NonNull
AndroidSourceSet res(Closure configureClosure);
/**
* Configures the location of the Android Assets for this set.
*
* <p>The given closure is used to configure the {@link AndroidSourceDirectorySet}
* which contains the assets.
*
* @param configureClosure The closure to use to configure the Assets.
* @return this
*/
@NonNull
AndroidSourceSet assets(Closure configureClosure);
/**
* Configures the location of the Android AIDL source for this set.
*
* <p>The given closure is used to configure the {@link AndroidSourceDirectorySet}
* which contains the AIDL source.
*
* @param configureClosure The closure to use to configure the AIDL source.
* @return this
*/
@NonNull
AndroidSourceSet aidl(Closure configureClosure);
/**
* Configures the location of the Android RenderScript source for this set.
*
* <p>The given closure is used to configure the {@link AndroidSourceDirectorySet}
* which contains the Renderscript source.
*
* @param configureClosure The closure to use to configure the Renderscript source.
* @return this
*/
@NonNull
AndroidSourceSet renderscript(Closure configureClosure);
/**
* Configures the location of the Android JNI source for this set.
*
* <p>The given closure is used to configure the {@link AndroidSourceDirectorySet}
* which contains the JNI source.
*
* @param configureClosure The closure to use to configure the JNI source.
* @return this
*/
@NonNull
AndroidSourceSet jni(Closure configureClosure);
/**
* Configures the location of the Android JNI libs for this set.
*
* <p>The given closure is used to configure the {@link AndroidSourceDirectorySet}
* which contains the JNI libs.
*
* @param configureClosure The closure to use to configure the JNI libs.
* @return this
*/
@NonNull
AndroidSourceSet jniLibs(Closure configureClosure);
/**
* Configures the location of the Android shaders for this set.
*
* <p>The given closure is used to configure the {@link AndroidSourceDirectorySet}
* which contains the shaders.
*
* @param configureClosure The closure to use to configure the shaders.
* @return this
*/
@NonNull
AndroidSourceSet shaders(Closure configureClosure);
/**
* Sets the root of the source sets to a given path.
*
* All entries of the source set are located under this root directory.
*
* @param path the root directory.
* @return this
*/
@NonNull
AndroidSourceSet setRoot(String path);
}
Here I have removed all get
methods, we only care about the settings.
The first example: modify the so
file location of our default storage. The default storage location of
our AS project is as src/main/jniLibs
follows, we want to store it in our libs
directory
sourceSets {
main {
jniLibs.srcDirs = ['libs']
}
}
The second example: res
subcontracting, like our java
code,
here we first create a few folders, which are at the res
same level as ours.
Here we find that the two new folders we added are res
still not the same as ours. folder, then we put these two folders to add to our sourceSets
in
sourceSets {
main {
res.srcDirs = ['src/main/res',
'src/main/res-ad',
'src/main/res-player']
}
}
After synchronization, we are watching
We can also two examples of our above code written in one sourceSets
of the
You can also get it android
outside
2. Gradle
The Plugin
actual
2.1 Plugin
Definition
Gradle
In the package Plugin
is to complete the specified function Task
, as long as the project depends on a certain Plugin
, you can perform Plugin
all the functions in it, for example: using the Java
plug-in can be jar
packaged, using the Android
plug-in, you can generate apk、aar
.
2.2 Create aPlugin
2.2.1 Create a plug-in project
- Create a
buildSrc
folder under our project directory .
- Under the
buildSrc
directory, createsrc/main
folders andbuild.gradle
files.
- In the
main
Create the following foldersgroovy
andresources
folders
- In
resources
creating aMETA-INF
folder, and then in theMETA-INF
creation of agradle-plugins
folder.
build.gradle
Enter the following script in the file:
apply plugin: 'groovy'
sourceSets {
main {
groovy {
srcDir 'src/main/groovy'
}
resources {
srcDir 'src/main/resources'
}
}
}
- Compile
2.2.2 Create a plugin class
This is Java
basically the same as ours, we groovy
create a folder under our com.hfs.gradle.study
folder, this is equivalent to our package name
We then study
create a folder plugin class GradleStudyPlugin
, pay attention, here GradleStudyPlugin
is a .groovy
suffix, not .java
because we are creating a plug-in, so we need to take this class implements Gradle
the interface provided
2.2.3 Specifying the plugin entrance
We next want to declare how others use our plug-in, so where do we declare it? We need to META-INF.gradle-plugins
create a properties
file in the directory first , properties
we generally use the package name of the plug-in class to define
the content inside is very simple, just a sentence
2.2.4 Using custom plugins
The next step is to use it, it is very simple, apply plugin:
plus the package name of our plugin, for example, our app
project needs to introduce this plugin, open app
the build.gradle
file, plus this sentence
2.2.5 Creating extended attributes
1. Create a class entity for receiving the gradle中
parameters, similar to our Java
classes, but to .groovy
the suffix
package com.hfs.gradle.study
/**
* 与自定义Plugin进行参数传递
*/
class ReleaseInfoExtension {
/**
* 版本号
*/
String versionCode
/**
* 版本名字
*/
String versionName
/**
* 版本信息
*/
String versionInfo
/**
* 文件路径
*/
String fileName
ReleaseInfoExtension() {
}
@Override
String toString() {
"""| versionCode = ${versionCode}
| versionName = ${versionName}
| versionInfo = ${versionInfo}
| fileName = ${fileName}
""".stripMargin()
}
}
2. Create in a custom plugin
/**
* 自定义Plugin
*/
class GradleStudyPlugin implements Plugin<Project> {
/**
* 唯一需要实现的就是这个方法,参数就是引入了当前插件的Project对象
* @param project
*/
@Override
void apply(Project project) {
//创建扩展属性
project.extensions.create('hfsReleaseInfo', ReleaseInfoExtension)
}
}
In app to build.gradle
be used in
the next
2.2.6 Create Extended Task
package com.hfs.gradle.study
import groovy.xml.MarkupBuilder
import org.gradle.api.DefaultTask
import org.gradle.api.tasks.TaskAction
/**
* 自定义Task,实现维护版本信息功能
*/
class ReleaseInfoTask extends DefaultTask {
ReleaseInfoTask() {
// 指定分组
group = 'hfs'
//说明信息
description = 'update the release info'
}
/**
* 使用TaskAction注解,可以让方法在gradle的执行阶段去执行。
* doFirst其实就是在外部为@TaskAction的最前面添加执行逻辑。
* 而doLast则是在外部为@TaskAction的最后面添加执行逻辑。
*/
@TaskAction
void doAction() {
updateInfo()
}
//真正的将Extension类中的信息呢,写入指定文件中
private void updateInfo() {
//获取将要写入的信息
String versionCodeMsg = project.extensions.
hfsReleaseInfo.versionCode
String versionNameMsg = project.extensions.
hfsReleaseInfo.versionName
String versionInfoMsg = project.extensions.
hfsReleaseInfo.versionInfo
String fileName = project.extensions.
hfsReleaseInfo.fileName
def file = project.file(fileName)
if (file != null && !file.exists()) {
file.createNewFile()
}
//将实体对象写入到xml文件中
def sw = new StringWriter()
def xmlBuilder = new MarkupBuilder(sw)
if (file.text != null && file.text.size() <= 0) {
//没有内容
xmlBuilder.releases {
release {
versionCode(versionCodeMsg)
versionName(versionNameMsg)
versionInfo(versionInfoMsg)
}
}
//直接写入
file.withWriter { writer -> writer.append(sw.toString())
}
} else {
//已有其它版本内容
xmlBuilder.release {
versionCode(versionCodeMsg)
versionName(versionNameMsg)
versionInfo(versionInfoMsg)
}
//插入到最后一行前面
def lines = file.readLines()
def lengths = lines.size() - 1
file.withWriter { writer ->
lines.eachWithIndex { line, index ->
if (index != lengths) {
writer.append(line + '\r\n')
} else if (index == lengths) {
writer.append('\r\r\n' + sw.toString() + '\r\n')
writer.append(lines.get(lengths))
}
}
}
}
}
}
Like custom attributes, they need to be created in a custom plugin
/**
* 自定义Plugin
*/
class GradleStudyPlugin implements Plugin<Project> {
/**
* 唯一需要实现的就是这个方法,参数就是引入了当前插件的Project对象
* @param project
*/
@Override
void apply(Project project) {
//创建扩展属性
project.extensions.create('hfsReleaseInfo', ReleaseInfoExtension)
//创建Task
project.tasks.create('hfsReleaseInfoTask', ReleaseInfoTask)
}
}
Under synchronization, you will gradle
see this intask
Execute thistask
3. android
Plug-in gradle
extension
I will take an app from a project to build.gradle
see what is in the android
closure. What
can be configured here? Mainly look at BaseExtension
this class
BaseExtension official specific explanation
So where are the android
introductions task
? Mainly look at BaseVariant
this class
/**
* A Build variant and all its public data. This is the base class for items common to apps,
* test apps, and libraries
*/
public interface BaseVariant {
/**
* Returns the name of the variant. Guaranteed to be unique.
*/
@NonNull
String getName();
/**
* Returns a description for the build variant.
*/
@NonNull
String getDescription();
/**
* Returns a subfolder name for the variant. Guaranteed to be unique.
*
* This is usually a mix of build type and flavor(s) (if applicable).
* For instance this could be:
* "debug"
* "debug/myflavor"
* "release/Flavor1Flavor2"
*/
@NonNull
String getDirName();
/**
* Returns the base name for the output of the variant. Guaranteed to be unique.
*/
@NonNull
String getBaseName();
/**
* Returns the output file for this build variants. Depending on the configuration, this could
* be an apk (regular and test project) or a bundled library (library project).
*
* If it's an apk, it could be signed, or not; zip-aligned, or not.
*/
@NonNull
File getOutputFile();
void setOutputFile(@NonNull File outputFile);
/**
* Returns the Manifest processing task.
*/
@NonNull
ProcessManifest getProcessManifest();
/**
* Returns the AIDL compilation task.
*/
@NonNull
AidlCompile getAidlCompile();
/**
* Returns the Renderscript compilation task.
*/
@NonNull
RenderscriptCompile getRenderscriptCompile();
/**
* Returns the resource merging task.
*/
@Nullable
MergeResources getMergeResources();
/**
* Returns the asset merging task.
*/
@Nullable
MergeAssets getMergeAssets();
/**
* Returns the Android Resources processing task.
*/
@NonNull
ProcessAndroidResources getProcessResources();
/**
* Returns the BuildConfig generation task.
*/
@Nullable
GenerateBuildConfig getGenerateBuildConfig();
/**
* Returns the Java Compilation task.
*/
@NonNull
JavaCompile getJavaCompile();
/**
* Returns the Java resource processing task.
*/
@NonNull
Copy getProcessJavaResources();
/**
* Returns the assemble task.
*/
@Nullable
Task getAssemble();
}
Documentation The
above document has a detailed introduction
Next, let's practice the custom apk
output path and name
this.afterEvaluate {
this.android.applicationVariants.all { variant ->
def output = variant.outpus.first()
def apkName = "app-${variant.baseName}-${variant.versionName}.apk"
output.outputFile = new File(output.outputFile.parent, apkName)
}
}