为 TheRouter 开发一个 IDEA 插件
❝本插件代码已全部开源,走过路过请给个star: https://github.com/kymjs/TheRouterIdeaPlugin ❞
这篇文章是假定你已经有了 idea 插件开发的入门知识,来教你如何实现一个实际项目的功能。如果你还不知道如何开发一个插件,建议先从这个链接查看官网相关文档 https://plugins.jetbrains.com/docs/intellij/welcome.html。
TheRouter 是一个移动端动态路由框架,同时支持 Android、iOS,具有高度双端一致性,可以把原本类依赖解耦为字符串依赖。
做过 Android 开发的应该都知道,页面跳转强行跟Activity.class
绑定的,所以大部分路由框架都会把class
替换成一个字符串,用字符串来解耦,但是这样一来就又变成了字符串满天飞的情况。
所以我做了这个用于自动跳转的高效辅助插件,可以直接从路由的声明处查看到哪些地方跳转到本路由,再也不用怕路由字符串满天飞了。
先想想需要哪些功能,首先页面跳转肯定是要有个导航的。类似这张图,在路由声明的地方,只需要点一下侧面的导航箭头,就能跳转到所有使用了这个路由页面的地方,并且还能标记出有哪些类用到了他。
http://therouter.cn/assets/img/image/ideaplugin1.png
对于开源项目,最麻烦的就是什么时候有新版本,新版本修复了什么问题。类似这张图,如果能有一个提醒,每次有新版本就告诉我,新版本有什么功能,修复了什么问题,跟我当前使用的版本有哪些变化,直接升级需不需要改代码,那就方便很多了。
http://therouter.cn/assets/img/image/ideaplugin1.png
TheRouter 官网本身提供了一个图形化界面的迁移工具,可以直接从其他路由迁移到TheRouter。但是使用的时候还得要额外下载一个APP,既然代码都是开源的,如果这个功能直接放在开发工具里面,那就方便多了。
https://therouter.cn/assets/img/image/TheRouterTransfer.png
在 idea 插件的开发中,有个很重要的类就是 LineMarkerProvider
,他是 Jetbrains 提供的 SDK 中的类。他是代码中每一行的标记提供者,也就对应了上面图中代码侧面的标记,是如何创建的。
比如在给 TheRouter 设计的这个插件里,就用这样的代码创建了一个侧边栏行标记:
if (allMarkerStatus[key] != STATUS_SHOWN) {
allMarkerStatus[key] = STATUS_SHOWN
val builder = NavigationGutterIconBuilder.create(getIcon(targetContent.type))
builder.setAlignment(GutterIconRenderer.Alignment.CENTER)
builder.setTargets(all)
if (targetContent.type == TYPE_ANNOTATION || targetContent.type == TYPE_ACTION) {
builder.setTooltipTitle("TheRouter:跳转到使用处")
} else {
builder.setTooltipTitle("TheRouter:跳转到声明处")
}
result.add(builder.createLineMarkerInfo(psiElement))
}
其中的 NavigationGutterIconBuilder.create()
就是创建一个侧边栏行标记,入参是一个图片资源,这里我根据要展示的类型返回了不同的资源图片。
fun getIcon(type: Int): Icon {
return when (type) {
TYPE_ANNOTATION -> IconLoader.getIcon("/icon/icon_from.png")
TYPE_NAVIGATION -> IconLoader.getIcon("/icon/icon_to.png")
TYPE_ACTION -> IconLoader.getIcon("/icon/icon_from.png")
else -> IconLoader.getIcon("/icon/icon_warn.png")
}
}
解决了显示的标记,剩下的就是找到点击标记后要跳到哪里了。
在 idea 插件的 SDK 中,还有个很重要的类就是 PsiElement
,PSI (Program Structure Interface),指程序结构接口,主要负责解析文件、创建语法、语义代码。一个 PsiElement
就表示了一个我们要处理的代码语句。
在上面代码的builder
里面有一个重要的方法是builder.setTargets()
,就表示点击这个图标后要跳到哪里,上面的代码中传入的all
是一个PsiElement
集合,如果只有一个PsiElement
,点击以后就会直接跳转,如果集合有多个元素,则会先展示一个选择框,由插件的使用方自行选择跳到哪个目标PsiElement
。
而这个all
集合的获取,也是来自另一个SDK中的方法PsiManager.getInstance(project).findFile(virtualFile)
,他可以将整个项目中的所有代码以 psi 的方式返回给你,这样你就可以根据实际需要,过滤找到跳转的目标位置了。具体使用可以看下面这段节选代码:
private fun findAllTargetPsi(
project: Project,
filePath: String?,
target: TargetContent
): Collection<TargetPsiElement> {
val allTargetPsi = HashSet<TargetPsiElement>()
val scopes = GlobalSearchScope.projectScope(project)
val allCodeFiles = FilenameIndex.getAllFilesByExt(project, "kt", scopes)
allCodeFiles.addAll(javaFiles)
for (virtualFile in allCodeFiles) {
val psiFile: PsiFile? = PsiManager.getInstance(project).findFile(virtualFile)
psiFile ?: return HashSet()
val properties = PsiTreeUtil.findChildrenOfType(psiFile, PsiElement::class.java)
properties.forEach { psiElement ->
allTargetPsi.add(TargetPsiElement(psiElement, psiFile.name))
}
}
return allTargetPsi
}
有个最简单的原因,TheRouter在设计阶段就参考了大量其他路由的设计,根据官网的描述:
❝之所以叫TheRouter 因为 The 代表了一种唯一性,我们在设计的时候就参考了全部现有的开源方案,吸取了大量优秀实现,同时补齐了各个方案的缺点。 ❞
所以本身在 API 层面,TheRouter 跟其他的路由就没有什么区别,因此迁移工具的核心就是「字符串替换」,这里替换的内容没什么好讲的,重点讲讲如何在插件里面展示一个UI弹窗。
首先第一步是创建一个AnAction
类,他也是 Jetbrains 提供的 SDK 中的类。用于在菜单栏中展示一个菜单项,就像这样:
同样SDK
也已经提供好了弹窗的API,跟开发 Android 一样,直接调用MessageDialogBuilder
就可以创建了。
class TransferAction : AnAction() {
private val routerNameList = HashMap<String, ITransfer>()
override fun actionPerformed(event: AnActionEvent) {
val project = event.project ?: return
val version = getVersion()
val file = File(desktop, fileName)
if (MessageDialogBuilder
.okCancel(
"TheRouter 一键迁移工具",
"当前项目为:$projectPath\n\n即将迁移至 TheRouter $latestVersion。迁移完成后,会在桌面生成改动日志。请注意查看:\n\n${file.absolutePath}。"
)
.noText("取消")
.yesText("开始迁移")
.icon(Messages.getInformationIcon())
.ask(project)
) {
routerNameList["ARouter"]?.transfer(projectPath, latestVersion, file)
}
}
}
本项目已基于 Apache License 2.0
协议开源,并上架插件市场,欢迎 star 与下载
GitHub:https://github.com/kymjs/TheRouterIdeaPlugin
插件下载: https://plugins.jetbrains.com/plugin/20047-therouter
https://therouter.cn/assets/img/image/TheRouterIdeaPlugin.jpg
向大家推荐下我的网站 https://www.yuque.com/xuyisheng 点击原文一键直达
专注 Android-Kotlin-Flutter 欢迎大家访问