Settings 类
决定一个工程中有哪些模块是需要被处理的。
public interface Settings extends PluginAware, ExtensionAware { //默认的文件名称 String DEFAULT_SETTINGS_FILE = "settings.gradle"; //将指定的 project 加载到的构建中 void include(String... projectPaths); }
Settings 类如何被 gradle 初始化完全取决于 settings.gradle 文件的配置。setting.gradle 中就需要指定有哪些模块需要被处理。
include ':app', ':core', ':detegateManager', ':tabHome', ':tabShop', ':tabDiscover', ':tabMall', ':tabMine', ':ui'
如上就是有多个模块被加载到构建中,Settings 会在 gradle 生命周期的初始化阶段执行,确定要构建的模块,并创建 project 对象
SourceSet 类
gradle 是如何从从 src/main/java/package/ 下面去读取我们的源码,然后生成字节码文件呢?其实就是通过 SourceSet 类的配置中拿到的。
SourceSet 类决定了我们所有的代码,资源,第三方库等存放的位置。
gradle 中约定大于配置,只要没有配置,那就是按约定的来。gradle 默认从 java 文件下获取源码,从 res 文件下获取资源 进行编译。这些约定可以进行修改。
通过 SourceSet 类我们可以修改默认的存放路径,如 so 的路径,res 的路径,java 文件的路径等。如下所示:
android { sourceSets { main { //修改 so 文件存放的位置 jniLibs.srcDirs = ['libs'] } } }
使用上面的配置后,gradle 在加载 so 文件时就会从 libs 下进行加载。
修改资源路径:如果一个项目太过庞大,其代码还可以通过创建 package 来整理一下,看起来会更加简洁,容易寻找。但是资源文件却不行,默认只有一个 res 目录,所有的自愈都需要放在 res 中。但是通过 SourceSet 类可以指定多个 res 文件夹,这些文件夹里面就可以存放不同模块下的资源文件了。如下:
在 main 文件下新建文件夹 res-ad 用来存放广告资源,res-play 存放游戏资源。创建完成后在 build.gradle 中的 android 下添加如下代码:
sourceSets { main { res.srcDirs = ['src/main/res', 'src/main/res-ad', 'src/main/res-play'] } }
接着同步一下,就会发现这两个文件夹上面的图标和 res 的图标是一样的了。
Plugin 详解及自定义 Plugin
Gradle 插件使用 Groovy 开发的,而 Groovy 完全兼容 Java ,使用 AS 完全可以开发 Gradle 插件。
处理插件:Gradle 会自动找到插件的所在位置,如 buildSrc 名字会被 Gradle 识别为 插件工程
应用环境:一旦插件被应用到构建的脚本中,那么插件对应的 apply 方法就会被调用
插件项目的创建:在 as 中新建一个 library。删除一些内容。使其和图片中的一样:
groovy 下新建一个包名。
META-INF/gradle-plugins/下新建一个 .properties 文件,这里的为文件名字最终会出现在:
apply plugin: 'com.car.srcplugin'
注意 :build.gradle 中所有的内容都需要删掉
下面开始一个小 Demo:还是保存每次发布的版本信息。只不过有了很大的改进。
1,配置一些 build.gradle
apply plugin: 'groovy' sourceSets { main { groovy { srcDir 'src/main/groovy' } resources { srcDir 'src/main/resources' } } } dependencies { //gradle sdk implementation gradleApi() //groovy sdk implementation localGroovy() }
2,自定义 Taks
class UpDataInfoTask extends DefaultTask { private VersionInfo versionInfo ReleaseInfoTask() { //设置组名和描述信息 group = '345' description = 'update the release info' } /** * 使用 TaskAction 注解,这个方法会执行在执行阶段 * doFirst 就是给这个方法的最前面添加代码 * doLast 就是给这个方法的最后面添加代码 */ @TaskAction void doAction() { upDataInfo() } /** * 将 Extension 类中的信息写入到指定的文件中 */ void upDataInfo() { project.logger.error "------------------- 开始插入信息 -------------------" String versionNameMsg = project.extensions .upDataInfo.versionName String versionCodeMsg = project.extensions .upDataInfo.versionCode String versionInfoMsg = project.extensions .upDataInfo.versionInfo String buildType = project.extensions. upDataInfo.buildType if (buildType == null || buildType.isEmpty()) { buildType = "Release" } File file = project.file(buildType + ".json") if (file != null && !file.exists()) { file.createNewFile() } if (file.text != null && file.text.size() >= 0) { String text = file.text if (text != null && !text.isEmpty()) { versionInfo = new JsonSlurper().parseText(text) } else { versionInfo = new VersionInfo() versionInfo.setUpDataInfo = [] } if (versionInfo.setUpDataInfo.size() > 0) { //如果版本号一样,使用新的 int pos = versionInfo.setUpDataInfo.size() - 1; if (versionNameMsg == versionInfo.setUpDataInfo.get(pos).versionName) { project.logger.error "------------------- 版本号相同,已替换 -------------------" versionInfo.setUpDataInfo.remove(pos) } } VersionInfo.UpDataInfoBean bean = new VersionInfo.UpDataInfoBean(); bean.versionCode = versionCodeMsg bean.versionName = versionNameMsg bean.versionInfo = versionInfoMsg bean.versionTime = stampToDate(System.currentTimeMillis()) versionInfo.setUpDataInfo.add(bean) String json = JsonOutput.toJson(versionInfo) file.withWriter { write -> write.write(JsonOutput.prettyPrint(json)) } project.logger.error "------------------- 更新信息已生成 -------------------" } } private static String stampToDate(long time) { SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); Date date = new Date(time) simpleDateFormat.format(date) } }
3,VersionInfo
class VersionInfo { private List<UpDataInfoBean> updataInfo; public List<UpDataInfoBean> getSetUpDataInfo() { return updataInfo; } public void setSetUpDataInfo(List<UpDataInfoBean> relaseInfo) { this.updataInfo = relaseInfo; } public static class UpDataInfoBean { /** * versionName : * versionCode : * versionInfo : * versionTime : */ private String versionName; private String versionCode; private String versionInfo; private String versionTime; public String getVersionName() { return versionName; } public void setVersionName(String versionName) { this.versionName = versionName; } public String getVersionCode() { return versionCode; } public void setVersionCode(String versionCode) { this.versionCode = versionCode; } public String getVersionInfo() { return versionInfo; } public void setVersionInfo(String versionInfo) { this.versionInfo = versionInfo; } public String getVersionTime() { return versionTime; } public void setVersionTime(String versionTime) { this.versionTime = versionTime; } } }
4,UpDataInfoExtension
闭包中要用到的属性
class UpDataInfoExtension { /** * code */ String versionCode /** * name */ String versionName /** * 发布信息 */ String versionInfo /** * 打包类型。默认为 Release ,也可以是 Debug。注意 首字母大写。 */ String buildType }
5,自定义 plugin
/** * 自定义插件 */ class GradleStudyPlugin implements Plugin<Project> { Project mProject = null; /** * 插件被引入时要执行的方法 * @param project 引入当前插件的 project */ @Override void apply(Project project) { mProject = project def android = mProject.extensions.android //通过在外边定义 upDataInfo 闭包,完成对 UpDataInfoExtension 的初始化 project.extensions.create('upDataInfo', UpDataInfoExtension) //创建 Task UpDataInfoTask task = project.tasks.create('upDataInfoTask', UpDataInfoTask) //配置阶段完成后执行 mProject.afterEvaluate { String buildType = mProject.extensions.upDataInfo.buildType //默认 Release if (buildType == null || buildType.isEmpty()) { buildType = "Release" } mProject.logger.error("------------------- ${buildType} -------------------") def buildTask = mProject.tasks.getByName("assemble${buildType}") if (buildTask == null) { throw GradleException('the build task is not fond') } buildTask.doLast { task.upDataInfo() } } } }
6,META-INF/gradle-plugins/
META-INF/gradle-plugins/下新建一个 .properties 文件。文件名字一般和包名一样
implementation-class=com.car.srcplugin.GradleStudyPlugin
这里指向自定义的 Plugin
7,使用方式
每次打Release 或者 Debug 包的时候这个会自动执行。或者是使用命令行直接启动也可以。
在 app/build.gradle 中引入
apply plugin: 'com.car.srcplugin'
创建闭包,注意和 android 闭包平级
upDataInfo { versionCode String.valueOf(version_code) versionName version_name versionInfo version_info //默认 Release,还可以是Debug ,注意首字母大写 buildType "Debug" }
8,使用结果
9,总结
这个插件也写了好久,因为也是刚开始学,到现在有些问题还没有解决。以后再慢慢解决吧。
android 插件对 gradle 扩展
在 build.gradle 中,有一个 android 的闭包,在这个闭包中可以的定义非常多的内容。BaseExtension 类就是 闭包中能够调用的所有方法如下:
public abstract class BaseExtension implements AndroidConfig { /** Secondary dependencies for the custom transform. */ private final List<List<Object>> transformDependencies = Lists.newArrayList(); protected final GlobalScope globalScope; private final DefaultConfig defaultConfig; private final AaptOptions aaptOptions; private final LintOptions lintOptions; private final ExternalNativeBuild externalNativeBuild; private final DexOptions dexOptions; private final TestOptions testOptions; private final CompileOptions compileOptions; private final PackagingOptions packagingOptions; private final JacocoOptions jacoco; private final Splits splits; ...... }
上面列举了部分的属性。android 闭包中所有的属性方法都是调用这个类里面的。