Android Studio Plugin 开发

背景
最近,在搞 kmp 工程化的一些东西,因为官方不支持 ohos,所以其对应的 android studio plugin 也不支持 ohos
比如:创建一个 module 等等,都不会自动携带 ohos 目录
看了 kuikly 提供了一个 project 模板,但是没有提供 new module 的模板,所以,开始研究有关 new module 的插件开发
Android Studio Plugin 开发
创建工程
参考: https://plugins.jetbrains.com/docs/intellij/creating-plugin-project.html
需要先安装 plugin devkit
然后按照文档创建即可
添加本地依赖
因为我们要开发的是 android studio 插件,所以 dependency 需要选择 android studio 平台,还有对应的版本
android studio 对应的版本在这里查看:https://plugins.jetbrains.com/docs/intellij/android-studio-releases-list.html
如果依赖添加的是对应版本,则会自动下载对应版本的 android studio,如果我们本地存在一个版本的 android studio,则可以从本地依赖,完全没必要下载
配置如下:
dependencies {
intellijPlatform {
// 本地路径
local("/Applications/Android Studio.app/Contents")
// 添加一些打在 andorid studio 内部的插件
// 不然有些代码,我们无法引用
bundledPlugins(listOf(
"com.intellij.java",
"org.jetbrains.kotlin",
"org.jetbrains.android",
))
}
}
接下来就是进入开发的步骤了
IDEA 的 New Module 开发
查了很多网上的教程,都是对于 action 的开发
这块我自己验证了下没什么问题
但是,当我想开发 New Module 的界面,增加下图中红色部分的一个 type 的时候,遇到了困难
官方文档如下:文档链接
简单介绍一下就是:
- 添加一个 module type
- 实现 module type 和 module builder
然后就可以了
按照文档介绍以后,我如果将上面的 dependency 的配置改成 IDEA,确实可以看到,new module 多了一个 type
但是,android studio 纹丝不动
Android Studio 的 New Module 开发
尝试了半天,无功而返,只好去查看 andorid studio 的源码,提供一个可以预览源码的网址 链接
经过不懈努力,最终,发现了如下配置
<extensions defaultExtensionNs="com.android">
<moduleDescriptionProvider implementation="com.XXXXX"/>
</extensions>
通过 copy 相关代码到我自己的工程中,最终实现了 andorid studio 中增加一个 module type 的能力
部分核心代码
需要继承自 ModuleDescriptionProvider
,并且实现其 ModuleGalleryEntry
,然后就进入到了正常的 create step 步骤
create step 也需要继承自 ConfigureModuleStep
重写其 createMainPanel
,也就是我们的 UI 界面
同时,需要绑定一个 Model,model 又有一些 render 方法,负责渲染对应模板
其实,我们没必要这么复杂,可以简化一些操作
部分 copy 过来的核心代码如下:
// plugin.xml 中注册 moduleDescriptionProvider
<extensions defaultExtensionNs="com.android">
<moduleDescriptionProvider implementation="com.XXX.TestModuleDescriptionProvider"/>
</extensions>
class TestModuleDescriptionProvider : ModuleDescriptionProvider {
override fun getDescriptions(project: Project): Collection<ModuleGalleryEntry> = listOfNotNull(
if (StudioFlags.NPW_NEW_KOTLIN_MULTIPLATFORM_MODULE.get()) KotlinMultiplatformLibraryModuleTemplateGalleryEntry() else null,
)
// copy from kmp plugin
private class KotlinMultiplatformLibraryModuleTemplateGalleryEntry : ModuleGalleryEntry {
override val name: String = "Your Library Name"
override val description: String = "your library escription"
override val icon: Icon = IconLoader.getIcon("/icons/your_icon.png", this::class.java.classLoader)
// 重写 createStep
override fun createStep(project: Project, moduleParent: String, projectSyncInvoker: ProjectSyncInvoker): SkippableWizardStep<*> {
// 这里我是想创建一个类似 kmp plugin 的 module type
return ConfigureKmpLibraryModuleStep(
KmpModel(project, moduleParent, projectSyncInvoker), name)
}
}
}
class ConfigureKmpLibraryModuleStep(
model: KmpModel,
title: String,
) : ConfigureModuleStep<KmpModel>( model,
FormFactor.MOBILE,
SdkVersionInfo.LOWEST_ACTIVE_API,
title = title) {
// UI 界面
override fun createMainPanel(): DialogPanel =
panel {
row(contextLabel("Module name", AndroidBundle.message("android.wizard.module.help.name"))) {
cell(moduleName).align(AlignX.FILL)
}
row("Package name") { cell(packageName).align(AlignX.FILL) }
}.withBorder(empty(6))
override fun onProceeding() {
super.onProceeding()
model.template.set(
// 创建自己的 template
// 需要继承
)
}
override fun getPreferredFocusComponent() = moduleName
}
class KmpModel(
project: Project,
moduleParent: String,
projectSyncInvoker: ProjectSyncInvoker,
name: String = "shared",
) :
ModuleModel(
name = name,
commandName = "New Kotlin Multiplatform Library Module",
isLibrary = true,
_template = GradleAndroidModuleTemplate.createMultiplatformModuleTemplate(project, name),
projectModelData = ExistingProjectModelData(project, projectSyncInvoker),
moduleParent = moduleParent,
wizardContext = AndroidStudioEvent.TemplatesUsage.TemplateComponent.WizardUiContext.NEW_MODULE,
) {
override val renderer: MultiTemplateRenderer.TemplateRenderer =
object : ModuleTemplateRenderer() {
@WorkerThread
override fun init() {
super.init()
moduleTemplateDataBuilder.apply {
commonSrcDir =
(template.get().paths as KotlinMultiplatformModulePathsImpl).getCommonSrcDirectory(
this@KmpModel.packageName.get()
)
iosSrcDir =
(template.get().paths as KotlinMultiplatformModulePathsImpl).getIosSrcDirectory(
this@KmpModel.packageName.get()
)
}
}
// 这部分的调用没有详细去看,强行塞了个 ohos dir 进去
override val recipe: Recipe
get() = { td: TemplateData ->
val ohosSrcDir = (template.get().paths as KotlinMultiplatformModulePathsImpl).getOHOSSrcDirectory(
this@KmpModel.packageName.get()
)
generateCTModule(this, data = td as ModuleTemplateData, ohosSrcDir, useKts = true, generateManifest())
}
}
}
总结
想给 Android Studio 添加 Module Type,按照 Intellij SDK 添加 Module Type 是不行的
对于新版本的 Android Studio,需要注册 moduleDescriptionProvider,并且参照 kmp plugin 来实现 moduleDescriptionProvider 对应逻辑
如果需要额外定制目录等等,则需要自己深入修改