Android一步步实现无痕埋点(2)-------开始折磨

0.前言

Android一步步实现无痕埋点(1)-------万恶之源
https://blog.csdn.net/qq_33902817/article/details/122410168

上一篇文章,我们讲解了无痕埋点的基本概念.这里我们就开始继续讲解无痕埋点如何实现.
我们先上一个完好的插件的Module图
Android一步步实现无痕埋点(2)-------开始折磨_第1张图片

1.无痕

总所周知,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"

如下
Android一步步实现无痕埋点(2)-------开始折磨_第2张图片

并且修改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下面发现自己的输出信息。

Android一步步实现无痕埋点(2)-------开始折磨_第3张图片
是不是觉得自己突然犀利了起来~ ( ✌°∀° ) !!!
无痕其实就是把我们的操作放到编译过程中,而实现这个操作靠的就是我们的自定义Plugins,这个是gradle的特性
如此,只要编译,我们的代码就是起作用.所以在整体看来,运行期间是对我们的代码没有任何感知的,这就是无痕啦~
Android一步步实现无痕埋点(2)-------开始折磨_第4张图片

2.总结

这里主要让大家做两件事情.

构建不受当前项目引用的Plugins Module
引入该Plugins.并且验证该插件是否成功被插入

这里更需要我们去理解一个合理的Plugins如何被插入到我们的项目中.如果我们的项目直接引入该Plugins,也不是不行。但是这样造成了依赖,对我们原本的Project是会有一定的影响的。这里让我学到了很多未曾看到过的知识.
这里的Plugins其实就已经很类似我们的Android项目了,只不过它不适用Android的东西罢了.
我们的Application再引入该Plugins. 有点类似于Project引入Project的感觉了…
就这里让我感觉到有一丢丢奇怪.但是却又非常的合理…

这里其实更多需要的是关于Gradle的知识,其实和Android没什么关系,只是Android使用了Gradle,让它具备了这样的一个功能.

OK,这里我们将其中之一讲完啦,实现了我们的编译过程执行某些代码.之后就轮到我们的transform啦~预告一下,这个是Google官方允许第三方自定义插件在dex文件前对class进行操作的接口.—>插桩入口

你可能感兴趣的:(无痕埋点,android,kotlin,aop)