ZorvAI APK 插件框架 · 技术架构与功能介绍

1 阅读18分钟

ZorvAI APK 插件框架 · 技术架构与功能介绍

文档类型:技术架构说明 | 架构介绍 | 功能介绍 适用宿主:Zorv AI(com.ai.assistance.quro)≥ 1.0.89 框架版本:v1.0.90 代码位置:plugin-contract(契约层)· :plugin-engine(引擎层)· app/core/plugin + app/core/tools + app/ui(宿主接入层) 示例插件:plugin-devkit :plugin-express :plugin-todo :plugin-units :plugin-sysinfo :plugin-zorvweb

开源地址

平台仓库地址
GitHub(主仓库 · Release / Issues)github.com/Quor-a/Zorv…
Giteegitee.com/ZorvAI/Zorv…
GitLab(极狐)jihulab.com/quor-a-grou…
常用入口链接
最新 Release(免登录下载 APK)github.com/Quor-a/Zorv…
问题反馈 / 需求建议github.com/Quor-a/Zorv…
开发手册(apk-plugin-arch 分支)docs/APK_PLUGIN_DEVELOPMENT_MANUAL.md
克隆仓库git clone https://github.com/Quor-a/ZorvAI

本项目完全开源(Apache-2.0),多平台托管;插件框架的源码就在上面的仓库里—— 契约层 plugin-contract/、引擎层 plugin-engine/、6 个示例插件 plugin-*/ 可直接编译运行。


目录

章节内容
为什么需要 APK 插件框架
核心思想(一句话)
分层架构
四个关键机制
加载全流程
AI 工具链
界面体系
安全模型
可靠性设计
功能介绍
十一内置示例插件
十二方案对比
十三设计原则与边界

一、为什么需要 APK 插件框架

ZorvAI 是一个能力密度很高的 AI 助理:终端、浏览器、ACI、TTS、可视化和 14 类扩展能力都长在宿主里。 传统做法下,每加一个能力都要动宿主源码——改工具注册表、改系统提示、改设置页、重新发版。 这条路径有三个绕不开的成本:

成本具体表现
发布耦合一个小工具也要走完整 App 发版流程(构建 383MB APK、上传、用户下载安装)
源码耦合第三方想在 ZorvAI 里加能力,必须拿到宿主源码并编译整个工程
能力上限 = 团队上限宿主团队写多少,AI 就有多少能力,无法外部扩展

APK 插件的目标:把「给 AI 加能力」从「改宿主」变成「装一个 APK」。

设计目标四条:

  1. 宿主零改动 —— 宿主不认识任何具体插件,只认识「扩展点」这一个抽象;
  2. 能力可分发 —— 插件是标准 APK,可签名、可版本管理、可从任意渠道分发;
  3. AI 原生 —— 插件注册的工具自动进入 LLM 工具集,装完立刻可用,无需重启;
  4. 可控安全 —— 插件与宿主同进程、同权限,因此必须有明确的信任边界(同签名)。

二、核心思想(一句话)

宿主不认识任何具体插件,只认识「扩展点」这一个抽象。 插件往槽里放实现,宿主负责调度。

// 插件作者写的全部代码,本质上就是「往槽里放东西」
class HelloEntry : PluginEntry {
    override fun onCreate(ctx: PluginContext) {
        plugin(ctx) {
            aiTool("hello_greet", "向某人打招呼。当用户说「跟某人打招呼」时调用。") {
                param("who", ParamType.STRING, "要打招呼的对象名字")
                execute { args -> ToolResult.text("你好,${args.string("who")}!") }
            }
        }
    }
}

这段代码不进宿主、不改宿主、不重新编译宿主。装进宿主后,LLM 的工具集里立刻多出一个 hello_greet

这就是「神经-代码一体化」在宿主侧的具体形态:宿主提供稳定的骨架(扩展点 + 调度), 插件提供可替换的血肉(实现),两者通过签名互相担保。


三、分层架构

框架是严格的四层结构,依赖方向单向向下,上层不知道下层的具体实现:

┌──────────────── 宿主 App(:app)· 调度层 ────────────────────────────┐
│                                                                      │
│  QuroApplication.onCreate()                                          │
│      └── QuroPluginHost.attach(this)      ← 宿主唯一一次性接线点       │
│               ├── QuroPluginEngine.init(app, HOST_CAPS)              │
│               ├── AciBridge 双向注入                                  │
│               └── QuroPluginEngine.loadAllInstalled()                │
│                                                                      │
│  AI 工具链                                                            │
│    QuroToolRegistry.coreSpecs()                                      │
│        └── pluginHostToolSpecs()                                     │
│              ├── QuroPluginTools        → 单入口工具 apk_plugin       │
│              └── QuroPluginHost.toolSpecs() → 插件贡献的 AI 工具       │
│                                                                      │
│  QuroToolEngine.execute()                                            │
│      ├── 命中插件工具 → QuroPluginHost.executePluginTool()(suspend)  │
│      └── 否则走内置注册表派发                                          │
│                                                                      │
│  界面                                                                 │
│    PluginManagerScreen    ← 启动器式插件桌面(网格/搜索/长按菜单/Dock)│
│    PluginSurfaceActivity  ← 通用界面承载 Activity                     │
└──────────────────────────────────────────────────────────────────────┘
                              ▲
               HostToolBridge / AciBridge(宿主取用桥)
                              │
┌────────────── :plugin-engine(引擎层)· 能力层 ───────────────────────┐
│  QuroPluginEngine     加载 / 卸载 / 热重载(DexClassLoader)           │
│  PluginInstaller      清单解析 · 同签名校验 · 原子替换 · .so 提取       │
│  PluginClassLoader    隔离类加载器(宿主 ClassLoader 作父)             │
│  PluginContextImpl    插件运行时上下文(存储 / 日志 / 互调)            │
│  ExtensionRegistry    14 个扩展点「收纳槽」                            │
│  HostToolBridge       扩展点 → 宿主工具规格                            │
│  AciBridge            ACI 能力双向桥                                  │
└──────────────────────────────────────────────────────────────────────┘
                              ▲
┌──────────── :plugin-contract(契约层|compileOnly)· 约定层 ──────────┐
│  PluginEntry   PluginContext   ExtensionType   PluginDsl   ToolSpec…  │
└──────────────────────────────────────────────────────────────────────┘
                              ▲
┌──────────────── 你的插件 APK(独立签名 APK)· 实现层 ─────────────────┐
│  YourEntry : PluginEntry  →  onCreate 里 plugin(ctx) { ... }          │
└──────────────────────────────────────────────────────────────────────┘

各层职责

模块 / 位置谁依赖它职责
契约层:plugin-contract插件 compileOnly、引擎 implementation只放接口与数据类,不含任何实现。插件编译期可见、运行期由宿主提供
引擎层:plugin-engine宿主 implementation安装、加载、卸载、热重载、扩展点收纳、桥接
调度层:app宿主本体决定「什么时候、用哪个扩展点、给谁看」,接进 AI 工具链与 UI
实现层你的插件 APK只依赖契约层,提供扩展点实现

为什么契约层必须是 compileOnly 若用 implementation 把契约层打进插件 APK,插件与宿主会各持有一份 PluginEntry 类的副本。 宿主用自己的 ClassLoader 加载插件时,ClassCastException 会立刻出现—— 这是本框架第一大坑,也是新人最常踩的坑。


四、四个关键机制

4.1 扩展点收纳槽(ExtensionRegistry)

框架的灵魂是一个只有 14 个格子的注册表。每个格子对应一类可插入的能力:

#ExtensionType用途宿主消费方
1AI_TOOL给 LLM 加一个可调用工具 ★ 最常用HostToolBridgeQuroToolRegistry
2ACI_CAPABILITY把能力暴露给其他 App / AgentAciBridge → ACI 服务端清单
3UI_SURFACE插件自带的完整界面(View 树)PluginSurfaceActivity
4CHAT_CARD聊天气泡内自定义结构化卡片聊天渲染层
5UI_WIDGET气泡内可交互内联组件内联组件渲染
6MODEL_PROVIDER新增一种大模型接入模型配置层
7RAG_SOURCE新增一种知识库来源知识库层
8COMMAND输入框 /斜杠指令输入框解析
9SETTING设置页新增配置项设置页
10SCHEDULE_TASK新增周期任务执行体定时任务调度
11CHANNEL新增一个 IM 接入消息渠道层
12FILE_HANDLER新增文件类型的打开/预览文件打开分发
13CODE_RUNTIME新增脚本语言引擎脚本执行层
14SPEECH新增 TTS / STT 引擎语音层

收纳槽的索引键是 (ExtensionType, id)

  • 同名同类的扩展后注册者覆盖先注册者 —— 所以工具名必须加插件前缀(如 express_queryweb_open);
  • 插件卸载时 unregisterAll() 一次性清空该插件的全部格子,不留悬挂引用。

4.2 类加载与资源挂载

插件 APK 不是系统安装的应用,它用 DexClassLoader 在宿主进程内加载:

PluginClassLoader(
    dexPath          = <host>/files/plugins/<id>/active/base.apk,
    optimizedDir     = <host>/files/plugins/.odex/<id>,
    nativeLibraryDir = <host>/files/plugins/<id>/active/lib,   ← 按设备 ABI 提取的 .so
    parent           = 宿主 ClassLoader                          ← 关键
)

两个设计细节:

  • 父加载器 = 宿主 ClassLoader:插件因此能拿到宿主的 Class,也能被宿主反射实例化;
  • 资源挂载 = 宿主资源路径 + 插件资源路径:新建 Android.Resources 时把两边都挂上, 插件里的 R.string.xxx 能用,同时插件的 View 也能继承宿主主题(不会出现样式割裂)。

因为跑在宿主进程内,插件不能有自己的 Activity / Service / BroadcastReceiver—— 要界面请注册 UI_SURFACE,由宿主用通用 Activity 承载。

4.3 双向桥(HostToolBridge / AciBridge)

桥的作用是把插件的能力翻译成宿主认识的形态,两个方向:

方向一(插件 → 宿主)
  AiToolExtension  →  HostToolBridge.collectToolSpecs()
                   →  ToolParamSpec → OpenAI function-calling JSON Schema
                   →  QuroToolRegistry.coreSpecs()  →  LLM tools 字段

方向二(ACI 双向)
  AciCapabilityExtension  →  AciBridge.capabilitySink
                          →  QuroPluginAciRegistry.publish()  →  对外能力清单

  AciBridge.externalCapabilities + aciInvoker
      →  refreshAciMirror()(宿主定期刷新)
      →  外部 ACI 能力镜像成 AI 工具 aci_list / aci_call

结果:插件既是能力的提供方,也是能力的消费方,且两条链路都收敛到「AI 工具」这一个出口。

4.4 单入口工具 apk_plugin

框架只暴露 1 个 AI 工具给 LLM,而不是十几个零散管理工具。这样做的原因:

  • 工具集里工具越少,LLM 选错工具的概率越低;
  • 管理类动作(装/卸/查)不该进入日常工具集,只在需要时由同一入口分发。
action必填参数作用
status框架状态(engine_ready 等)
list已装插件清单
infoplugin_id插件明细(含扩展点构成)
tools插件贡献的全部 AI 工具
surfaces插件界面清单
opensurface_id打开插件界面
installpath(可选 skip_signature_check从 APK 安装
install_builtin装宿主内置示例插件
uninstallplugin_id卸载
reloadplugin_id(不传=全部)热重载
callname(可选 args★ 直接调用插件 AI 工具

call 是关键的兜底通道:工具集被裁剪、或插件刚装完还没轮到下一轮时, AI 仍可用 apk_plugin(action="call", name="...", args="{...}") 调用插件工具。 宿主侧等价于直接调 QuroPluginHost.executePluginTool不经过工具集—— 所以「插件装了但 AI 用不了」这个死角不存在。

历史说明:早期版本曾用 6 个独立工具(plugin_list / plugin_info / plugin_install / plugin_uninstall / plugin_reload / plugin_surface_open)实现同样的功能, 现已全部删除,统一收敛为 apk_plugin


五、加载全流程

5.1 安装(install(apk)

install(apk)
  ├─ 1. PackageManager 读清单 → 校验 meta-data quro.plugin.entry,缺失即拒
  ├─ 2. 校验 APK 签名 SHA-256 == 宿主签名,不一致即拒
  ├─ 3. 取 pluginId / versionCode / versionName / label(桌面显示名)
  ├─ 4. 原子替换写入 /data/data/<host>/files/plugins/<pluginId>/active/base.apk
  ├─ 5. 从 APK 提取 lib/<abi>/*.so → active/lib/
  ├─ 6. 写 SharedPreferences 记录(quro_plugins/record_<pluginId>)
  └─ 7. load(pluginId)
        ├─ 新建 PluginClassLoader(宿主 ClassLoader 作父)
        ├─ Android.Resources 挂「宿主资源路径 + 插件资源路径」
        ├─ 反射 newInstance() → YourEntry
        └─ YourEntry.onCreate(ctx)   ← 你在这里注册扩展点

七步里前两步是信任闸门,任何一步不过,安装直接失败并给出明确原因(见手册「调试与排错」)。

5.2 启动(宿主冷启动)

QuroApplication.onCreate()
  └── QuroPluginHost.attach(app)
        ├── QuroPluginEngine.init(app, HOST_CAPS)
        │      HOST_CAPS = {llm, memory, tts, stt, aci, terminal, file, web, screen, shell}
        ├── AciBridge 双向注入
        ├── QuroPluginEngine.loadAllInstalled()   ← 已装插件的 onCreate 在此跑
        ├── refreshAciMirror()                    ← 外部 ACI 能力镜像成 AI 工具
        └── QuroPluginAciRegistry.publish(...)    ← 插件能力对外发布

性能约束onCreateApplication.onCreateloadAllInstalled() 里同步执行, 所以插件必须保持轻量——耗时的初始化放到首次 execute 时惰性执行,或自己开后台线程。


六、AI 工具链(让 LLM 自己找到插件)

这是整个框架最核心的价值链路。插件注册完,AI 不用被通知就知道新工具存在

YourEntry.onCreate
   └─ ctx.register(AiToolExtension)
        └─ ExtensionRegistry(收纳槽)
             └─ HostToolBridge.collectToolSpecs()
                  └─ QuroPluginHost.toolSpecs()        ← ToolParamSpec → JSON Schema
                       └─ pluginHostToolSpecs() → QuroToolRegistry.coreSpecs()
                            └─ LLM tools 字段(下一轮 function calling 即可见)

执行:
QuroToolEngine.execute(call)
   └─ QuroPluginHost.executePluginTool(name, args)     ← suspend 桥接
        └─ HostToolBridge.executeTool → YourExecutor.execute(ToolArgs)

三个设计要点:

  1. 自动进工具集:不需要重启宿主,不需要手动刷新注册表;
  2. 契约是 JSON SchemaToolParamSpec(含 enumdefaultrequired)被宿主翻译成 标准 function-calling schema,LLM 侧零特殊处理;
  3. 执行体是 suspend:插件可以直接 withContext(Dispatchers.IO) 发网络请求、读数据库, 不会阻塞主线程(这是 Android 侧最容易被忽略的一条)。

决定调用率的是 description

宿主的系统提示里有一整章讲插件框架,但真正决定 LLM 会不会调用你的是工具描述

做法效果
"快递查询工具"AI 不知道什么时候该用
"根据快递单号查询物流轨迹。当用户询问快递到哪了、物流状态、包裹进度时调用。"AI 能把口语映射过来
param("no", STRING, "单号")AI 可能传错格式
param("no", STRING, "快递单号,如 SF1234567890")有示例,命中率高
✅ 用 enum 约束有限取值集合避免 AI 自由发挥传错值

七、界面体系

7.1 为什么插件不能写 Activity

插件 APK 没有真实的系统安装记录,startActivity 一个插件里的 Activity 会直接失败。 宿主提供通用承载 Activity解决这个问题:

PluginManagerScreen(插件桌面)
        │  单击图标 / 长按「打开界面」/ 详情「打开界面」
        │  AI: apk_plugin(action="open", surface_id="...")
        ▼
PluginSurfaceActivity(宿主通用承载)
        │  调用插件的 UiSurfaceExtension.build(activityContext, host)
        ▼
插件返回的 View 树(由插件负责构建,可用 WebView 做完整前端)

7.2 交给插件的三个回调

interface SurfaceHost {
    val pluginId: String
    fun close()                    // 关闭当前界面
    fun toast(message: String)     // 宿主 Toast
    fun runOnUi(block: () -> Unit) // 切主线程
}
回调时机插件该做什么
build(actCtx, host)界面打开返回 View 树(拿到的是 Activity Context,可直接 WebView(actCtx)
SurfaceBackHandler.onSurfaceBack()返回键/手势true = 自己消费(如先退一层内部页面);false = 交宿主关闭
onRelease()界面关闭释放资源:detach WebView、注销监听、停计时器

7.3 插件桌面(PluginManagerScreen)

启动器形态的插件管理界面,是插件能力的可视化入口

  • 网格布局 + 搜索 + 长按菜单(打开界面 / 重载 / 卸载 / 详情)
  • 底部 Dock →「导入 APK」直接装
  • 图标取插件 APK 的 launcher 图标(没配则显示首字母色块)
  • 显示 v1.0.0 (1) 形式的版本信息

已废弃:早期 JS 演示壳 PluginsScreen 已更名 LegacyJsPluginRuntimeScreen,打开即空白, 不要把它当成插件入口。现役插件桌面就是 PluginManagerScreen


八、安全模型

插件跑在宿主进程内、拥有与宿主完全相同的权限——这本质上等同于「代码注入」。 因此框架的安全边界不是「限制插件能做什么」,而是「保证插件是我信任的代码」:

边界机制为什么必须
同签名宿主比对 APK 证书 SHA-256插件与宿主同进程同权限;不同签名 = 不可信代码
只放私有目录/data/data/<host>/files/plugins/外置存储可被其他 App 篡改
必须是声明了 entry 的 APK清单解析 quro.plugin.entry防止误装普通 APK
原子替换.tmp.bakactive,失败回滚避免安装中断导致插件损坏
卸载即注销unregisterAll()不留悬挂扩展点

宿主 Release 证书 SHA-256(插件必须使用同一份 keystore):

D9:5B:1B:EC:57:B9:D5:EE:88:96:05:9C:0F:3C:B5:09:E5:E9:CE:7C:CD:AE:DB:9C:6B:2E:98:49:BA:10:C7:99

调试期可用 apk_plugin(action="install", path=..., skip_signature_check=true) 跳过校验, 正式分发绝不能跳过


九、可靠性设计

机制实现解决的问题
原子替换安装先写 .tmp → 旧版改名 .bak.tmp 改名 active → 删 .bak;任一步失败回滚不会出现「装一半坏掉」
热重载apk_plugin(action="reload", plugin_id=...) = unload + load改完插件立刻生效,不需要重启宿主 App
卸载即清理unloadonDestroy + unregisterAll)→ 删 plugins/<id>/ → 清记录不留垃圾、不留悬挂扩展点
失败降级安装失败给出明确原因(缺 entry / 签名不符 / 写入失败…)排错不靠猜
原生库自动适配安装时按设备 ABI 提取 lib/<abi>/*.soactive/lib/,作为 librarySearchPath 传入一个 APK 适配多 ABI 设备

热重载会丢状态reload = unload + load,插件实例重建。 需要持久化的东西放 ctx.putString()ctx.getFilesDir()


十、功能介绍

10.1 面向用户:装了插件之后,AI 多了什么能力

能力域用户可说的话背后是谁在干活
给 AI 加工具「帮我算一下 base64 解码」「查一下我的快递」插件的 AI_TOOL 扩展点
完整的插件界面插件桌面点图标打开「ZorvWeb 浏览器」插件的 UI_SURFACE 扩展点
斜杠指令/express SF1234567890插件的 COMMAND 扩展点
对话卡片聊天里出现插件渲染的结构化卡片插件的 CHAT_CARD 扩展点
跨 App 能力开放其他 App / 其他 Agent 通过 ACI 调我的能力插件的 ACI_CAPABILITY 扩展点
新模型 / 新知识源在模型列表里多一个自建服务商MODEL_PROVIDER / RAG_SOURCE
新文件类型支持点开 .xyz 文件由插件预览FILE_HANDLER
新语音 / 脚本引擎换一个 TTS,或多一种脚本语言SPEECH / CODE_RUNTIME

关键点:这些能力全部由插件提供,宿主代码零改动。

10.2 面向开发者:你能往哪些槽里放东西

你想做的用哪个扩展点难度
给 AI 加一个可调用工具AI_TOOL★ 最常用,10 行代码
做一个插件自己的完整界面UI_SURFACE★★ 会写 View / WebView 即可
加一条 /斜杠指令COMMAND
把能力暴露给别的 AppACI_CAPABILITY★★
加配置项 / 定时任务 / 文件处理SETTING / SCHEDULE_TASK / FILE_HANDLER★★
接新模型 / 新知识库 / 新渠道 / 新语音MODEL_PROVIDER / RAG_SOURCE / CHANNEL / SPEECH★★★

10.3 框架给开发者提供的便利

便利具体体现
声明式 DSLplugin(ctx) { aiTool(...) { param(...); execute {...} } },不用手写注册样板
参数宽松解析LLM 把数字传成字符串也能取到(args.int() / args.number() 兜底转换)
宿主能力探测ctx.hasHostCapability("llm") 做可选依赖判断,有则增强、无则降级
安全的键值存储ctx.getString / putString / getBool / putBool,底层按插件隔离
私有文件目录ctx.getFilesDir()<host>/files/plugins/<pluginId>/
日志归集ctx.log(tag, msg) → logcat TAG 为 QuroPlugin/[<pluginId>],一眼分清是哪个插件
插件互调ctx.callCapability(id, args),先找插件能力、再找外部 ACI 能力
AI 兜底调用apk_plugin(action="call") 绕过工具集裁剪

十一、内置示例插件

仓库内置 6 个可直接编译、可直接安装的示例插件,本身就是框架能力的规格说明

插件显示名注册了哪些扩展点演示了什么
:plugin-express快递查询插件1 AI_TOOL + 1 ACI_CAPABILITY + 1 COMMAND最小完整范式:一个插件同时贡献 AI 工具、对外能力、斜杠指令
:plugin-devkit开发工具箱6 AI_TOOL + 1 ACI_CAPABILITY多功能插件组织方式(dev_base64 dev_hash dev_json dev_regex dev_url dev_uuid
:plugin-zorvwebZorvWeb 网页引擎15 AI_TOOL + 1 UI_SURFACE旗舰示例:AI 工具 + 完整界面共存,用 WebView 做插件自带前端
:plugin-todo待办清单5 AI_TOOL有状态插件 + 持久化
:plugin-units单位换算1 AI_TOOL极简单工具插件(含 enum 参数约束)
:plugin-sysinfo设备体检4 AI_TOOL借宿主 Context 读系统信息(sys_battery sys_memory sys_storage sys_report

旗舰示例:plugin-zorvweb 的 15 个工具

web_open        web_nav         web_read       web_query      web_find
web_elements    web_console     web_script     web_wait       web_tabs
web_media       web_http        web_crawl      web_info       web_search_page

外加 1 个 uiSurface(id = 浏览器,标题「ZorvWeb 浏览器」), 插件内部用 BrowserSurfaceView 构建界面,onRelease 里做 WebView 资源释放—— 这一个插件就同时演示了 AI 工具族、界面承载、生命周期管理三件事


十二、方案对比

维度系统安装的独立 App纯 JS / 脚本插件ZorvAI APK 插件
能给 AI 加工具不能(除非走 ACI 绕行)能,且自动进工具集
能访问宿主上下文不能受限能(同进程同权限)
能渲染完整界面自己开 Activity(体验割裂)受沙箱限制能(宿主通用 Activity 承载 + 继承宿主主题)
分发形式应用商店 / APK脚本文件签名 APK,可版本管理与热重载
性能跨进程开销解释执行开销同进程原生,无跨进程开销
语言Kotlin / JavaJSKotlin / Java(全生态可用)
安全边界系统沙箱沙箱同签名 + 私有目录 + 清单校验
改宿主源码不需要不需要不需要

取舍说明:APK 插件用「同签名」换来了最强的能力与性能, 代价是第三方无法自由发布插件——这是有意的设计选择:插件跑在宿主进程内, 放开签名等于允许任意代码注入。需要开放生态时,正确路径是 ACI_CAPABILITY(走 Binder 语义、跨进程隔离)。


十三、设计原则与边界

13.1 五条设计原则

原则落地方式
宿主只认识抽象宿主不 import 任何插件类,只消费 ExtensionType
依赖单向向下实现层 → 契约层;引擎层 → 契约层;调度层 → 引擎层。禁止反向
契约层零实现:plugin-contract 只有接口与数据类,保证 compileOnly 语义成立
能力收敛到单一出口14 类能力最终都翻译成「AI 工具」或「ACI 能力」两种形态
默认安全同签名 + 私有目录 + 清单校验,三条闸门都不提供「宽松模式」(调试开关除外)

13.2 边界与限制(明确不做的事)

限制原因替代方案
不能写 Activity / Service / Receiver插件无系统安装记录UI_SURFACE(界面)、SCHEDULE_TASK(周期任务)
不能直接改宿主源码或布局会破坏「宿主零改动」前提只能通过扩展点接入
不能自由分发(必须同签名)同进程 = 代码注入开放生态走 ACI_CAPABILITY
不能在 onCreate 里做重活Application.onCreate 同步链路里惰性执行 / 自己开后台线程
热重载不保状态reload = unload + load持久化到 ctx.putString / getFilesDir()

13.3 术语表

术语含义
宿主(Host)ZorvAI 主程序(:app),负责调度与承载
契约层(Contract):plugin-contract,插件与宿主之间的唯一接口约定
扩展点(Extension Point)14 种可插入能力槽位之一
收纳槽(Registry)ExtensionRegistry,按 (ExtensionType, id) 索引的注册表
表面(Surface)插件提供的完整界面,由宿主通用 Activity 承载
桥(Bridge)HostToolBridge / AciBridge,把插件能力翻译成宿主认识的形态
ACI跨进程能力调用体系;插件能力可对外发布,外部能力也可镜像成 AI 工具

相关文档与源码位置

文档 / 源码链接内容
《ZorvAI APK 插件开发手册》本机桌面 / apk-plugin-arch 分支 docs从 0 到 1 写插件:DSL 完整参考、工程配置、排错速查、完整示例
仓库 READMEgithub.com/Quor-a/Zorv… →「APK 级插件框架」面向使用者的能力索引
扩展点权威定义plugin-contract/.../extension/ExtensionPoints.kt14 种 ExtensionType + 数据类
DSL 权威定义plugin-contract/.../dsl/PluginDsl.ktplugin(ctx) { ... } 全部 builder
引擎层实现plugin-engine/加载 / 安装 / 收纳槽 / 双向桥
示例插件plugin-zorvweb · plugin-devkit · plugin-express可直接编译运行的参考实现

仓库地址

GitHubgithub.com/Quor-a/Zorv…(主仓库) Giteegitee.com/ZorvAI/Zorv… GitLabjihulab.com/quor-a-grou… 下载Releases反馈Issues


本文档描述 ZorvAI APK 插件框架 v1.0.90 的架构与能力,随代码演进维护。 项目开源地址:github.com/Quor-a/Zorv…