需求背景
- 最近做了个需求,是需要将EventBus集成到自己的项目中,由于我们是做SDK的,提供给用户的库不能有太多的第三方依赖库,否则别人接入你的SDK的时候容易发送冲突,我们将不使用gradle进行依赖,而转用EventBus源码的方式,为了提升EventBus的执行效率,还引入了apt,下面我们来说下具体的实践吧
了解EventBus
- 首先我们找到EventBus的官网,对其基本使用有个大概的了解:EventBus: Events for Android - Open Source by greenrobot
- 我们的首要目标是找到源码,然后根据需要去使用相关的代码:https://github.com/greenrobot/EventBus
- 关于EventBus源码的解析网上有很多,这个我就不多叙说了
EventBus源码集成
- 我们使用git clone https://github.com/greenrobot/EventBus.git将源码copy到本地,然后使用Android studio 打开,然后将需要用到的源码拷贝的我们定义好的项目包名下
- 在我们的项目里面建一个模块,比如就叫lcqlib,然后将EventBus上面两个modul里面的源码拷贝到 com.lcq.lcqlib.msgbus包路径下
- 然后我们需要将报的红色异常给解决掉,下面提供一个快速的查找替换方式
- 这样可以找到所有使用的地方进行全部替换
- 使用Replace All 就可以替换所有的代码了,我们再找到AndroidDependenciesDetector类
- 然后搜索“org.greenrobot.eventbus”将这个位置替换为“com.lcq.lcqlib.msgbus.org.greenrobot.eventbus”,要不后面执行时会抛异常
- 然后我们再assemble一下module,能正常编译过就可以了,为方便使用,我们有比较将这个库打包一下,由于只有源码没有资源文件,我们直接打包成jar包吧,这个jar在后面我们说apt的时候也会用到
- 要方便的生成jar并且定义名称,最好的方式就是写个task运行最好了
- makejar就是用来生成我们所需要jar的
task makeJar(group: 'build', type: Copy) { String libName = "${project.name}_3.3.2.jar" delete "build/libs/${libName}" from('build/intermediates/aar_main_jar/release') into('build/libs/') include('classes.jar') rename('classes.jar', libName) } makeJar.dependsOn(build)
我们执行makejar的task会生成一个lcqlib_3.3.2.jar已备后续使用
EventBus的APT源码集成
- 我们为了提高EventBus代码执行的效率,还需要使用APT方式,关于EventBus的APT的使用可以 参考这个Subscriber Index - Open Source by greenrobot
- 官网的使用方式是这样的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | android { defaultConfig { javaCompileOptions { annotationProcessorOptions { arguments = [ eventBusIndex : 'com.example.myapp.MyEventBusIndex' ] } } } } dependencies { def eventbus_version = '3.2.0' implementation "org.greenrobot:eventbus:$eventbus_version" annotationProcessor "org.greenrobot:eventbus-annotation-processor:$eventbus_version" } |
- 当然,这样的方式对于我们源码的使用方式肯定是不行的,EventBus的apt是针对自己的源码来进行注解实现的,现在我们已经将源码包名都给改了肯定是不行的,现在我们就需要自己模仿EventBus的APT源码进行实现了,其实很简单,下面我们来实现以下
- 首先找到EventBus源码项目里面的EventBusAnnotationProcessor工程,然后将里面的源码拷贝出来
- 我们在自己的项目里面建一个java library 类型的module,然后将 EventBusAnnotationProcessor的源码拷贝进来
- 可以看到报红了,里面就一个类,我们看看报红的地方
- 应该是缺少某些依赖并且里面的import org.greenrobot.eventbus.Subscribe需要替换为我们自己定义的类,将上面生成的lcqlib_3.3.2.jar拷贝到lcqlib的lib目录下,import依赖为com.lcq.lcqlib.msgbus.org.greenrobot.eventbus.Subscribe和com.lcq.lcqlib.msgbus.org.greenrobot.eventbus.ThreadMode,
- 然后我们再看看EventBusAnnotationProcessor 类的源码,搜索“import org.greenrobot.eventbus.”,我们需要将这个代码替换成“com.lcq.lcqlib.msgbus.org.greenrobot.eventbus.”,这样做的目的是使用我们自己源码里面的类,否则后面会报找不类的异常
- 修改后的代码
- 还需修改下这个注解的地方,也改成我们源码的包名
- 修改完源码后我们需要将EventBusAnnotationProcessor这个类的带包名全路径配置到res/META-INFO/services/javax.annotation.processing.Processor这个文件中,这个很重要,如果不配置,后面使用apt的时候将不起作用,如下图所示
- 接下来还需要在lcqapt模块build.gradle中配置apt所依赖的第二三方库了。如下
apply plugin: 'java' group = rootProject.group version = rootProject.version java.sourceCompatibility = JavaVersion.VERSION_1_8 java.targetCompatibility = JavaVersion.VERSION_1_8 dependencies { implementation files('libs/lcqlib_3.3.2.jar') implementation 'de.greenrobot:java-common:2.3.1' // Generates the required META-INF descriptor to make the processor incremental. def incap = '0.2' implementation "net.ltgt.gradle.incap:incap:$incap" implementation "net.ltgt.gradle.incap:incap-processor:$incap" annotationProcessor "net.ltgt.gradle.incap:incap-processor:$incap" } sourceSets { main { java { srcDir 'src' } resources { srcDir 'res' } } } javadoc { title = "EventBus Annotation Processor ${version} API" options.bottom = 'Available under the Apache License, Version 2.0 - <i>Copyright © 2015-2020 <a href="https://greenrobot.org">greenrobot.org</a>. All Rights Reserved.</i>' } task javadocJar(type: Jar, dependsOn: javadoc) { archiveClassifier.set("javadoc") from 'build/docs/javadoc' } task sourcesJar(type: Jar) { archiveClassifier.set("sources") from sourceSets.main.allSource } apply plugin: 'com.github.johnrengelman.shadow' shadowJar { manifest { //main方法所在的类 } }
- dependencies{} 里面配置了用到的依赖库
- sourceSets 里面配置了 “src”和“res”路径
- apply plugin: 'com.github.johnrengelman.shadow' 用来将生成的apt 打包成一个jar包,使用这个gradle插件还需要在根目录的build.gradle做如下配置
// Top-level build file where you can add configuration options common to all sub-projects/modules. buildscript { repositories { google() jcenter() //shadow插件用到的仓库 mavenCentral() } dependencies { classpath "com.android.tools.build:gradle:7.0.3" //shadow 插件的配置 classpath 'com.github.jengelman.gradle.plugins:shadow:4.0.0' // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files } } task clean(type: Delete) { delete rootProject.buildDir }
- 配置好后我们执行下shadowJar task,会生成我们需要的apt 插件jar包
- 我们把生成的lcqapt.jar拷贝到需要使用的模块或者项目中,然后进行配置就能使用了
如何使用自己构建的EventBus和apt库
- 上面的一系列操作,主要新建了lcqlib和lcqapt两个库,生成的jar包产物为lcqlib_3.3.2.jar和lcqapt.jar,下面我们就来在demo中看下如何使用
- 首先肯定是需要在项目中引入我们生成的jar包了,将lcqlib_3.3.2.ja拷贝到libs目录,将lcqapt.jar拷贝到libs_apt目录,lcqapt.jar不拷贝到libs目录主要是为了不让其生成apk或者aar包的时候编译进行去,这个只是用来为我们生成代码的,只在编译阶段使用
- 然后在app的build.gradle里面配置依赖,以及要生成的类
plugins { id 'com.android.application' } android { compileSdk 30 defaultConfig { applicationId "com.lcq.lcqeventbus" ... javaCompileOptions { annotationProcessorOptions { //指定辅助索引类的名称和包名 EventBus config arguments = [eventBusIndex: 'com.lcq.lcqeventbus.MyEventBusIndex'] } } } ... } dependencies { ... //EventBus config api files("libs/lcqlib_3.3.2.jar") annotationProcessor files("/libs_apt/lcqapt.jar") }
- 配置完成后,就需要编写代码了,我们再app模块里面的MainActivity里进行测试,编写如下代码,如果对EventBus的使用还不清楚,可以去官网学习下
package com.lcq.lcqeventbus; import androidx.appcompat.app.AppCompatActivity; import android.os.Bundle; import android.view.View; import android.widget.Toast; import com.lcq.lcqlib.msgbus.org.greenrobot.eventbus.EventBus; import com.lcq.lcqlib.msgbus.org.greenrobot.eventbus.Subscribe; public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); EventBus.builder() .addIndex(new MyEventBusIndex()) .installDefaultEventBus(); EventBus.getDefault().register(this); } @Subscribe public void handleMsg(String msg) { Toast.makeText(this, "msg:" + msg, Toast.LENGTH_LONG).show(); } public void onClick(View v) { EventBus.getDefault().post("HELLO,EventBus APT"); } }
-
运行后的结果,如下:
总结: 整个过程还是比较繁琐的,也有很多容易出错的地方,还用到了很多第三方gradle插件或脚本,不过只要搭建好了这个框架,后期基本就不会怎么变化了,使用起来和原生的EventBus 几乎一模一样,达到了修改源码包名的目的,这样发出去的SDK也不会担心和接入方的有冲突了,还可以根据自己的需求修改EventBus源码,这样就把EventBus的轮子集成到我们自己项目中了