← 跨平台应用开发 · 第 10 篇

用 VS Code 扩展连接命令、文件与任务记录

构建项目任务记录扩展,连接命令声明、扩展生命周期和限定存储,明确工作区信任、URI与取消写入规则。

学完这一篇,你能做到

实现查看与保存任务笔记命令,在多根目录、受限工作区和取消输入时验证写入范围与资源清理。

任务记录扩展提供两个动作:查看当前项目笔记,给一个任务追加记录。它会读写数据,所以需要明确记录属于哪个工作区、命令什么时候生效,以及打开不可信项目时哪些功能可以运行。

本课用合成任务 ID,不读取终端历史或自动运行项目命令。第一版采用编辑器原生选择与输入界面,不需要 webview;以后加入复杂界面时再处理其独立安全边界。

从命令声明到执行函数

扩展 manifest 中的 contribution 声明命令及用户看到的标题,扩展代码注册实际处理函数。声明一个菜单项不等于实现了行为。扩展激活时建立注册与监听,停用时释放资源;注册对象加入 disposables,避免反复激活造成重复处理。

激活机制与最低 engines.vscode 版本有关,按当前官方说明选择事件和贡献点,不把旧样例中的事件配置当作所有版本要求。工程先验证命令出现,再验证调用到正确处理函数。

命令应有稳定 ID,显示标题可翻译。处理函数接收参数时仍需检查类型和范围,因为调用不一定来自菜单。未知任务或缺少工作区应返回可理解信息,不默认写进第一个找到的目录。

任务与存储作用域

任务记录包含任务 ID、文本、记录时间与对应项目身份。多根工作区需要明确选择哪一个 folder;不同项目不能仅靠同名任务标题混在一起。记录 ID 保持稳定,列表展示顺序由明确字段决定。

个人笔记可以使用扩展提供的工作区存储;需要共享的文件另走用户明确选择的导出流程。本课默认不将记录自动写入仓库,也不把服务秘密存进普通 JSON。全局偏好与项目数据分开,避免换项目时看到上一项目的任务。

资源使用 URI 表示。远程工作区和虚拟文件系统不一定对应本机路径,优先使用编辑器 workspace 文件系统接口,而不是直接把 URI 路径交给 Node 的本地文件操作。若某项能力仅支持本地,明确检查并说明限制。

建立扩展开发工程

按官方指南准备 Node.js 与 Git,用 VS Code Extension Generator 创建 TypeScript 工程。打开 src/extension.ts,通过 F5 启动 Extension Development Host,确认模板命令可执行。这里是供读者运行的步骤,本文未运行扩展宿主。

在 manifest 加入查看与保存命令,在激活函数注册两个 handler。查看读取所属项目的记录存储并展示任务选择;保存先选择项目和任务,再输入正文。用户取消任何一步都返回,不创建空记录、不触发后续写入。

加入存储适配器,统一读取、验证、保存与错误映射。启动检查 schema,读取失败保留原记录并显示错误。文件保存采用平台支持的安全写入策略;操作失败不要覆盖现有内容,也不要把“调用已发出”显示成保存完成。

Workspace Trust 的判断要进入执行路径

官方文档允许在 manifest 声明完全、有限或不支持受限工作区。本课采用有限支持:查看笔记可以运行,具有副作用的保存路径要求信任。这是本扩展的明确策略,不表示所有记笔记扩展都必须采用相同限制。

界面可以用信任条件隐藏动作,但隐藏不足以阻止代码调用,handler 仍检查当前信任状态。工作区配置可能含恶意参数,特别是用于执行命令或决定任意写入路径的配置;本课不开放 shell 执行入口。

下面 Python 检查有限命令集合。它是策略模型,不运行 VS Code API,也不实现真实信任状态变化。

def command_allowed(command, trusted):
    read_only = {"show_notes", "list_tasks"}
    if command in read_only:
        return True
    return trusted and command == "save_note"
assert command_allowed("show_notes", False)
assert not command_allowed("save_note", False)
assert command_allowed("save_note", True)
assert not command_allowed("run_shell", True)
print(command_allowed("save_note", False))

实际输出 False。受限模式下保存被拒绝,查看允许,未知 run_shell 即使信任也拒绝。真实扩展以 workspace.isTrusted 等官方 API 读取状态,并按实际能力说明限制;不要仅信任传入参数中的一个布尔值。

路径、监听与重入

如果增加共享文件导出,先让用户选择目标,检查 URI 是否在允许范围,并确认覆盖已有文件。路径检查需处理父目录跳转与真实文件系统行为,不能用简单字符串前缀保证边界。本课先把可写范围固定为扩展自己的存储。

文件 watcher 可能对自己的写入发事件。给操作分配 ID,并区分外部变化与自身保存,避免“检测变化、再次写入”的无限循环。批量变化可以防抖,仍要保证最终读取当前内容,而不是把延迟事件当作完整历史。

一次保存期间继续输入时,旧保存响应只确认自己的快照。新输入保持未保存状态。多窗口同时改同一记录,需要版本或冲突策略,不能因属于同一个工作区就假定只有一个写入者。

错误与界面扩展

没有工作区时提示打开或选择项目;只读资源时允许查看但解释不能保存;容量或编码错误保留输入供重试。取消是用户的正常选择,不当作异常弹窗。日志记录错误码和操作 ID,避免写入完整笔记或私人路径。

若未来使用 webview,要设置内容安全策略、限制本地资源根和校验消息,不把笔记正文拼接为可执行脚本。webview 自身与扩展宿主的权限不同,页面发送“运行任务”不自动构成授权。

输入记录先定义最大文本规模与编码,并在写入前检查。保存一条空白笔记是允许还是拒绝要明确,不依靠提示框自动保证;时间信息说明来源,仅用于展示时不要把它当并发版本。查看命令排序稳定,任务ID与标题分别显示。

对异步选择流程建立操作上下文:选择时记录工作区URI,输入完成后再次确认该项目仍有效。如果用户中途关闭项目或切换工作区,停止保存并保留可复制文本,不能把旧输入落到新项目。若文件提供者不支持某项写入能力,返回受控错误。测试远程URI时记录提供者与实际能力,没有覆盖的环境在验收中保留未知状态。

练习:验收项目隔离

建立两个教学项目,分别保存同名任务的不同记录,切换后只能看到所属项目内容。测试没有工作区、取消输入、受限模式、保存失败和扩展重新加载,已确认记录不丢失,不创建空条目。

检查菜单隐藏后直接调用保存命令仍受信任策略限制。停用扩展时监听与注册被释放,重复启动不会重复响应。若只完成本地环境测试,记录远程工作区仍未验证;Python 策略通过不能证明URI读写或扩展生命周期已正确运行。

资料来源与延伸阅读

资料核验:2026-11-10。本文为原创工程讲解,教学示例不代表线上实测。