intellij-platform-plugin-template使用笔记

开发过程中会有大量的模板方法,诸如,生成一个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

19.将生成的jar包作为一个插件安装到AndroidStudio中

20.在项目中使用

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,013评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,205评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,370评论 0 342
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,168评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,153评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,954评论 1 283
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,271评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,916评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,382评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,877评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,989评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,624评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,209评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,199评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,418评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,401评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,700评论 2 345