Skip to content

Plugin SDK

AceGuru-mjh edited this page Oct 1, 2026 · 4 revisions

插件 SDK

🎨 UI & 扩展 · 🏠 首页 › Plugin-SDK

Home Version Kotlin Modules Tools License

Plugin-SDK

📑 本页目录

插件是独立 APK,通过 AIDL 导出 IApexPlugin 服务;宿主(主 App)经 PackageManager 发现 → 绑定 → 把插件声明的工具桥接进 ToolRegistry。适合"能力要独立分发、独立更新、独立沙箱"的场景。

1. 契约:plugin-sdk/plugin-api

package com.apex.agent.plugin.api;

interface IApexPlugin {
    String getMetadataJson();
    String getToolsJson();
    String executeTool(String toolId, String argumentsJson);
    void onActivate();
    void onDeactivate();
}

Kotlin 侧镜像接口(PluginContract.kt):

interface ApexPluginService {
    fun getMetadata(): PluginMetadata
    fun getTools(): List<PluginToolDescriptor>
    suspend fun executeTool(toolId: String, arguments: String): String
    fun onActivate()
    fun onDeactivate()
}

data class PluginMetadata(
    val id: String, val name: String, val version: Int, val versionName: String,
    val minHostVersion: Int, val description: String
)

data class PluginToolDescriptor(
    val id: String, val name: String, val description: String, val parametersSchema: String
)

Note

plugin-api 模块开启了 buildFeatures { aidl = true };插件 APK 只需依赖 plugin-api, 不需要依赖宿主任何代码 —— 这是刻意保持的最小契约。

2. 宿主侧:plugin-sdk/plugin-host

PluginManager.kt 负责三件事:

flowchart LR
    A["PackageManager 查询<br/>action = com.apex.agent.plugin.PLUGIN"] --> B["bindService( exported Service )"]
    B --> C["IApexPlugin.Stub.asInterface(binder)"]
    C --> D["getMetadataJson() / getToolsJson()"]
    D --> E["校验 minHostVersion"]
    E --> F["桥接:每个 tool 注册进 ToolRegistry"]
    F --> G["LLM 像用内置工具一样调用(含斜杠 /plugin: 前缀)"]
Loading

生命周期:onActivate() / onDeactivate() 由宿主在绑定建立与断开时调用, 插件可以在这里初始化/释放资源(如打开设备、连接池)。

3. 参考实现:plugins/plugin-workflow

<!-- AndroidManifest.xml -->
<service
    android:name=".WorkflowPluginService"
    android:exported="true">
    <intent-filter>
        <action android:name="com.apex.agent.plugin.PLUGIN" />
    </intent-filter>
</service>
class WorkflowPluginService : Service() {
    private val binder = object : IApexPlugin.Stub() {
        override fun getMetadataJson(): String = /* id=com.apex.agent.plugin.workflow */
        override fun getToolsJson(): String   = /* 3 个工具的 schema */
        override fun executeTool(toolId: String, argumentsJson: String): String = …
        override fun onActivate() {}
        override fun onDeactivate() {}
    }
    override fun onBind(intent: Intent): IBinder = binder
}

暴露的三个工具:

工具 用途
workflow/save 保存流程定义
workflow/execute 执行已保存流程
workflow/list 列出流程

4. 写一个自己的插件(步骤)

  1. 新 Gradle 模块(com.android.application),依赖 :plugin-sdk:plugin-api;
  2. 在 settings.gradle.kts 里 include;
  3. 写一个 Service 实现 IApexPlugin.Stub(),android:exported="true" + intent action com.apex.agent.plugin.PLUGIN;
  4. getMetadataJson() 返回 PluginMetadata(含 minHostVersion,防宿主过旧);
  5. getToolsJson() 返回 PluginToolDescriptor 列表 —— parametersSchema 用 JSON Schema 字符串 (可与 core 的 ToolSchema DSL 渲染结果对齐);
  6. executeTool() 返回结果字符串(失败请返回模型可读的错误说明,不要崩溃);
  7. 安装 APK,宿主 Market 屏的"插件"货架会自动发现。

Caution

插件跑在自己的进程里:跨进程调用有开销,也有权限边界。 需要高频调用或需要宿主 UI 上下文的能力更适合做成内置工具/技能。

5. 安全边界

风险 现状 / 建议
恶意插件伪造 action 目前依赖 Android 包安装来源管控(未知来源安装需用户确认);建议用户在市场货架里只装可信插件
工具 ID 冲突 插件工具使用带前缀的 id(如 workflow/save);CI 有内置工具的 ID 唯一性门禁,插件侧请自觉用命名空间
参数注入 argumentsJson 是字符串,边界之内由插件自己校验,不要直接拼进 shell
版本漂移 用 minHostVersion 声明最低宿主版本

6. 相关页面

footer

🏠 返回首页 · 📚 文档索引 · ❓ FAQ · 🔧 故障排查 · 🗺️ 路线图 · 🐛 提 Issue

Android Guru Agent · v1.4.4 · Kotlin 2.0.21 · Compose · PRoot · Room

Clone this wiki locally