Skip to content

Plugin Development

Laffey-82 edited this page Aug 31, 2026 · 3 revisions

从零写第一个插件(教程)

目标:用 10 分钟写一个「掷硬币」插件 /coin,覆盖脚手架、声明式 manifest、handler、静态校验、启用与投稿。

1. 生成脚手架

ofbot2 plugin new coin

会在 plugins/coin/ 生成最小包(plugin.json + __init__.py)。

2. 声明命令(plugin.json)

编辑 plugins/coin/plugin.json,加入声明式 feature:

{
  "features": [{
    "id": "coin",
    "label": "掷硬币",
    "description": "随机正反面",
    "enable_on_default": true,
    "manage_permission": "coin.admin",
    "commands": [{
      "name": "coin",
      "aliases": ["硬币"],
      "handler": "handlers.coin_command",
      "permission": "coin.use",
      "description": "随机正反面",
      "usage": "/coin",
      "examples": ["/coin"]
    }]
  }]
}

3. 实现 handler

新建 plugins/coin/handlers.py:

import random

from app.core.messages import Message, MessageEvent
from app.core.plugin import PluginContext

_ctx: PluginContext | None = None

def setup(ctx: PluginContext) -> None:
    global _ctx
    _ctx = ctx

async def coin_command(event: MessageEvent, args: Message, command_ctx) -> None:
    await event.reply("🪙 " + random.choice(["正面", "反面"]))

在 __init__.py 中让插件加载 handlers:

from app.core.plugin import Plugin, PluginContext
from . import handlers

class CoinPlugin(Plugin):
    def setup(self, ctx: PluginContext) -> None:
        handlers.setup(ctx)

def create_plugin() -> Plugin:
    return CoinPlugin()

4. 静态校验

ofbot2 plugin check coin

校验 manifest 字段、handler 符号是否存在、规则是否注册;失败会给出明确错误。

5. 启用

  1. 在 config.yaml 的 plugins 中加入 coin: true,重启机器人(或 Web「插件」页启用)。
  2. 在群内发送 /coin。
  3. 在 Web「监听环境」页可按群独立开/关该功能,群管理员也可用 /功能启用 coin.coin。

6. 进阶:响应规则与会话

  • 命令声明 "rules": [{"name": "group_only"}] 限制仅群内可用;"session": true 后可读写 command_ctx.session(确认流示例见 plugins/template 的 /ask)。
  • 定时任务与事件监听直接在 manifest 的 tasks / listeners 声明。

7. 投稿到插件仓库

  1. 参照官方插件补 README.md(功能/配置/启用方式)。
  2. 把插件放入 plugin-repo/plugins/<分类>/<插件名>/,运行:
py plugin-repo/tools/build_packages.py --check
py plugin-repo/tools/build_packages.py
  1. 提交源码与构建产物(packages/*.zip、registry.json)并发 PR;CI 会复跑校验。

8. v1.4 新增能力速览

  • 权限角色映射:manifest 声明 "permission_roles": {"my_plugin.admin": ["admin", "superadmin"]} 后,该权限只授予 指定角色;未声明的权限仍默认授予 user(向后兼容)。管理员命令无需在 handler 里自查角色。
  • 指令冲突解决:多个插件声明同名/同别名命令时不再加载失败。先加载者保留原名, 后加载者冲突主命令自动注册为 <插件名>.<命令>(如 /order_ledger.分账),冲突别名丢弃; system 插件命令保留。manifest 可用 conflicts: {"命令": "rename"|"skip"} 覆盖。 开发期用 plugin conflicts 查看全量策略,plugin check 预览本插件解决结果。
  • 配置驱动任务:任务参数支持 ${插件配置点分路径} 模板,如 "cron": "${tasks.daily_commission.cron}";Web 保存配置后自动重载并重注册任务。 运行时任务用 ctx.register_managed_task(...) 注册后进入 Web「定时任务」页(可启停)。
  • records 过滤:ctx.records.list(record_type, filters={"status": "done", "amount": {"gte": 10}}, sort_by="amount");过滤器支持等值 / gte / lte / gt / lt / contains / in。
  • rest 参数:命令参数 {"name": "content", "type": "rest"} 会把剩余全部参数合并为 一个字符串,适合多词自由文本。
  • ctx 注入:命令/任务/监听 handler 若声明 ctx 参数,框架自动注入 PluginContext, 不再需要模块级全局变量。
  • 文本转图与群文件上传:ctx.text_image(text) 生成 PNG; await ctx.bot.upload_group_file(group_id, file_path, name)(OneBot 适配器实现)。
  • 插件 e2e:app.testing.FakeBotHarness 启动假 Chronocat + 真实机器人子进程, 插件可放 e2e/*.py 脚本并用 plugin e2e <name> 一键运行。
  • 命令级参数长度:命令声明 max_arg_length 可覆盖全局 security.max_arg_length。

完整参考

Clone this wiki locally