Compose Multiplatform simplifies and accelerates UI development for Desktop and Web applications, and allows extensive UI code sharing between Android, Desktop and Web.
2021 年 12 月,JetBrains 发布了 Compose Multiplatform 1.0。本文中,我们将用到其中 Compose Desktop 来构建现代 IDEA 插件 UI。
创建 IDEA 插件项目
开发环境:IntelliJ IDEA 2022.2.2 根据 JetBrains 的开发文档里 Creating A Plugin 一章提及,有以下三种创建插件工程的方式
- Github 模板 直接从 Github clone 插件工程模板作为您的项目起点
- Gradle 使用 IDEA 提供的新建项目向导功能,创建和配置基于 Gradle 的 IntelliJ Platform 插件工程
- DevKit JetBrains 已不再推荐该方式,略
这里我们选择第二种,也是开发者最习惯的创建项目方式
File -> New -> Project, 在创建项目页,左侧 Generators 下选择 IDE Plugin 类型,然后按照您自己的需求填写基础的项目配置。注意,这里 Type 是 Plugin,Language 是 Kotlin,JDK 最好是 11,因为从 IDEA 2020.3(也就是北极狐的 base 版本) 开始,JDK 版本限制最低为 11。
IDEA 插件开发配置说明
上一步点击 create 之后,我们进入到项目中,在等待 sync 完成期间,我们先了解下关于 IDEA 插件开发常见的配置
compose_sample
├── .run
│ └── Run IDE with Plugin.run.xml
├── gradle
│ └── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── src
│ ├── main
│ │ ├── java
│ │ └── resources
│ │ └── META-INF
│ │ └── plugin.xml
│ └── test
│ ├── java
│ └── resources
├── .gitignore
├── build.gradle.kts
├── gradlew
├── gradlew.bat
└── settings.gradle.kts
上面是一个最精简的 IDEA 插件项目的目录结构,其中大部分跟其他基于 Gradle 的项目类型是一致的,例如 Android 开发者熟悉的 build.gradle.kts(注意,这里可以看到 Kotlin Script 已成为 JetBrains 默认的 Gradle 脚本语言)
我们重点介绍两个文件:
./build.gradle.kts
这个 gradle 脚本基本等同于 Android 项目中的 app/build.gradle.kts。同样的,它主要提供了以下作用:
- 导入我们需要的 Gradle plugins,项目默认引入的有 Java、Kotlin、intelliJ 等
- 对导入的 Gradle plugins 进行二次配置
- 指定 IDEA 插件的包名和版本号等信息
- 声明项目依赖及依赖仓库
- … 下面我们逐一认识这个文件里的各项配置
plugins {
id("java") // Java Gradle plugin
id("org.jetbrains.kotlin.jvm") version "1.7.10" // Kotlin Gradle plugin
id("org.jetbrains.intellij") version "1.8.0" // IntelliJ Gradle plugin,主要为 IDEA 插件开发流程提供各方面的支持,例如运行、测试、部署等
}
// 指定我们正在开发的这个 IDEA 插件的包名和版本号
group = "com.example"
version = "1.0-SNAPSHOT"
// 指定依赖仓库。可以看到下面并没有 dependencies 配置,因为默认没有依赖其他库,之后我们会逐一添加
repositories {
mavenCentral()
}
// 这里是对文件头 org.jetbrains.intellij Gradle 插件的二次配置,默认生成的以下三项,您可以理解为是配置了一个简易版本的 JetBrains IDE 环境,用来运行和调试我们正在开发的这个 IDEA 插件
intellij {
version.set("2021.3.3") // IDEA 插件运行调试版本
type.set("IC") // 指定运行在哪个 JetBrains 的 IDE 类型上,这里 IC 是 IntelliJ IDEA Community Edition 的缩写,您也可以指定 JetBrains 的其他 IDE 产品例如 CLion, PyCharm...
plugins.set(listOf(/* Plugin Dependencies */)) // 指定上面这个 IDE 环境需要自带哪些插件,默认不需要
}
tasks {
// 设置 Java/Kotlin 相关的编译选项,一般我们需要指定为 11
withType<JavaCompile> {
sourceCompatibility = "11"
targetCompatibility = "11"
}
withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile> {
kotlinOptions.jvmTarget = "11"
}
// 声明 IDEA 插件的版本支持范围
patchPluginXml {
sinceBuild.set("213") // 213 代表 2021.3
untilBuild.set("223.*") // 223.* 代表 2022.3 及任意子版本
}
signPlugin {
certificateChain.set(System.getenv("CERTIFICATE_CHAIN"))
privateKey.set(System.getenv("PRIVATE_KEY"))
password.set(System.getenv("PRIVATE_KEY_PASSWORD"))
}
publishPlugin {
token.set(System.getenv("PUBLISH_TOKEN"))
}
}
./src/main/resources/META-INF/plugin.xml
如果您是一个 Android 开发者,那此文件基本可以理解为是 AndroidManifest.xml 。plugin 主要用来声明关于插件的配置信息,包含且不限于:
- 支持的 IntelliJ Platform 版本范围
- 插件 id, 名称, 描述信息
- 更重要的,声明插件里的 Actions。不同的 action 会触发不同的事件,比如前往哪个界面,比如触发某个功能,等等 我们会在后面进一步配置 plugin.xml
OK,至此,我们初步地认识了关于 IDEA 插件开发的一些相关配置。
ps. 如果您是第一次创建 IDEA 插件项目,在 sync 过程中,除了常规的依赖之外,还会下载我们之后会在运行调试中用到的 IDE 环境,即上面 build.gradle.kts 说明里的 简易版本的 JetBrains IDE,size 大约为600mb,请耐心等候直到 sync 成功。
添加 Compose Desktop 依赖
在 build.gradle.kts 中,添加如下代码与依赖项
plugins {
...
// JetBrains Compose Gradle 插件,主要用于提供 Compose multiplatfrom 需要的依赖项配置
id("org.jetbrains.compose") version "1.2.0-beta01"
}
...
dependencies {
// 添加 Compose Desktop 需要的依赖项,compose.desktop.currentOs 这个 value 便来自于上面添加的 org.jetbrains.compose 插件
implementation(compose.desktop.currentOs)
}
sync 成功后,您会发现项目里多了许多 Compose 与 Skia 相关的依赖库
使用 Compose 编写一个简单的 hello world
这里我们简单地实现一个计数界面:即有一个文本和一个按钮,前者会显示后者的点击次数
package com.example.composesample
import androidx.compose.foundation.layout.*
import androidx.compose.material.Icon
import androidx.compose.material.OutlinedButton
import androidx.compose.material.Surface
import androidx.compose.material.Text
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.FavoriteBorder
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
@Composable
fun App() {
Surface {
Box(contentAlignment = Alignment.Center) {
Column(horizontalAlignment = Alignment.CenterHorizontally) {
// 声明 count state,接收读写
var count by remember { mutableStateOf(0) }
// Text 的内容跟随 count 变化
Text("Count: $count")
Spacer(modifier = Modifier.height(8.dp))
OutlinedButton(
onClick = {
// 每点击一次,count 加一
count += 1
}
) {
Icon(
imageVector = Icons.Default.FavoriteBorder,
contentDescription = null,
modifier = Modifier.padding(4.dp)
)
Text("Hello JetBrains!")
}
}
}
}
}
运行您的第一段 Compose 代码
在运行您的第一段 Compose 代码前,先为它添加触发显示的逻辑。
定义 Action
Action是连接各种事件(例如菜单项的点击)与功能的桥梁,类比 Android 里的 Intent
package com.example.composesample
import androidx.compose.material.MaterialTheme
import androidx.compose.ui.awt.ComposePanel
import com.intellij.openapi.actionSystem.AnActionEvent
import com.intellij.openapi.project.DumbAwareAction
import com.intellij.openapi.project.Project
import com.intellij.openapi.ui.DialogWrapper
import javax.swing.JComponent
class SampleAction : DumbAwareAction() {
override fun actionPerformed(e: AnActionEvent) {
SampleDialog(e.project).show()
}
class SampleDialog(project: Project?) : DialogWrapper(project) {
init {
title = "Compose Sample"
init()
}
override fun createCenterPanel(): JComponent? {
return ComposePanel().apply {
setBounds(0, 0, 800, 600)
setContent {
// 这里嵌入我们之前写好的计数器界面
MaterialTheme {
App()
}
}
}
}
}
}
在 plugin.xml 里注册 Action
<idea-plugin>
...
// 将下面的 action tag 内容添加到 plugin.xml 里
<actions>
<action id="ComposeSampleAction" class="com.example.composesample.SampleAction"
text="Show Compose Sample">
// 这里的作用是将此 action 添加到 IDEA tools 下拉菜单里的最后一个位置
<add-to-group group-id="ToolsMenu" anchor="last"/>
</action>
</actions>
</idea-plugin>
Run Plugin!
至此,我们的编码工作已全部完成。在运行插件之前,检查 IDEA 右上角当前的 Gradle 任务是否为 Run Plugin,然后点击运行 icon,等候构建运行成功
第一次运行成功后,会弹出如下窗口
我们需要先选择或创建一个项目才能进入平时的开发视图
进入项目后,从菜单栏 Tools -> Show Compose Sample 进入 Compose 界面
至此,我们成功在 IDEA 上运行了第一个使用 Compose 编写的插件