Skip to content

Extension Points

Ling edited this page Jul 12, 2026 · 4 revisions

通用扩展点

通用扩展点用于让插件向宿主或其他插件贡献对象。它适合那些还不需要变成 IPluginHost 顶层专用属性的能力。

当前 SDK 提供的是通用注册机制:贡献对象的类型、元数据键和调用约定由具体扩展点自行约定。源码中没有预置 PluginExtensionPoints 常量或联机专用接口。

需要的能力

manifest 声明:

"capabilities": ["RegisterExtension"]

C# Attribute 声明:

Capabilities = PluginCapabilities.RegisterExtension

未声明时,context.Host.Extensionsnull

注册贡献项

var extensions = context.Host.Extensions
    ?? throw new InvalidOperationException("Extension API is unavailable.");

var registration = extensions.Register(new PluginExtensionDescriptor<IMyContribution>
{
    ExtensionPoint = "com.example:my-extension",
    Id = "default",
    DisplayName = "Example Contribution",
    Order = 100,
    Metadata = new Dictionary<string, string>
    {
        ["kind"] = "example"
    },
    Contribution = new MyContribution()
});

返回的 registration 必须在插件卸载时释放:

public override Task UnloadAsync(CancellationToken cancellationToken = default)
{
    _registration?.Dispose();
    _registration = null;
    return Task.CompletedTask;
}

Descriptor 字段

字段 说明
ExtensionPoint 扩展点标识
Id 贡献项 ID,同一插件同一扩展点内唯一即可
DisplayName 展示名,用于 UI 或日志
Order 排序权重,数值越小越靠前
Metadata 可选元数据
Contribution 实际贡献对象

宿主注册表会按 ExtensionPoint 区分条目。同一插件、同一扩展点、同一 Id 的新贡献会替换旧贡献。

命名建议

PCL 内置扩展点建议使用 pcl: 前缀:

pcl:feature:name

第三方扩展点建议使用反向域名或明确前缀:

com.example:backup-provider
net.example.launcher:custom-source

贡献接口应放在调用方和贡献方都能引用的共享契约包中。不要让一个公开插件为了扩展点直接引用启动器内部项目。

读取扩展点

公开 SDK 当前只暴露插件侧注册 API。宿主内部会通过 PluginExtensionRegistry 按扩展点读取贡献项,并按 Order、插件 ID、贡献 ID 排序。

如果你在设计新的扩展点,至少要先定义:

  • 扩展点名称。
  • 贡献对象接口或基类。
  • Metadata 中可用键。
  • 贡献对象的生命周期和线程模型。
  • 异常处理和超时策略。

何时新增 SDK 强类型接口

如果一个扩展点满足这些条件,可以考虑沉淀为 SDK 中的强类型接口:

  • 多个插件都会实现。
  • 宿主核心功能需要稳定依赖它。
  • 参数、生命周期和错误语义已经稳定。
  • 不再只是某个插件的一次性需求。

在此之前,优先使用 IPluginExtensionApi 和明确的扩展点约定。

Clone this wiki locally