Android Studio自定义页面模板

历史背景

随着Android原生环境的丰富多彩,诞生了很多的架构,比如我们熟悉的MVC、MVP、MVVM,还有MVI,然而使用这些架构不得已会新建很多类文件(项目结构会更加清晰),MVC我们会新建Activity/Fragment、Model、Controller、View的布局文件,MVP会新建Activity/Fragment、Model、Presenter、View的布局文件,MVVM会新建Activity/Fragment、Model、ViewModel、View的布局文件。随着我们项目页面越来越多,新建起文件来就会愈加觉得繁琐。

谷歌爸爸或许早就认识到了我们的耐心是有限的,从很早开始就为我们提供了创建Activivity/Fragment的项目模板,File -> New -> Activity/Fragment就会看到,瞬间热泪盈眶。。。。

Android Studio自定义页面模板_第1张图片

Android Studio自定义页面模板_第2张图片

可以看到谷歌提供了不少模板,下面来举个例子,看看怎么用这些模板。
File -> New -> Activity -> Empty Activity可以看到

Android Studio自定义页面模板_第3张图片

Activity Name:即新建页面的名称。
Generate a Layout File:是否创建布局文件。
Layout Name:即新建布局文件的名称。
Laucher Activity:即是否运行这个Activity。
Package name:即新建页面所在的包名。
Source Language:即新建页面所使用的语言。

修改上述这些参数,然后点击Finish就可以看到AS已经在为我们创建Activity以及布局文件了,AndroidManifest.xml里也会有相应的声明添加进来。

自定义模板

谷歌提供的创建页面的模板在我们不使用架构的前提下是可以很方便的解决我们的问题的,但是如果我们使用了架构,而且是自己封装的框架,那么谷歌提供的模板就不是那么方便了,于是从5年前就有开发大佬开始为自己的框架提供页面生成模板,例如JessYanCoding的MvpArms,不仅为单一页面提供了模板,还为整个module的创建提供了模板,在这里为拥护开源精神默默付出的大佬们致敬。

依据MVPArmsTemplate创建页面的方式,只需要我们把自定义的模板放在AS安装目录\plugins\android\lib\templates\activities里,然后重启AS即可使用,这种方式在Android Studio版本4.0以下是没有问题的,然而随着AS版本的更新,AS安装目录里已经没有了对应的模板文件夹,也就不允许我们这样操作了。后来找Issue发现也有同学遇到了同样的问题,并且已经找到了解决方法AndroidStudio4.1 自定义模板。我也就顺其自然的去照葫芦画瓢,意外顺利的撸了一个框架模板,下面说一下具体步骤:

打开Template repository for creating plugins for IntelliJ Platform 点击绿色的#Use this template#按步骤在自己的github上创建模板。然后使用AndroidStudio 将模板下载到本地。
(截止到本文写的时间2021/11/29该模板版本是1.1.0 使用的IDE版本是2021.2.3,java环境:java11)

添加wizard-template.jar

在根目录里添加lib文件夹,并添加AndroidStudio安装目录里的wizard-template.jar,位于 /Applications/Android Studio.app/Contents/plugins/android/lib/目录下。

修改build.gradle.kts

在dependencies里添加wizard-template.jar的依赖

dependencies {
    detektPlugins("io.gitlab.arturbosch.detekt:detekt-formatting:1.18.1")
    compileOnly(files("lib/wizard-template.jar"))
}

修改gradle.properties

修改gradle.properties中的pluginGroup, pluginName_, platformPlugins, platformVersion。
pluginSinceBuild表示插件适配的最低版本,pluginUntilBuild表示插件适配的最高版本。
踩坑注意:pluginSinceBuild不是说想适配到哪个版本就可以适配的,跟对应Android Studio的JDK版本需保持一直,太低不支持。

# IntelliJ Platform Artifacts Repositories
# -> https://plugins.jetbrains.com/docs/intellij/intellij-artifacts.html

pluginGroup = me.soushin
pluginName = tin-mvvm
# SemVer format -> https://semver.org
pluginVersion = 1.0.71

# See https://plugins.jetbrains.com/docs/intellij/build-number-ranges.html
# for insight into build numbers and IntelliJ Platform versions.
pluginSinceBuild = 201
pluginUntilBuild = 213.*
pluginVerifierIdeVersions = 2020.2.4, 2020.3.4, 2021.1
# IntelliJ Platform Properties -> https://github.com/JetBrains/gradle-intellij-plugin#intellij-platform-properties
platformType = IC
platformVersion = 2020.2.4

# Plugin Dependencies -> https://plugins.jetbrains.com/docs/intellij/plugin-dependencies.html
# Example: platformPlugins = com.intellij.java, com.jetbrains.php:203.4449.22
platformPlugins = java, com.intellij.java, org.jetbrains.android, android, org.jetbrains.kotlin

# Java language level used to compile sources and to generate the files for - Java 11 is required since 2020.3
javaVersion = 11

# Gradle Releases -> https://github.com/gradle/gradle/releases
gradleVersion = 7.3

# Opt-out flag for bundling Kotlin standard library.
# See https://plugins.jetbrains.com/docs/intellij/kotlin.html#kotlin-standard-library for details.
# suppress inspection "UnusedProperty"
kotlin.stdlib.default.dependency = false

修改MyProjectManagerListener

将默认的listeners的父包名,调整为自己想要的样子,例如me.soushin。修改MyProjectManagerListener。

internal class MyProjectManagerListener : ProjectManagerListener {

    override fun projectOpened(project: Project) {
        projectInstance = project
        project.getService(MyProjectService::class.java)
    }

    override fun projectClosing(project: Project) {
        projectInstance = null
        super.projectClosing(project)
    }

    companion object {
        var projectInstance: Project? = null
    }
}

在src/main/kotlin里创建tinmvvm文件夹用于放置自定义模板

Android Studio自定义页面模板_第4张图片

正式开始编写自定义模板,以Activity为例。

1. 实现WizardTemplateProvider

SamplePluginTemplateProviderImpl

package me.soushin.tinmvvm

import com.android.tools.idea.wizard.template.Template
import com.android.tools.idea.wizard.template.WizardTemplateProvider
import me.soushin.tinmvvm.activity.mvvmActivityTemplate
import me.soushin.tinmvvm.fragment.mvvmFragmentTemplate

class SamplePluginTemplateProviderImpl: WizardTemplateProvider() {
    override fun getTemplates(): List