AE ANDROEQ+文档

ANDROEQ+ 插件系统(SDK v6)

在线版:https://api.androeq.cc/plugins.html

入口:左侧导航栏 插件。插件是独立 DLL,不链接进 androeq_win.exe;

删除 DLL 即可停用。宿主只负责窗口、控件、输入、曲库导入和「今天听什么」。

1. 目录与加载#

宿主按以下目录扫描 *.dll:

text
<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. 最小插件#

cpp
#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):

bat
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_PROGRESSvalue 0.0–1.0
AEQ_CTL_IMAGE显示 set_control_image 指定的图片文件
AEQ_CTL_SEPARATOR分隔线

控件状态 API(全部可按数字句柄或稳定字符串 id 操作):

cpp
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_msGetTickCount64
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 会写入标题、歌手、专辑和封面(FLAC PICTURE +
    VORBIS_COMMENT,MP3 ID3v2.4 + APIC);
  • 歌单导入:粘贴歌单链接 / ID;每日推荐:自动读取当日推荐;
  • NCM 导入:可直接选择 .ncm 文件,或把 .ncm 路径粘贴到歌单输入框;
    使用与 ncm2music 相同的 NCM 解密算法,并回写封面 / 歌手 / 专辑;
  • 推到今天:把本次导入的本地歌曲推送到曲库页「今天听什么」;
  • 下载到 %APPDATA%\ANDROEQ+\imports\<平台>\(NCM 为 imports\ncm\),
    完成后调用宿主 add_media_file;
  • 下载进度、失败原因、成功标记(✓)都回写到控件状态。

构建:

bat
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% 日志。