整合包开发
整合包(Pack)是一组 Friend + Application 的打包集合。它让用户一键装上一套搭配好的插件组合,不用一个个找。整合包本身不含可执行代码——它只是一个 manifest 加若干子插件目录。
什么时候写整合包
Section titled “什么时候写整合包”- 你做了好几个风格统一的 Friend,想打包成“系列”发布
- 你做了一个 Friend 加一个配套的 Application(比如动漫风伙伴 + 动漫风 TTS),想让用户一次装齐
- 你想给新用户一个“开箱即用”的推荐组合
整合包不是必须的——每个插件都能独立安装。它只是方便。
manifest.json
Section titled “manifest.json”{ "id": "com.example.pack.anime_collection", "type": "pack", "name": "动漫合集", "description": "三个动漫风格伙伴 + 一个动漫风 TTS", "version": "1.0.0", "author": "你的名字", "icon": "icon.png", "platforms": { "supported": ["android", "windows", "linux", "macos"] }, "plugins": { "friend": [ { "id": "com.example.friend.hatsune", "path": "friend/hatsune" }, { "id": "com.example.friend.rem", "path": "friend/rem" }, { "id": "com.example.friend.asuka", "path": "friend/asuka" } ], "application": [ { "id": "com.example.app.anime_tts", "path": "application/anime_tts" } ] }, "recommended": { "defaultFriend": "com.example.friend.hatsune", "defaultApplication": ["com.example.app.anime_tts"] }}plugins
Section titled “plugins”| 字段 | 类型 | 说明 |
|---|---|---|
friend |
object[] | 包含的 Friend 子插件列表 |
application |
object[] | 包含的 Application 子插件列表 |
每条目:
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
id |
string | 是 | 子插件 id |
path |
string | 是 | 子插件在 ZIP 内的目录路径 |
path 指向 ZIP 内的一个目录,目录内要有该子插件自己的 manifest.json 和资源文件。安装时容器把每个子插件目录复制到 plugins root——和单独安装那个插件效果一样。
recommended
Section titled “recommended”| 字段 | 类型 | 说明 |
|---|---|---|
defaultFriend |
string | 装完后默认激活的 Friend id |
defaultApplication |
string[] | 装完后默认启用的 Application id 列表 |
这是给用户的便利——装完整合包后不用手动去切 Friend 和启用 Application,容器自动按推荐设置。
Pack 的 system / uninstallable / defaultEnabled 在 PackManifest 构造函数里硬编码:
system:false(整合包永远不是系统插件)uninstallable:true(用户可以卸载整合包)defaultEnabled:false(整合包本身不需要 enable,是它的子插件需要)
manifest 里写了这三个字段也会被忽略。
ZIP 结构
Section titled “ZIP 结构”整合包的 ZIP 里,manifest.json 在根目录,子插件是目录(不是 zip):
com.example.pack.anime_collection.moodpack (ZIP)├── manifest.json├── icon.png├── friend/│ ├── hatsune/│ │ ├── manifest.json│ │ ├── system_prompt.txt│ │ ├── emoji_mapping.json│ │ └── identity.json│ ├── rem/│ │ ├── manifest.json│ │ ├── system_prompt.txt│ │ └── emoji_mapping.json│ └── asuka/│ ├── manifest.json│ ├── system_prompt.txt│ └── emoji_mapping.json└── application/ └── anime_tts/ ├── manifest.json └── main.dart每个子插件目录的结构和它单独发布时完全一样——有自己的 manifest.json 和必需文件。path 字段对应 ZIP 内的路径,比如 friend/hatsune。
容器安装整合包时(installPack()):
- 读整合包的
manifest.json,解析plugins.friend和plugins.application - 对每个引用的子插件,把
<zip内path>目录复制到 plugins root:- Friend →
<safeId>.moodfriend/ - Application →
<safeId>.moodapp/
- Friend →
- 把整合包目录本身也复制到 plugins root:
<safeId>.moodpack/ - 调
PluginManager.refresh()重新扫描
如果某个子插件目录在 ZIP 里不存在,容器会跳过它(不报错,但不安装那个子插件)。所以打包时检查 path 和实际目录一致。
卸载整合包会删除整合包目录本身。子插件不会被自动卸载——它们已经是独立的插件了,用户可以在插件管理页单独管理。这个设计让用户可以“装整合包 → 只卸载不喜欢的子插件 → 保留其余”。
以“动漫合集”为例,准备文件:
anime_collection/├── manifest.json├── icon.png├── friend/│ ├── hatsune/│ │ ├── manifest.json│ │ ├── system_prompt.txt│ │ └── identity.json│ ├── rem/│ │ ├── manifest.json│ │ └── system_prompt.txt│ └── asuka/│ ├── manifest.json│ └── system_prompt.txt└── application/ └── anime_tts/ ├── manifest.json └── main.dart打包:
cd anime_collectionzip -r ../com.example.pack.anime_collection.moodpack .
# 验证unzip -l ../com.example.pack.anime_collection.moodpack# manifest.json 在根目录,friend/hatsune/manifest.json 等在对应路径- 子插件 id 要和 path 对应的目录内 manifest id 一致。验证脚本会交叉校验。
- 子插件可以是独立发布的插件的副本。你可以把已经单独发布过的 Friend 放进整合包——用户单独装或通过整合包装都是同一个 id,不会重复安装(容器按 id 去重,同 id 会覆盖旧版本)。
- 整合包的 platforms 应该是所有子插件的交集。如果某个子插件只支持 Android,整个整合包就不应该在 Windows 上展示给用户安装。
- ZIP 根目录直接放 manifest.json 和子插件目录,不要套一层外层目录。