intellij-platform-plugin-templat

2023-03-22  本文已影响0人  紫鹰

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

/**

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.在项目中使用

上一篇 下一篇

猜你喜欢

热点阅读