HmLogcat:在DevEco里打印logcat
隔了快半年没发技术blog了,混一篇 Intellij 插件开发。
最近在搞鸿蒙,申请开发者账号就可以体验他家的模拟器了,模拟器有个Hilog,也有安卓logcat,二者独立存在。
由于看 Hilog 要在 DevEco(鸿蒙专属IDE) 里看,看 logcat 要在 AndroidStudio 里看,切来切去很麻烦,于是就将 android logcat移植到了 DevEco 里。
需求分析
写一个 Intellij 全系列的插件,实现 logcat 的功能。
最开始想适配到任意的IDE,后来因为 Intellij 上实现不来,就降低要求到 DevEco 了。
测试环境
- DevEco 2.1
- Intellij 2021.1
- Android Studio 4.2.1
成品
https://github.com/LeadroyaL/HmLogcat
背景调研
众所周知,Intellij是支持安卓开发的,只是没什么人愿意用罢了。它有一个自带的插件叫做 “android”,插件包名为
org.jetbrains.android
。Android Studio 基于 Intellij 开发,底部的 Logcat 属于 Toolbar 的一部分,我猜是一个独立的模块。
AndroidStudio 是开源的,编译说明位于 https://android.googlesource.com/platform/tools/base/+/studio-master-dev/studio.md ,提到有三个仓库,稍加分析可以得知我们想要的功能位于 https://android.googlesource.com/platform/tools/adt/idea/
根据日常体验,安装第三方 plugin 确实可以在 toolbar 上添加新的按钮,难度不会太高。
Plugin 基础知识
建议看官网介绍,这里摘一些主要内容
plugin 本身是一个 jar 包,由 META-INF/plugin.xml
来描述主要功能,例如独一无二的包名、适用版本、依赖、为哪些 module 提供入口。
logcat 展示的页面其实是用 swing 来写的,按照 java gui 常规开发流程就可以。
使用 gradle 开发最为方便,官方提供了较为友好的 gradle task,例如 buildPlugin 是打包。
开发(抄代码)
将上文提到的AndroidStudio的源码 clone 回来,可以发现 public class AndroidLogcatToolWindowFactory implements ToolWindowFactory, DumbAware
刚好就是那个 toolbar 的容器,所在目录下的代码独立性很高,看起来没有什么依赖。
创建gradle项目,核心在于这个 plugin,会自动配很多环境。
1 | plugins { |
不加任何依赖,把 platform/tools/adt/idea/android/src/com/android/tools/idea/logcat
下的代码都贴过去,编译发现一些 ClassNotFound。
在 Intellij 或 AndroidStudio 的 runtime 里,发现这几个类都在的 PATH_TO_IDEA/plugins/android/lib
,缺一个补一个,当然如果懒的话可以 *.jar
都依赖进来,为了防止重复定义,需要 compileOnly(似乎重复定义也没什么)。
直到编译不报错,就可以进行测试了。
编写 plugin.xml,修改部分源码,重写一些配置防止冲突,主要是 toolWindow 的 ID。
1 | <idea-plugin> |
进行尝试
尝试1:使用 Intellij Idea 加载该插件
失败,弹 "There is no Android facets in the project"
按照猜测,Intellij 默认情况是不会启用 adb 那一套的,弹这个也比较合理。
尝试2:使用 Android Studio 加载该插件
提示类被重复定义,并且两个 class 的 JDK 版本不一致。
失败信息是在右下角红色叹号显示的,和平时 crash 的位置一致,具体在哪有其他日志,我还真不知道。
Intellij 最近在对 jre 进行升级,稍微早一点的是 Java8,新一点的是 Java11。
我编译时提示某些依赖是 JDK11,打包出来的 plugin 也是 JDK11 的。因此我将 Android Studio 升级到最新,问题解决。
尝试3:使用 DevEco Studio 加载该插件
出于顾虑,我怀疑 DevEco 里没有 org.jetbrains.android
插件,但事实上只是没有显示出来而已,不大像是被刻意隐藏,因为 Android Studio 也没有显示这个 plugin,查了半天也没查出来原因。
也罢,既然runtime 是完备的,那么插件直接加载应该也是可以的,加载后,非常完美,效果如图:
尝试4:精简代码
删除除了 GUI 之外的内容,只保留单个 AndroidLogcatToolWindowFactory
的逻辑。
这样可以避免API更替带来的影响,并且可以移除一部分依赖,减小维护成本。
测试后发现思路可行。
更进一步,其实这个 GUI 的 class 在 org.jetbrains.android
里也是有的,我们甚至可以把这个 java 代码也删掉,按理说大部分情况可以正常运行,偶尔 ID 可能会冲。
测试后发现似乎可行。
最终代码
1 | <idea-plugin> |
最终,整个 plugin 只有一个 xml 描述文件。。。却实现了预期的功能。。。
思路总结
绕了半天弯路,绕路的原因还是对 Intellij 插件开发不熟悉,对 Intellij 的 runtime 不熟悉,找对方法的话其实就很简单了。
只要 DevEco 不彻底把插件移除了,这个方法还是可以继续用的。如果移除了,那可能就要把整个runtime 都重建一遍,代价还是有点高了。