0.前言
Android一步步实现无痕埋点(1)-------万恶之源
https://blog.csdn.net/qq_33902817/article/details/122410168
上一篇文章,我们讲解了无痕埋点的基本概念.这里我们就开始继续讲解无痕埋点如何实现.
我们先上一个完好的插件的Module图
总所周知,Plugin是Gradle插件类.在编译过程会执行这一过程.
这里涉及到Gradle的插件知识.如果要了解更多请自行baidu
如果不是很熟悉,那么至少,你对这些应该很熟悉吧.如何来定义一个module是library还是application.
其实是一个道理的。
plugins {
id 'com.android.application'
}
apply plugin: 'kotlin-kapt'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-parcelize'
我们开始构造项目
这里的插件Module不同于我们普通的Module,它并不涉及任何Android内的开发.所以我们要对其中的build.gradle等动一番手脚.
首先我们new一个Android Library 名字为"plugins"
修改其build.gradle
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
ext.kotlin_version = '1.5.30-M1'
repositories {
maven {
url 'https://maven.aliyun.com/repository/central/'
}
google()
}
dependencies {
classpath "com.android.tools.build:gradle:7.0.2"
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath 'com.github.dcendents:android-maven-gradle-plugin:2.1'
classpath 'com.vanniktech:gradle-maven-publish-plugin:0.17.0'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
allprojects {
repositories {
maven {
url 'https://maven.aliyun.com/repository/central/'
}
google()
}
configurations.all { Configuration c ->
c.resolutionStrategy {
dependencySubstitution {
all { DependencySubstitution dependency ->
if (dependency.requested instanceof ModuleComponentSelector) {
def p = rootProject.allprojects.find { p -> p.group == dependency.requested.group && p.name == dependency.requested.module }
if (p != null) {
dependency.useTarget(project(p.path), 'selected local project')
}
}
}
}
}
}
pluginManager.withPlugin("java-library") {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
}
group("com.github.leifzhang")
version = property("plugin.version")
}
task clean(type: Delete) {
delete rootProject.buildDir
}
并在该Module下,添加settings.gradle文件
rootProject.name = "plugins"
并且修改app下的settings.gradle文件
rootProject.name = "KotlinFirst"
include ':app'
includeBuild("./plugins")
这时候,其实我们可以稍微的感知到,我们的整个pluginsModule.其实很类似与一个project了.这些都是gradle上的知识,一般我也不懂。但是这里能让插件隔离于我们整个APP项目。所以这些工作是十分有用的。
如果不懂,请去万恶之源那边找到大佬的demo照抄
然后我们在plugins中new一个Module…这里就不教学了…基础操作,名字为OnClickPlugin
然后我们开始编写我们的Plugin
很简单,只是简单的输出一个语句来验证我们的Plugins是否有被插入.
class DoubleTapPlugin : Plugin<Project> {
override fun apply(project: Project) {
//返回插件的类型
val isApp = project.plugins.hasPlugin(AppPlugin::class.java)
println("This is cool , you know -->$isApp")
return
}
companion object {
private const val EXT_NAME = "doubleTab"
}
}
那你此刻编译,并不会看到任何的改变.
因为你还没有将插件插入进去Project
,
那问题来了,我们的隔离出来的plugins不能直接被app引入从而对该类进行引用,怎么办捏?
我们看OnClickPlugin的build.gradle
dependencies先不说了,这里将这个Module,定义了一个Plugin
apply plugin: 'groovy'
apply plugin: 'kotlin'
apply plugin: 'java-gradle-plugin'
apply plugin: 'kotlin-kapt'
gradlePlugin {
plugins {
version {
// 在 app 模块需要通过 id 引用这个插件
id = 'OnClickPlugin'
// 实现这个插件的类的路径
implementationClass = 'com.aoto.onclickplugin.DoubleTapPlugin'
}
}
}
java {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
}
dependencies {
implementation gradleApi()
implementation localGroovy()
implementation project(":BasePlugin")
implementation 'commons-io:commons-io:2.6'
implementation 'org.javassist:javassist:3.27.0-GA'
implementation 'com.google.auto.service:auto-service:1.0-rc6'
kapt "com.google.auto.service:auto-service:1.0-rc6"
}
我们再看Project的build.gradle
我们就可以主要看到,在整个Project的build.gradle中对我们上方定义的插件进行了引用.
buildscript {
ext.kotlin_version = '1.5.30-M1'
repositories {
google()
maven {
url 'https://maven.aliyun.com/repository/public/'
}
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:7.0.2'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
plugins {
// 这个 id 就是在 versionPlugin 文件夹下 build.gradle 文件内定义的id
id "OnClickPlugin" apply false
id "NewDoubleTapPlugin" apply false
}
那么我们的app,Module中就可以对该插件进行引用了.
看我们的app的build.gradle
plugins {
id 'com.android.application'
}
apply plugin: 'kotlin-kapt'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-parcelize'
apply plugin: 'OnClickPlugin'
好了,当你配置完成之后,这些Plugin就被你项目引用并且插入了我们自己定义的Plugin了…
此刻你进行编译,你会在build下面发现自己的输出信息。
是不是觉得自己突然犀利了起来~ ( ✌°∀° ) !!!
无痕其实就是把我们的操作放到编译过程中,而实现这个操作靠的就是我们的自定义Plugins,这个是gradle的特性
如此,只要编译,我们的代码就是起作用.所以在整体看来,运行期间是对我们的代码没有任何感知的,这就是无痕啦~
这里主要让大家做两件事情.
构建不受当前项目引用的Plugins Module
引入该Plugins.并且验证该插件是否成功被插入
这里更需要我们去理解一个合理的Plugins如何被插入到我们的项目中
.如果我们的项目直接引入该Plugins,也不是不行。但是这样造成了依赖,对我们原本的Project是会有一定的影响的。这里让我学到了很多未曾看到过的知识.
这里的Plugins其实就已经很类似我们的Android项目了,只不过它不适用Android的东西罢了.
我们的Application再引入该Plugins. 有点类似于Project引入Project的感觉了…
就这里让我感觉到有一丢丢奇怪.但是却又非常的合理…
这里其实更多需要的是关于Gradle的知识,其实和Android没什么关系,只是Android使用了Gradle,让它具备了这样的一个功能.
OK,这里我们将其中之一讲完啦,实现了我们的编译过程执行某些代码.之后就轮到我们的transform啦~预告一下,这个是Google官方允许第三方自定义插件在dex文件前对class进行操作的接口.—>插桩入口