开发过程中会有大量的模板方法,诸如,生成一个Fragment的时候,需要同时生成一个ViewModel以及一个fragment_layout。同时,在这三个文件内部会生成一些模板方法。这里介绍的intellij-platform-plugin-template就是通过自定义插件的方式,一键批量生成模板方法。
这里记录一下使用步骤,方便以后查阅
模板地址
https://github.com/JetBrains/intellij-platform-plugin-template
自定义模板插件过程
1.打开模板地址
https://github.com/JetBrains/intellij-platform-plugin-template
2.登录Github,然后点击绿色Use this template按钮。选择Create a new repository,创建自己的仓库。
3.将模板仓库clone到本地,用AndroidStudio打开
4.打开android studio目录,找到wizard-template.jar文件
文件位置为:AS目录\plugins\android\lib。
5.将wizard-template.jar复制到模板工程的lib文件夹下
6.修改build.gradle.kts配置依赖,引入wizard-template.jar
dependencies {
compileOnly(files("lib/wizard-template.jar"))
}
7.修改MyProjectManagerListener文件
package com.github.vhawkmi.sk.listeners
import com.intellij.openapi.components.service
import com.intellij.openapi.project.Project
import com.intellij.openapi.project.ProjectManagerListener
import com.github.vhawkmi.sk.services.MyProjectService
internal class MyProjectManagerListener : ProjectManagerListener {
override fun projectOpened(project: Project) {
projectInstance = project
project.getService(MyProjectService::class.java)
// project.service<MyProjectService>()
// System.getenv("CI")
// ?: TODO("Don't forget to remove all non-needed sample code files with their corresponding registration entries in `plugin.xml`.")
}
override fun projectClosing(project: Project) {
projectInstance = null
super.projectClosing(project)
}
companion object {
var projectInstance : Project ?= null
}
}
8.注释MyApplicationService中的TODO
package com.github.vhawkmi.sk.services
import com.github.vhawkmi.sk.MyBundle
class MyApplicationService {
init {
println(MyBundle.message("applicationService"))
// System.getenv("CI")
// ?: TODO("Don't forget to remove all non-needed sample code files with their corresponding registration entries in `plugin.xml`.")
}
}
9.注释MyProjectService中的TODO
package com.github.vhawkmi.sk.services
import com.intellij.openapi.project.Project
import com.github.vhawkmi.sk.MyBundle
class MyProjectService(project: Project) {
init {
println(MyBundle.message("projectService", project.name))
// System.getenv("CI")
// ?: TODO("Don't forget to remove all non-needed sample code files with their corresponding registration entries in `plugin.xml`.")
}
/**
* Chosen by fair dice roll, guaranteed to be random.
*/
fun getRandomNumber() = 4
}
10.修改gradle.properties版本号与插件平台
pluginVersion = 0.0.2
platformPlugins = java, com.intellij.java, org.jetbrains.android, android, org.jetbrains.kotlin
11.修改plugin.xml
<!-- Plugin Configuration File. Read more: https://plugins.jetbrains.com/docs/intellij/plugin-configuration-file.html -->
<idea-plugin>
<id>com.github.vhawkmi.sk</id>
<name>IntelliJ Platform Plugin sk</name>
<vendor>vhawkmi</vendor>
<!-- Product and plugin compatibility requirements -->
<!-- https://www.jetbrains.org/intellij/sdk/docs/basics/getting_started/plugin_compatibility.html -->
<depends>org.jetbrains.android</depends>
<depends>org.jetbrains.kotlin</depends>
<depends>com.intellij.modules.java</depends>
<depends>com.intellij.modules.platform</depends>
<extensions defaultExtensionNs="com.intellij">
<applicationService serviceImplementation="com.github.vhawkmi.sk.services.MyApplicationService" />
<projectService serviceImplementation="com.github.vhawkmi.sk.services.MyProjectService" />
</extensions>
<applicationListeners>
<listener class="com.github.vhawkmi.sk.listeners.MyProjectManagerListener" topic="com.intellij.openapi.project.ProjectManagerListener" />
</applicationListeners>
</idea-plugin>
接下来就是开发插件的过程了
12.创建Provider
在kotlin目录下创建开发包,名字自己起,比如generator
创建文件夹generator/template
package com.github.vhawkmi.sk.generator
import com.android.tools.idea.wizard.template.Template
import com.android.tools.idea.wizard.template.WizardTemplateProvider
/**
@ProjectName: sk
-
@Description: java类作用描述
*/
class PluginGeneratorProvider : WizardTemplateProvider() {override fun getTemplates(): List<Template> = listOf(
)
}
13.在plugin.xml中注册改provider
<!-- Plugin Configuration File. Read more: https://plugins.jetbrains.com/docs/intellij/plugin-configuration-file.html -->
<idea-plugin>
<其他配置不再赘述>
<extensions defaultExtensionNs="com.android.tools.idea.wizard.template">
<wizardTemplateProvider implementation="com.github.vhawkmi.sk.generator.PluginGeneratorProvider" />
</extensions>
</idea-plugin>
14.创建文件模板
在文件夹虾创建文件FragmentTemplate.kt
package com.github.vhawkmi.sk.generator.template.fragment
fun simpleFragmentTemplate(packageName : String,modelName : String,viewName : String,desc : String) = """
package ${packageName}.ui
import android.os.Bundle
import androidx.fragment.app.viewModels
import androidx.recyclerview.widget.LinearLayoutManager
import com.qiuku8.android.R
import com.qiuku8.android.databinding.Fragment${modelName}Binding
import ${packageName}.viewmodel.${modelName}ViewModel
import com.qiuku8.android.ui.base.BaseBindingFragment
/**
*
* @Description: ${desc}
*/
class ${modelName}Fragment : BaseBindingFragment<Fragment${modelName}Binding>() {
private val viewModel: ${modelName}ViewModel by viewModels()
private var mAdapter = ${modelName}Adapter()
override fun getLayout(): Int {
return R.layout.${viewName}
}
override fun initDatas(savedInstanceState: Bundle?) {
lifecycle.addObserver(viewModel)
addObserver()
}
private fun addObserver() {
viewModel.uiStatusLiveData.observe(this){uiStatus ->
uiStatus.loadingStatus?.let { loadingStatus ->
binding.layoutLoading.status = loadingStatus
}
uiStatus.noMoreData?.let { noMore ->
binding.layoutRefresh.setNoMoreData(noMore)
}
uiStatus.isRefreshing?.let {
binding.layoutRefresh.finishRefresh()
binding.layoutRefresh.finishLoadMore()
}
// todo 特征处理
}
}
override fun initViews() {
binding.layoutLoading.setOnReloadListener {
// todo reload
}
binding.layoutRefresh.setEnableRefresh(true)
binding.layoutRefresh.setEnableLoadMore(true)
binding.layoutRefresh.setOnRefreshListener {
// todo refresh
}
binding.recycleContent.let {
it.layoutManager = LinearLayoutManager(requireActivity())
it.adapter = mAdapter
}
}
override fun initEvents() {
}
}
"""
LayoutFragmentTemplate.kt文件
package com.github.vhawkmi.sk.generator.template.layout
fun simpleLayoutTemp(desc : String) = """
<?xml version="1.0" encoding="utf-8"?>
<layout>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<xxxx需要的布局文件,这里不举例子了>
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
"""
这些文件,按需生成即可
15.创建写入类SimpleFragmentRecipe.kt
package com.github.vhawkmi.sk.generator
import com.android.tools.idea.wizard.template.Language
import com.android.tools.idea.wizard.template.ModuleTemplateData
import com.android.tools.idea.wizard.template.RecipeExecutor
import com.github.vhawkmi.sk.generator.template.bean.simpleUiStatusTemplate
import com.github.vhawkmi.sk.generator.template.fragment.simpleFragmentTemplate
import com.github.vhawkmi.sk.generator.template.layout.simpleLayoutTemp
import com.github.vhawkmi.sk.generator.viewmodel.simpleViewModelTemplate
fun RecipeExecutor.simpleFragmentRecipe(
moduleData: ModuleTemplateData,
packageName: String,
modelName: String,
layoutName: String,
desc: String,
language: Language
) {
val (projectData, srcOut, resOut) = moduleData
val ktOrJavaExt = language.extension
if (language == Language.Kotlin) {
// 生成 Fragment
save(
simpleFragmentTemplate(packageName = packageName, modelName = modelName, viewName = layoutName, desc = desc),
srcOut.resolve("ui/${modelName}Fragment.${ktOrJavaExt}")
)
// 生成 ViewModel
save(simpleViewModelTemplate(packageName, modelName, desc), srcOut.resolve("viewmodel/${modelName}ViewModel.${ktOrJavaExt}"))
// 生成UIStatus
save(simpleUiStatusTemplate(packageName, modelName, desc), srcOut.resolve("bean/${modelName}UiStatus.${ktOrJavaExt}"))
//生成 fragment_layout
save(simpleLayoutTemp(desc), resOut.resolve("layout/${layoutName}.xml"))
}
}
16.创建生成器SimpleFragmentGenerator.kt
package com.github.vhawkmi.sk.generator
import com.android.tools.idea.wizard.template.*
import com.android.tools.idea.wizard.template.impl.activities.common.MIN_API
import com.github.vhawkmi.sk.defaultPackageNameParameter
val simpleFragmentGenerator
get() = template {
name = "mmvm fragment"
description = "生成mmvm框架的Fragment和layout以及viewmodel"
minApi = MIN_API
category = Category.Fragment
formFactor = FormFactor.Mobile
screens = listOf(WizardUiContext.ActivityGallery, WizardUiContext.MenuEntry, WizardUiContext.NewProject, WizardUiContext.NewModule)
val modelName = stringParameter {
name = "Model Name"
default = "XxxModel"
help = "请输入model的名字"
constraints = listOf(Constraint.NONEMPTY)
}
val layoutName = stringParameter {
name = "layout name"
default = "fragment_xxx"
help = "请输入布局的名字"
constraints = listOf(Constraint.LAYOUT, Constraint.UNIQUE, Constraint.NONEMPTY)
suggest = { "fragment_${camelCaseToUnderlines(modelName.value)}" }
}
val descName = stringParameter {
name = "Desc Name"
default = "描述信息"
help = "请输入描述"
constraints = listOf(Constraint.NONEMPTY)
}
val language = enumParameter<Language> {
name = "Source Language"
help = "请选择语言"
default = Language.Kotlin
}
val packageName = defaultPackageNameParameter
widgets(
TextFieldWidget(modelName),
TextFieldWidget(layoutName),
TextFieldWidget(descName),
PackageNameWidget(packageName),
EnumWidget(language)
)
recipe = {
simpleFragmentRecipe(
moduleData = it as ModuleTemplateData,
packageName = packageName.value,
modelName = modelName.value,
layoutName = layoutName.value,
desc = descName.value,
language = language.value
)
}
}
17.Provider中添加代码生成器
package com.github.vhawkmi.sk.generator
import com.android.tools.idea.wizard.template.Template
import com.android.tools.idea.wizard.template.WizardTemplateProvider
class PluginGeneratorProvider : WizardTemplateProvider() {
override fun getTemplates(): List<Template> = listOf(
simpleFragmentGenerator,
)
}
18.打包
设置RunConfig为Run Plugin,运行 run plugin