# services 与 uses

服务用于后台插件之间的调用。提供方填写 `contributes.services`，消费方填写顶层 `uses`，并在 [dependencies](./manifest.md#manifest-dependencies) 中填写提供方包版本范围。随后消费方通过 [context.plugins.call()](./plugins.md)调用。

## 示例

服务提供方：



```json
{
  "apiVersion": 1,
  "id": "example.service-provider",
  "name": "数字服务提供方",
  "version": "1.0.0",
  "description": "数字服务提供方教学示例",
  "hostPlatforms": [
    "windows",
    "macos",
    "linux"
  ],
  "main": "index.js",
  "permissions": [],
  "contributes": {
    "services": [
      {
        "id": "numbers",
        "title": "数字求和",
        "version": 1,
        "methods": [
          "sum"
        ],
        "titleKey": "services.numbers.title",
        "methodSchemas": {
          "sum": {
            "argsSchema": {
              "type": "object",
              "properties": {
                "values": {
                  "type": "array",
                  "items": {
                    "type": "number"
                  },
                  "maxItems": 100
                }
              },
              "required": [
                "values"
              ],
              "additionalProperties": false
            },
            "outputSchema": {
              "type": "object",
              "properties": {
                "total": {
                  "type": "number"
                }
              },
              "required": [
                "total"
              ],
              "additionalProperties": false
            }
          }
        }
      }
    ]
  },
  "i18n": {
    "defaultLocale": "zh-CN",
    "resources": {
      "zh-CN": "locales/zh-CN.json",
      "en-US": "locales/en-US.json"
    }
  },
  "nameKey": "plugin.name",
  "descriptionKey": "plugin.description"
}
```



消费方：



```json
{
  "apiVersion": 1,
  "id": "example.service-consumer",
  "name": "数字服务消费方",
  "version": "1.0.0",
  "description": "数字服务消费方教学示例",
  "hostPlatforms": [
    "windows",
    "macos",
    "linux"
  ],
  "main": "index.js",
  "permissions": [],
  "contributes": {
    "actions": [
      {
        "id": "sum",
        "title": "远程求和",
        "argsSchema": {
          "type": "object",
          "properties": {
            "values": {
              "type": "array",
              "items": {
                "type": "number"
              },
              "maxItems": 100
            }
          },
          "required": [
            "values"
          ],
          "additionalProperties": false
        },
        "outputSchema": {
          "type": "object",
          "properties": {
            "total": {
              "type": "number"
            }
          },
          "required": [
            "total"
          ],
          "additionalProperties": false
        },
        "titleKey": "actions.sum.title"
      }
    ]
  },
  "uses": [
    {
      "pluginId": "example.service-provider",
      "serviceId": "numbers",
      "version": 1
    }
  ],
  "dependencies": {
    "example.service-provider": "^1.0.0"
  },
  "i18n": {
    "defaultLocale": "zh-CN",
    "resources": {
      "zh-CN": "locales/zh-CN.json",
      "en-US": "locales/en-US.json"
    }
  },
  "nameKey": "plugin.name",
  "descriptionKey": "plugin.description"
}
```



两份清单的服务 ID 和整数版本对应。每个服务方法必须通过 `methodSchemas` 声明参数和结果，由宿主在请求转发前和返回后校验。缺少或不完整的契约会导致清单校验失败。

## Service

清单位置：`manifest.contributes.services[]`。

### `Service.id`

`string` · 必填

服务 ID，在插件内唯一，最多 128 个字符。

### `Service.title`

`string` · 必填

服务名称。

### `Service.version`

`integer` · 必填

服务接口版本，正整数。消费方精确匹配这个值。

### `Service.methods`

`string[]` · 必填

可调用的方法名，1–32 项，不重复。

### `Service.methodSchemas`

`Record<string, { argsSchema, outputSchema }>` · 必填

键必须与 `methods` 完全对应，每个方法都需要契约；`argsSchema` 必须是对象 Schema，`outputSchema` 是结果 Schema。提供方可要求 `plugins.serviceSchemas` v1 宿主能力。

### `Service.maxBytes`

`integer` · 可选

每次服务请求、结果各自的 JSON 字节上限，默认 4096，允许 1024–65536。提高上限须显式声明。SDK 的 8 秒请求超时不变；超时不能撤销已经执行的业务，不自动重试写操作。

## ServiceUse

清单位置：`manifest.uses[]`。

### `ServiceUse.pluginId`

`string` · 必填

提供方的插件 ID。

### `ServiceUse.serviceId`

`string` · 必填

提供方声明的服务 ID。

### `ServiceUse.version`

`integer` · 必填

要调用的服务版本，正整数。

## 包版本与接口版本

`dependencies[pluginId]` 匹配提供方的 SemVer 包版本，`uses[].version` 精确匹配服务接口整数版本。例如 `^1.0.0` 与接口 `1` 是两个独立约束，必须同时满足。

安装和启动前会检查服务是否存在及接口版本是否匹配；调用时仍检查提供方是否运行、包版本、接口版本和方法。提供方仅升级包版本而保持接口不变时，消费方可继续使用允许范围内的新版本。

循环依赖会阻止安装或启动。先安装服务提供方，再安装消费方；宿主不会自动下载依赖。启动消费方会先启动已授权的依赖。停止或重启提供方前须先停止运行中的消费方；卸载提供方前须先卸载消费方。

## 天气能力与独立界面

`builtin.weather` 1.2.0 起提供 `forecast` v1 服务：`getForecast({city})` 查询归一化天气，`searchCities({query?,selectedValue?})` 提供城市选项。公共服务使用 Open-Meteo，共用原有后台的五分钟缓存，不读取或共享其他小组件的彩云 Token。温度单位为摄氏度，风速沿用 Open-Meteo 的 km/h；缺测字段可能为 null。小时与日期字符串是查询城市的当地时间。

[天气界面示例](../guides/examples.md)中的 `weather-card` 没有联网权限，仅调用提供方服务。消费方拥有自己的城市设置、页面和实例；提供方拥有数据源与缓存。
