Spotube 插件构建与打包——Gradle 编译 Kotlin/JS 成 .smplug
构建流程总览
Spotube 插件的构建链路:
Kotlin/JS 源码
↓ (Gradle + Kotlin Multiplatform)
编译成 JavaScript (node.js target)
↓ (spotube-gradle-plugin)
与 plugin.json manifest + deps 一起打包
↓
.smplug 文件(ZIP 格式)
build.gradle.kts 配置要点
plugins {
kotlin("multiplatform") version "2.0.20"
id("dev.krtirtho.spotube.gradle-plugin") version "5.1.0" // 版本跟 Spotube 主版本走
}
kotlin {
js(IR) {
nodejs() // Zipline 运行在 Node.js runtime 里
binaries.executable()
}
}
dependencies {
jsMainImplementation("dev.krtirtho.spotube:plugin_interfaces:5.1.0")
jsMainImplementation("app.cash.zipline:zipline-kotlin:9.0.0")
}
spotubePlugin {
// plugin.json 会自动从这里生成(也可以手写放在 src/jsMain/resources/plugin.json)
pluginName = "My Awesome Plugin"
pluginId = "com.example.myplugin"
pluginVersion = "1.0.0"
author = "Your Name"
description = "Does something useful for Spotube users"
abilities = listOf("metadata", "audio") // 声明实现了哪些接口
}
执行构建:
./gradlew spotubePlugin
产物位置:build/distributions/<plugin-name>-<version>.smplug
plugin.json manifest
spotube-gradle-plugin 会自动从 Gradle DSL 生成 plugin.json,也可以手写放在 src/jsMain/resources/plugin.json(会覆盖自动生成的):
{
"id": "com.example.myplugin",
"name": "My Awesome Plugin",
"version": "1.0.0",
"author": "Your Name",
"description": "Does something useful",
"abilities": ["metadata", "audio"],
"entrypoint": "index.zipline.js"
}
关键字段:
| 字段 | 必填 | 说明 |
|---|---|---|
id | ✅ | 全局唯一,建议用反向域名(com.xxx.yyy) |
name | ✅ | 插件页显示的名称 |
version | ✅ | semver |
abilities | ✅ | Spotube 用这个做能力过滤(v5.1 新特性) |
entrypoint | ❌ | 默认是 index.zipline.js,除非你改了编译产物名 |
.smplug 文件实际结构
解压一个 .smplug 会看到:
myplugin-1.0.0.smplug
├── plugin.json # manifest
├── index.zipline.js # 编译好的 Kotlin/JS 主文件(通常 50~200KB)
└── deps/ # 外部 JS 依赖(如果有)
├── lib_a.js
└── lib_b.js
index.zipline.js 是编译器产出的"单文件"——Gradle 把所有 Kotlin 代码 + Zipline runtime 打进了这一个文件,Spotube 加载时直接 eval() 或 new Function() 这个 JS 字符串。
手动调试技巧
Spotube 侧调试
Spotube 设置 → Debug → Export debug log → 保存日志文件。插件里用 host.logger.d("my debug message") 打的日志会出现在里面。
开发者模式
Spotube 有一个隐藏的开发者模式:
# 桌面端
spotube --developer-mode
# Android:安装 Magisk 模块或用 patch 过
# 不推荐,主要给 Spotube 自身开发用
开发者模式下会显示插件加载耗时、Bridge 调用时长等内部信息。
用 console.log 直接打
由于 Zipline runtime 跑在 Node.js JS 环境里,插件里可以直接用 println() 或 console.log()(Kotlin/JS 会把 println 编译成 console.log)。Spotube 宿主会拦截这些输出写到 debug log。
手动安装 .smplug 进行调试
- 构建出
.smplug - 复制到 Spotube 插件目录:
- Windows:
%APPDATA%\Spotube\plugins\ - macOS:
~/Library/Application Support/Spotube/plugins/ - Linux:
~/.local/share/spotube/plugins/
- 启动 Spotube → 插件页 → 应该能看到你的插件
- 启用它 → 搜索 / 播放测试
热更新
Spotube 目前不支持热更新插件——改完代码需要重新构建 .smplug,然后重启 Spotube。社区讨论过为开发者模式加 reload 按钮,但还没实现。
常见构建问题
Kotlin 版本不匹配
plugin_interfaces:5.1.0 需要 Kotlin 2.0+。如果 Gradle 报兼容性错误,升级 Kotlin 版本号。
spotube-gradle-plugin 找不到
确认版本号(5.1.0 对应 Spotube v5.1),Maven Central 上可能有延迟。可以加 maven { url = uri("jitpack") } 作为备用。
index.zipline.js 不是单文件
需要在 kotlin.js { binaries.executable() } 里加 applyBinaryOptimize("binaryOptimizer") 或者手动配置 webpack 打包。spotube-gradle-plugin 默认应该帮你做了这件事。