AOP
思想
AOP
为Aspect Oriented Programming
的缩写,意为:面向切面编程,通过预编译方式和运行期间动态代理实现程序功能的统一维护的一种技术。利用AOP
可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
Android
中常用的AOP
方式有四种:
APT
: (Annotation Processing Tool
)是一种处理注释的工具,它对源代码文件进行检测找出其中的Annotation
,根据注解自动生成代码。KAPT
: (Kotlin Annotation Processing Tool
) ,即用于kotlin的apt,将kotlin代码翻译成java,再由APT
处理KSP
: (Kotlin Symbol Processing
),Kapt
的升级版,可识别kotlin代码直接处理,比KAPT
快gradle plugin
:gradle
插件,功能更强大,不仅可以生成代码,还可以修改源文件字节码、资源文件等,还可以hook打包流程,处理额外的操作等
gradle plugin 7.0
之前,使用Transform
,本篇基于4.1.3
改造。gradle plugin 7.0
开始,Transform
废弃,这个方案后面再说。
1. 自定义gradle plugin
1.1 创建插件module
File
-> New
-> Module
-> Java or Kotlin Library
,右侧Build Configuration Language
选择Groovy DSL (build.gradle)
即可,表示使用groovy
语言。如果对kotlin
熟悉的,选择另一个Kotlin DSL (build.gradle.kts)
也可。
1.2 build.gradle
引入项目依赖
plugins {
id 'groovy' // Groovy Language
id 'java-gradle-plugin' // Java Gradle Plugin
}
repositories {
mavenCentral()
}
dependencies {
implementation gradleApi()
implementation localGroovy()
}
1.3 创建插件入口处理类
commonplugin
|_src
|_main
|_groovy
|_com
|_kongge
|_commonplugin
|_CommonPlugin.groovy
package com.kongge.commonplugin
import org.gradle.api.Plugin
import org.gradle.api.Project
class CommonPlugin implements Plugin<Project> {
@Override
void apply(Project project) {
println '----------CommonPlugin start----------'
println '----------CommonPlugin end----------'
}
}
1.4 配置插件
在build.gradle
下方配置插件id和主入口class
dependencies {
// ...
}
gradlePlugin {
plugins {
modularPlugin {
// Plugin id.
id = 'com.kongge.common_plugin'
// Plugin implementation.
implementationClass = 'com.kongge.commonplugin.CommonPlugin'
}
}
}
AS
Build
-> Make Module 'xx.commonplugin'
构建,会生成该插件的配置文件com.kongge.common_plugin.properties
commonplugin
|_build
|_pluginDescriptors
|_groovy
|_com.kongge.common_plugin.properties
com.kongge.common_plugin.properties
内容如下:
implementation-class=com.kongge.commonplugin.CommonPlugin
2. 插件发布到本地仓库
build.gradle
加入maven插件
plugins {
id 'groovy' // Groovy Language
id 'java-gradle-plugin' // Java Gradle Plugin
id 'maven' // 加入插件
}
// ...
uploadArchives {
repositories {
mavenDeployer {
pom.groupId = 'com.kongge'
pom.artifactId = 'common-plugin'
pom.version = '1.0.0'
repository(url: uri('../repo')) // 表示当前module根目录的父目录
}
}
}
gradle
同步之后,在Gradle面板会看到发布任务uploadArchives
如果没找到这个任务,在AS
设置里面勾选Configure all Gradle tasks during Sync
发布成功后,可以在项目根目录找到repo
目录,即发布成功
3. 集成使用插件
项目根目录的build.gradle
中引入依赖
buildscript {
repositories {
// ...
maven {
url uri('./repo') // 注意是一个“.”,表示当前目录下的repo目录
}
}
dependencies {
// ...
classpath 'com.kongge:common-plugin:1.0.0'
}
}
allprojects {
repositories {
// ...
maven {
url uri('./repo')
}
}
}
app build.gradle
引入插件
apply plugin: 'com.kongge.common_plugin'
构建项目,可以看到插件内的输出,至此自定义的插件流程基本完成。
PS E:\git\Demo2> ./gradlew assembleDebug
> Configure project :app
config.gradle load start
----------CommonPlugin start----------
----------CommonPlugin end----------
4. gradle插件扩展机制
有个需求,希望在APP项目里面动态设置当前插件是否生效和其他参数配置,可以使用扩展机制实现,类似如下配置
commonParam {
enable = true
doubleClickTimeSpace = 600
}
首先定义一个参数接收类,其成员变量就是接收的参数,如CommonParam.groovy
package com.kongge.commonplugin
import org.gradle.api.Project
class CommonParam {
public static final String EXT_NAME = "commonParam"
boolean enable = false
long doubleClickTimeSpace = 500
static CommonParam parseExt(Project project) {
CommonParam commonParam = project.extensions.findByType(CommonParam.class)
if (commonParam == null) {
commonParam = new CommonParam()
}
return commonParam
}
}
然后在插件入口解析参数CommonPlugin.groovy
package com.kongge.commonplugin
import org.gradle.api.Plugin
import org.gradle.api.Project
class CommonPlugin implements Plugin<Project> {
@Override
void apply(Project project) {
applyExtension(project)
println '----------CommonPlugin start----------'
doSomething(project)
println '----------CommonPlugin end----------'
}
private void applyExtension(Project project) {
project.extensions.create(CommonParam.EXT_NAME, CommonParam.class)
}
private void doSomething(Project project) {
project.afterEvaluate {
CommonParam commonParam = CommonParam.parseExt(project)
println "enable=${commonParam.enable}"
println "doubleClickTimeSpace=${commonParam.doubleClickTimeSpace}"
}
}
}
最后发布该插件,然后在APP build.gradle
中配置参数
android {
// ..
}
commonParam {
enable = true
doubleClickTimeSpace = 600
}
构建后输出
> Configure project :app
config.gradle load start
----------CommonPlugin start----------
----------CommonPlugin end----------
enable=true
doubleClickTimeSpace=600
要点如下:
- 定义参数接收
class
,其成员遍历即接收参数 - 在插件入口
class
,apply
方法中解析扩展参数 - 由于扩展参数解析时机比
apply
执行时机晚,所以需要在project.afterEvaluate
生命周期中再获取扩展参数
5. gradle
插件调试
5.1 配置调试参数 app
-> Edit Configurations...
-> Remote JVM Debug
Name
随便填,Use module classpath
选择要调试插件module
,其他默认即可
5.2 启动调试
打开Gradle
面板,找到主项目build
任务,右键选择Debug 'Demo2:app [build]'
运行
至此可以断点调试了。可能每个版本的AndroidStudio
配置略有差异,遇到不一样的稍微摸索下试试可能就成功了,一般版本越高配置越简单。