在线版:https://api.androeq.cc/plugins.html
入口:左侧导航栏 插件。插件是独立 DLL,不链接进
androeq_win.exe;删除 DLL 即可停用。宿主只负责窗口、控件、输入、曲库导入和「今天听什么」。
1. 目录与加载#
宿主按以下目录扫描 *.dll:
<exe目录>\plugins
%APPDATA%\ANDROEQ+\plugins插件 → 打开插件目录会直接打开<exe目录>\plugins;插件 → 加载 DLL…会把选中的 DLL 复制到<exe目录>\plugins并立即加载;插件 → 新建插件生成最小 C++ 工程到%APPDATA%\ANDROEQ+\plugins\_dev\<id>,包含plugin.cpp、CMakeLists.txt、README.md、plugin.json;- 已加载的插件 id 写入
%APPDATA%\ANDROEQ+\plugins.ini的[plugins] autoload=...;
下次启动自动加载(不会自动弹窗,点「运行」才显示窗口)。
2. 最小插件#
#include "PluginApi.h"
#include <cstdio>
namespace {
const AeqHostApi* g_api = nullptr;
void* g_host = nullptr;
AeqWindowId g_win = 0;
AeqControlId g_status = 0;
void AEQ_CALL on_event(void*, AeqWindowId, AeqControlId control, int32_t ev) {
if (ev != AEQ_EV_CLICK) return;
AeqControlId btn = g_api->get_control_id(g_host, g_win, L"hello");
if (control == btn) {
g_api->set_control_text(g_host, g_status, L"按钮已点击");
}
}
void* AEQ_CALL init_plugin(const AeqHostApi* api, void* host) {
g_api = api; g_host = host;
AeqWindowDesc wd{};
wd.size = sizeof(wd);
wd.title = L"Hello";
wd.x = wd.y = -1; // -1 = 居中
wd.width = 480; wd.height = 260;
g_win = api->create_window(host, &wd);
AeqControlDesc d{};
d.size = sizeof(d); d.type = AEQ_CTL_BUTTON;
d.x = 24; d.y = 24; d.w = 160; d.h = 38;
d.id = L"hello"; d.text = L"点我";
api->add_control(host, g_win, &d);
d = {}; d.size = sizeof(d); d.type = AEQ_CTL_LABEL;
d.x = 24; d.y = 84; d.w = 400; d.h = 28;
d.id = L"status"; d.text = L"等待点击";
g_status = api->add_control(host, g_win, &d);
api->set_event_callback(host, &on_event, nullptr);
return reinterpret_cast<void*>(1);
}
void AEQ_CALL shutdown_plugin(void*) {}
void AEQ_CALL activate_plugin(void*) { g_api->show_window(g_host, g_win, 1); }
}
extern "C" __declspec(dllexport) const AeqPluginDescriptor* AEQ_CALL
androeq_plugin_entry() {
static const AeqPluginDescriptor desc = {
sizeof(AeqPluginDescriptor), AEQ_PLUGIN_API_VERSION,
L"hello", L"Hello", L"1.0.0", L"you", L"示例",
&init_plugin, &shutdown_plugin, &activate_plugin, nullptr};
return &desc;
}构建(MSVC):
cmake -S . -B build -G "Visual Studio 18 2026" -A x64
cmake --build build --config Release把 DLL 放进 plugins,在插件页点「刷新」→「加载」→「运行」。
3. 坐标与生命周期#
- 窗口 / 控件坐标单位是 96 DPI 逻辑像素,宿主按界面 DPI 和缩放自动换算;
wd.x = wd.y = -1表示居中;内置窗口相对宿主客户区,独立窗口使用屏幕坐标;wd.standalone = 0:宿主内部模态窗口,打开时背景变暗、主界面点击被拦截;wd.standalone = 1:真正的外置悬浮窗口(独立顶层 HWND,可拖出主界面、
置顶显示,不阻塞主界面);wd.user_data:创建窗口时传入任意插件上下文指针,事件里用api->get_window_user_data(host, window)取回;窗口句柄只属于创建它的插件;- 主题:
wd.theme_mode = AEQ_THEME_FOLLOW:自动使用主窗口当前主题
(主色、文字、面板、边框实时同步),颜色字段忽略;wd.theme_mode = AEQ_THEME_CUSTOM:用 `color_window / color_header /
color_border / color_text / color_muted / color_accent` 指定颜色,
格式0xAARRGGBB(可用AEQ_RGBA(r,g,b,a));某项为 0 时回退宿主颜色;
init在加载时调用;shutdown在卸载 / 退出时调用,必须在这里join掉自己的后台线程,之后宿主才FreeLibrary;activate在点「运行」时调用;没有activate时宿主显示该插件创建的第一个窗口。
4. 控件#
| 类型 | 说明 |
|---|---|
AEQ_CTL_LABEL | 文本;AEQ_CF_BOLD / AEQ_CF_ALIGN_RIGHT |
AEQ_CTL_BUTTON | 点击触发 AEQ_EV_CLICK |
AEQ_CTL_EDIT | 单行输入;AEQ_CF_PASSWORD / AEQ_CF_READONLY;回车触发 AEQ_EV_SUBMIT |
AEQ_CTL_CHECKBOX | 点击切换,触发 AEQ_EV_CHANGE |
AEQ_CTL_LIST | 换行分隔条目;点击选中触发 AEQ_EV_CHANGE,双击触发 AEQ_EV_DOUBLE_CLICK;滚轮滚动 |
AEQ_CTL_PROGRESS | value 0.0–1.0 |
AEQ_CTL_IMAGE | 显示 set_control_image 指定的图片文件 |
AEQ_CTL_SEPARATOR | 分隔线 |
控件状态 API(全部可按数字句柄或稳定字符串 id 操作):
AeqControlId id = api->get_control_id(host, win, L"query");
api->set_control_text(host, id, L"text");
api->get_control_text(host, id, buffer, capacity);
api->set_control_value(host, id, 0.75);
api->get_control_value(host, id);
api->set_control_checked(host, id, 1);
api->get_control_checked(host, id);
api->set_control_enabled(host, id, 0);
api->get_control_enabled(host, id);
api->set_control_visible(host, id, 1);
api->get_control_visible(host, id);
api->set_control_items(host, id, L"a\nb\nc");
api->get_control_items(host, id, buffer, capacity);
api->set_control_image(host, id, path);
api->set_control_focus(host, id);
api->set_control_font_size(host, id, 12.0f);
api->set_control_rect(host, id, x, y, w, h); // 歌词推挤动画
api->set_control_opacity(host, id, 0.5); // 渐隐 / 渐显这些函数是线程安全的:后台线程也可以直接 set_control_text / set_control_value,宿主会合并重绘;事件回调永远在 UI 线程触发。
5. 宿主服务#
| API | 说明 |
|---|---|
set_status(text) | 写到主窗口底部状态栏 |
add_media_file(path,title,artist) | 把已存在的本地音频加入宿主曲库(宿主在 UI 线程实际执行) |
set_today_recommendations(paths,count) | 把一组本地音频推送到曲库页「今天听什么」;SDK v2 新增,宿主会加入曲库并替换今日推荐 |
get_window_user_data(window) | 取回 AeqWindowDesc.user_data;SDK v3 新增 |
get_playback_state(state) | 当前播放状态;SDK v4 新增 |
get_current_track(title,artist) | 当前曲目标题/歌手;SDK v4 新增 |
get_current_lyric(current,next) | 当前/下一句歌词;SDK v4 新增 |
set_window_opacity(window,0..1) | 外置窗口整体透明度;SDK v5 新增 |
show_context_menu(window,items,&selected) | 原生右键菜单;SDK v5 新增 |
get_data_dir() | %APPDATA%\ANDROEQ+ |
get_plugin_dir() | <exe目录>\plugins |
open_url(url) | 用系统默认浏览器打开 |
set_clipboard_text / get_clipboard_text | 剪贴板 |
now_ms | GetTickCount64 |
log | 输出到调试器(DebugView),不弹窗 |
6. 示例插件:第三方音频导入#
源码:plugins/audio_import/(独立构建,不链接进主程序)。
功能:
- 网易云 / QQ音乐 / 酷狗 三个平台;
- 自动识别 Cookie:点「自动识别」启动独立 Edge/Chrome 配置目录并打开登录页,
通过 CDP 的Network.getAllCookies自动读取登录 Cookie、DPAPI 加密保存; - Cookie 登录:也可点「打开登录页」→ 浏览器登录 → F12 → Network → 任意请求
→ 复制Cookie→ 粘贴 → 「保存 Cookie」; - Cookie 用 Windows DPAPI 加密后保存到
%APPDATA%\ANDROEQ+\plugins\audio_import.ini,不经过任何第三方服务器; - 搜索、选中、导入选中 / 全部;优先请求无损(FLAC),接口不可用时自动回退
320k MP3 / m4a;FLAC/MP3 会写入标题、歌手、专辑和封面(FLACPICTURE+VORBIS_COMMENT,MP3ID3v2.4 + APIC); - 歌单导入:粘贴歌单链接 / ID;每日推荐:自动读取当日推荐;
- NCM 导入:可直接选择
.ncm文件,或把.ncm路径粘贴到歌单输入框;
使用与ncm2music相同的 NCM 解密算法,并回写封面 / 歌手 / 专辑; - 推到今天:把本次导入的本地歌曲推送到曲库页「今天听什么」;
- 下载到
%APPDATA%\ANDROEQ+\imports\<平台>\(NCM 为imports\ncm\),
完成后调用宿主add_media_file; - 下载进度、失败原因、成功标记(✓)都回写到控件状态。
构建:
cmake --build build --config Release --target androeq_audio_import输出 build\Release\plugins\audio_import.dll,CMake 同时复制到dist\plugins\audio_import.dll。
能力边界#
- 仅用于个人备份你有权下载的内容;不绕过付费、DRM 或平台会员限制。
- VIP / 无版权 / 需要购买的数字专辑会在解析或下载阶段失败,界面会显示原因。
- 平台接口和风控会变化;QQ音乐、酷狗的部分曲目需要登录 Cookie;酷狗移动端接口
对免费曲目返回较低码率,是否返回 FLAC 取决于账号的 SQ 权限。 - 音质以平台实际返回为准:插件先请求无损,失败时回退;不会把低码率转码伪装成无损。
- Cookie 等同账号凭据:不要分享
audio_import.ini,不要提交到仓库。
7. 示例插件:窗口 API 演示#
源码:plugins/window_demo/,产物 window_demo.dll。
wd.standalone = 1创建外置悬浮窗口;wd.theme_mode = AEQ_THEME_CUSTOM+ 六个color_*字段自定义配色;wd.user_data传入DemoContext,按钮事件里用get_window_user_data取回并更新界面;- 可在插件页「加载」→「运行」查看。
8. 内置插件:桌面歌词#
源码:plugins/lyrics_float/,产物 lyrics_float.dll,随 APP 一起放到plugins 目录。
- 创建
standalone = 1的外置悬浮窗; - 两种样式:
卡片样式/简约透明(AEQ_WF_TRANSPARENT,仅文字); theme_mode = AEQ_THEME_FOLLOW,自动同步主窗口主题;- 右键菜单切换样式 / 隐藏歌词(
show_context_menu); - 当前歌词 + 下一句直接上下排列;下一句变成当前时,旧歌词上移渐隐、
新歌词从下方挤入(set_control_rect/set_control_opacity); - 后台线程每 ~30ms 轮询播放/歌词快照,并执行推挤动画;
- 可在插件页「加载」→「运行」显示;标题栏/整个窗口可拖动,右上角关闭。
- 样式选择保存到
%APPDATA%\ANDROEQ+\lyrics_float.ini。
完整 API 参考(结构体/函数表/线程规则/示例):PLUGIN_API.md。
9. 安全 / 兼容#
- 插件拥有宿主进程权限,只加载你信任的 DLL;
PluginApi.h使用 C ABI,带size/api_version;新增函数只能追加到函数表末尾;- 卸载插件前宿主会关闭它的全部窗口并调用
shutdown,插件必须停止所有线程; - 插件异常不会自动隔离(同进程 DLL),调试时优先写
log()和%TEMP%日志。