@quicktvui/ai 1.1.14 → 1.1.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +44 -0
- package/package.json +1 -1
- package/rules/.claude/commands/create-component.md +1 -1
- package/rules/.claude/commands/create-page.md +1 -1
- package/rules/.claude/commands/create-project.md +1 -1
- package/rules/.claude/commands/lookup-api.md +1 -1
- package/rules/.claude/commands/lookup-css.md +1 -1
- package/rules/.clinerules +141 -1
- package/rules/.cursorrules +141 -1
- package/rules/.docs/zh-CN/tool/api/overview.md +4 -0
- package/rules/.docs/zh-CN/tool/api/plugin-scaffold-mcp.md +46 -0
- package/rules/.docs/zh-CN/tool/api/plugin-server-api.md +198 -0
- package/rules/.docs/zh-CN/tool/cli/introduction.md +7 -0
- package/rules/.docs/zh-CN/tool/cli/plugin-create-component.md +101 -0
- package/rules/.docs/zh-CN/tool/cli/plugin-create-module.md +88 -0
- package/rules/.docs/zh-CN/tool/cli/plugin-create-project.md +106 -0
- package/rules/.docs/zh-CN/tool/cli/plugin-server.md +152 -0
- package/rules/.github/copilot-instructions.md +141 -1
- package/rules/.windsurfrules +141 -1
- package/rules/AGENTS.md +148 -1
- package/rules/AI_HANDOFF.md +131 -1
- package/rules/CLAUDE.md +148 -1
- package/rules/GEMINI.md +148 -1
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Plugin Server API
|
|
3
|
+
lang: zh-CN
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# 插件服务接口
|
|
7
|
+
|
|
8
|
+
## 一、概述
|
|
9
|
+
|
|
10
|
+
电视侧插件服务默认监听 `36366` 端口,接口根路径为:
|
|
11
|
+
|
|
12
|
+
```text
|
|
13
|
+
http://<tv-ip>:36366/api/v1
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
在调用 `/hello`、`/status`、`/uploadSo`、`/uploadPlugin` 之前,必须先通过 Toolkit 广播打开 `RESTFUL_API`。
|
|
17
|
+
|
|
18
|
+
重要约束:
|
|
19
|
+
|
|
20
|
+
1. 文档与接口返回不一致时,统一以接口真实返回为准。
|
|
21
|
+
2. 这些接口要求使用 `POST`;同路径 `GET` 在实测设备上可能返回 `404`。
|
|
22
|
+
3. `uploadSo` 已观察到 `pkg` / `tag` 字段漂移;调用时建议同时传这两个字段。
|
|
23
|
+
4. `status.pluginList` 可能在 `uploadPlugin` 返回 `registered: true` 后仍为空,这属于真实接口行为,不能自行推导为失败或成功安装完成。
|
|
24
|
+
5. QuickTVUI AI 工具在未显式传 `baseUrl` 时,会优先尝试 adb 已连接设备的插件服务地址;如果没有 adb 设备,AI 应先向用户索要服务 IP / `baseUrl`。
|
|
25
|
+
6. `abi` 只在上传 So 时才需要。CLI / MCP 如果在 `uploadSo` 时未显式传 `abi`,会尝试读取当前插件服务对应设备的 `ro.product.cpu.abi` 并按需补齐;`check` / `hello` / `status` / `uploadPlugin` 不会主动查询 ABI。
|
|
26
|
+
7. `uploadPlugin` 返回成功,只代表插件包已上传到插件服务缓存;如果 Vue 页面需要实际使用该插件,还必须在页面侧通过 `useESPlugin()` 监听并调用 `installPlugin({ pkg })`,不能把“上传成功”误当成“页面已安装完成”。
|
|
27
|
+
8. 上传新的插件包到服务后,当前宿主 / runtime 进程不会自动热更新到新字节码;复测启动、注册或页面接入前,必须先重启宿主进程。
|
|
28
|
+
|
|
29
|
+
## 二、开启服务
|
|
30
|
+
|
|
31
|
+
### 2.1 adb 广播
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
adb -s <serial> shell am broadcast -a "eskit.sdk.core.ACTION_TOOLKIT_SETTING" --es "RESTFUL_API" "true"
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### 2.2 QuickTVUI AI CLI
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
quicktvui-ai plugin-enable-api --device <serial>
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## 三、接口列表
|
|
44
|
+
|
|
45
|
+
### 3.1 `POST /hello`
|
|
46
|
+
|
|
47
|
+
用途:确认服务已启动。
|
|
48
|
+
|
|
49
|
+
典型响应:
|
|
50
|
+
|
|
51
|
+
```json
|
|
52
|
+
{
|
|
53
|
+
"code": 0,
|
|
54
|
+
"message": "success",
|
|
55
|
+
"data": {}
|
|
56
|
+
}
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### 3.2 `POST /status`
|
|
60
|
+
|
|
61
|
+
用途:读取当前插件服务缓存状态。
|
|
62
|
+
|
|
63
|
+
典型响应:
|
|
64
|
+
|
|
65
|
+
```json
|
|
66
|
+
{
|
|
67
|
+
"code": 0,
|
|
68
|
+
"message": "success",
|
|
69
|
+
"data": {
|
|
70
|
+
"soList": [
|
|
71
|
+
"eskit.so.player.v1"
|
|
72
|
+
],
|
|
73
|
+
"pluginList": []
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
说明:
|
|
79
|
+
|
|
80
|
+
1. `soList` / `pluginList` 反映的是当前服务返回的数据,不应脑补额外状态。
|
|
81
|
+
2. 即使上传插件成功,`pluginList` 也可能仍为空。
|
|
82
|
+
|
|
83
|
+
### 3.3 `POST /uploadSo`
|
|
84
|
+
|
|
85
|
+
用途:上传 So zip。
|
|
86
|
+
|
|
87
|
+
推荐请求方式:`multipart/form-data`
|
|
88
|
+
|
|
89
|
+
建议字段:
|
|
90
|
+
|
|
91
|
+
| 字段 | 必填 | 说明 |
|
|
92
|
+
| ---- | ---- | ---- |
|
|
93
|
+
| `tag` | 是 | So 标识,建议与包名保持一致 |
|
|
94
|
+
| `pkg` | 是 | 兼容字段,当前建议与 `tag` 同时传 |
|
|
95
|
+
| `abi` | 是 | 目标设备 ABI,例如 `armeabi-v7a` / `arm64-v8a`;CLI / MCP 在 `uploadSo` 且未显式传值时,会尝试按当前服务目标设备自动补齐 |
|
|
96
|
+
| `osCpuAbi` | 否 | 建议与 `abi` 保持一致 |
|
|
97
|
+
| `file` | 是 | zip 文件 |
|
|
98
|
+
| `fileName` / `name` | 否 | 上传文件名 |
|
|
99
|
+
|
|
100
|
+
空请求实测返回:
|
|
101
|
+
|
|
102
|
+
```json
|
|
103
|
+
{
|
|
104
|
+
"code": 400,
|
|
105
|
+
"message": "tag is required",
|
|
106
|
+
"data": null
|
|
107
|
+
}
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
成功响应示例:
|
|
111
|
+
|
|
112
|
+
```json
|
|
113
|
+
{
|
|
114
|
+
"code": 0,
|
|
115
|
+
"message": "success",
|
|
116
|
+
"data": {
|
|
117
|
+
"tag": "eskit.so.ffmpeg.command",
|
|
118
|
+
"abi": "armeabi-v7a",
|
|
119
|
+
"fileName": "armeabi-v7a.zip",
|
|
120
|
+
"filePath": "/data/user/0/tv.eskit.debugger/cache/rpk/local_install_so/eskit.so.ffmpeg.command/armeabi-v7a/armeabi-v7a.zip",
|
|
121
|
+
"size": 4623751,
|
|
122
|
+
"registered": true
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
说明:
|
|
128
|
+
|
|
129
|
+
1. 返回字段以 `data.tag` 为准。
|
|
130
|
+
2. `filePath` 实测会带 `rpk/local_install_so/` 路径层级。
|
|
131
|
+
3. 上传前必须根据当前插件服务对应设备的 `ro.product.cpu.abi` 选择正确的 zip。
|
|
132
|
+
|
|
133
|
+
### 3.4 `POST /uploadPlugin`
|
|
134
|
+
|
|
135
|
+
用途:上传插件 APK。
|
|
136
|
+
|
|
137
|
+
推荐请求方式:`multipart/form-data`
|
|
138
|
+
|
|
139
|
+
建议字段:
|
|
140
|
+
|
|
141
|
+
| 字段 | 必填 | 说明 |
|
|
142
|
+
| ---- | ---- | ---- |
|
|
143
|
+
| `pkg` | 是 | 插件包名 |
|
|
144
|
+
| `packageName` | 否 | 兼容字段,建议与 `pkg` 同时传 |
|
|
145
|
+
| `file` | 是 | APK 文件 |
|
|
146
|
+
| `fileName` / `name` | 否 | 上传文件名 |
|
|
147
|
+
|
|
148
|
+
空请求实测返回:
|
|
149
|
+
|
|
150
|
+
```json
|
|
151
|
+
{
|
|
152
|
+
"code": 400,
|
|
153
|
+
"message": "pkg is required",
|
|
154
|
+
"data": null
|
|
155
|
+
}
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
成功响应示例:
|
|
159
|
+
|
|
160
|
+
```json
|
|
161
|
+
{
|
|
162
|
+
"code": 0,
|
|
163
|
+
"message": "success",
|
|
164
|
+
"data": {
|
|
165
|
+
"pkg": "eskit.plugin.imagequality",
|
|
166
|
+
"fileName": "plugin-general-debug.apk",
|
|
167
|
+
"filePath": "/data/user/0/tv.eskit.debugger/cache/rpk/local_upload_plugin/eskit.plugin.imagequality/plugin-general-debug.apk",
|
|
168
|
+
"size": 89578,
|
|
169
|
+
"registered": true
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
说明:
|
|
175
|
+
|
|
176
|
+
1. `filePath` 实测会带 `rpk/local_upload_plugin/` 路径层级。
|
|
177
|
+
2. `registered: true` 只代表接口返回注册成功,不代表 `status.pluginList` 一定马上可见。
|
|
178
|
+
3. 如果业务页面要真正使用该插件,还必须在 Vue 侧调用插件安装流程,推荐参考 `module/plugin` 文档、`module/plugin/es-basic.vue` 示例,以及 `quicktvui/src/long-image/index.vue` 的注册检查实现。
|
|
179
|
+
4. 如果上传成功但设备日志出现 `ClassNotFoundException: com.quicktvui.sdk.base.core.EsProxy` 或缺失 `com.quicktvui.sdk.base.*`,应视为运行时命名空间兼容性问题,而不是插件服务上传失败。
|
|
180
|
+
5. 如果设备日志出现 `java.lang.NoSuchMethodError: No static method get()Leskit/sdk/support/core/EsProxy;`,应视为插件注册入口的字节码签名与设备 runtime 不兼容;需要改成匹配设备真实 `EsProxy.get()` 签名 / 调用路径的实现后重新构建、重传。
|
|
181
|
+
6. 上传新的插件版本后,必须先重启宿主 / runtime 进程,再验证插件启动、注册和页面侧安装,否则当前进程仍可能持有旧插件字节码。
|
|
182
|
+
|
|
183
|
+
## 四、测试 Demo 标识
|
|
184
|
+
|
|
185
|
+
推荐默认测试标识:
|
|
186
|
+
|
|
187
|
+
| 类型 | 标识 |
|
|
188
|
+
| ---- | ---- |
|
|
189
|
+
| So 包名 / tag | `eskit.so.ffmpeg.command` |
|
|
190
|
+
| 插件包名 | `eskit.plugin.imagequality` |
|
|
191
|
+
|
|
192
|
+
本地测试文件映射:
|
|
193
|
+
|
|
194
|
+
| 文件 | 用途 | 对应标识 |
|
|
195
|
+
| ---- | ---- | -------- |
|
|
196
|
+
| `docs/plugin/arm64-v8a.zip` | arm64-v8a So 包 | `eskit.so.ffmpeg.command` |
|
|
197
|
+
| `docs/plugin/armeabi-v7a.zip` | armeabi-v7a So 包 | `eskit.so.ffmpeg.command` |
|
|
198
|
+
| `docs/plugin/plugin-general-debug.apk` | 插件 APK | `eskit.plugin.imagequality` |
|
|
@@ -23,4 +23,11 @@ lang: zh-CN
|
|
|
23
23
|
* 日志 [`qui logcat`](/zh-CN/tool/cli/logcat)
|
|
24
24
|
* 测试 [`qui test`](/zh-CN/tool/cli/test)
|
|
25
25
|
|
|
26
|
+
## QuickTVUI AI 插件工作流
|
|
27
|
+
|
|
28
|
+
* 插件服务联调 [`plugin-server`](/zh-CN/tool/cli/plugin-server)
|
|
29
|
+
* 插件工程创建与打包 [`plugin-create-project`](/zh-CN/tool/cli/plugin-create-project)
|
|
30
|
+
* 插件模块创建 [`plugin-create-module`](/zh-CN/tool/cli/plugin-create-module)
|
|
31
|
+
* 插件组件创建 [`plugin-create-component`](/zh-CN/tool/cli/plugin-create-component)
|
|
32
|
+
|
|
26
33
|
<img src="/tool/cli/cli.png" />
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Plugin Create Component
|
|
3
|
+
lang: zh-CN
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# 插件组件创建
|
|
7
|
+
|
|
8
|
+
## 一、适用范围
|
|
9
|
+
|
|
10
|
+
组件用于有原生 UI 的能力,例如二维码、卡片、轮播、支付入口、图片容器等。
|
|
11
|
+
|
|
12
|
+
如果只是无界面能力,请改用 `plugin-create-module`。
|
|
13
|
+
|
|
14
|
+
## 二、源码真值
|
|
15
|
+
|
|
16
|
+
生成组件前,必须优先对照:
|
|
17
|
+
|
|
18
|
+
1. `node_modules/@quicktvui/ai/rules/.source/sdk/base/sdk-base/src/main/java/com/quicktvui/sdk/base/component/IEsComponent.java`
|
|
19
|
+
2. `node_modules/@quicktvui/ai/rules/.source/sdk/base/sdk-base/src/main/java/com/quicktvui/sdk/base/component/IEsComponentView.java`
|
|
20
|
+
3. `node_modules/@quicktvui/ai/rules/.source/sdk/base/sdk-base/src/main/java/com/quicktvui/sdk/base/component/EsComponentAttribute.java`
|
|
21
|
+
|
|
22
|
+
真实接口:
|
|
23
|
+
|
|
24
|
+
```java
|
|
25
|
+
com.quicktvui.sdk.base.component.IEsComponent
|
|
26
|
+
com.quicktvui.sdk.base.component.IEsComponentView
|
|
27
|
+
com.quicktvui.sdk.base.component.EsComponentAttribute
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## 三、CLI 命令
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
quicktvui-ai plugin-create-component \
|
|
34
|
+
--project plugin/demo-plugin \
|
|
35
|
+
--description "展示二维码" \
|
|
36
|
+
--props '[{"name":"content","type":"String","description":"二维码内容"}]' \
|
|
37
|
+
--events onRendered \
|
|
38
|
+
--functions refresh
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## 四、MCP 工具
|
|
42
|
+
|
|
43
|
+
```text
|
|
44
|
+
plugin_component_create
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## 五、生成规则
|
|
48
|
+
|
|
49
|
+
1. `--description` 必填
|
|
50
|
+
2. 组件类名追加 `Component`
|
|
51
|
+
3. View 类名追加 `View`
|
|
52
|
+
4. Java 包名必须合法,不能把 `kebab-case` 直接写入包路径
|
|
53
|
+
5. Vue 标签必须使用 `kebab-case`
|
|
54
|
+
6. `--project` 默认应指向项目根目录下可见的 `plugin/<plugin-name>`,不要默认指向隐藏目录
|
|
55
|
+
7. 默认生成 `docs/component/<name>.md`
|
|
56
|
+
8. 默认不强依赖 `@ESKitAutoRegister`
|
|
57
|
+
9. 默认尝试在 `Application#onCreate` 中注册 `EsProxy.get().registerComponent("com.xxx.Component")`
|
|
58
|
+
10. 编译期接口由插件工程内的 `quicktvui-plugin-stubs` 模块提供;运行时依赖仍以模板工程里的 `com.extscreen.runtime:eskit:2.6.0` 为准
|
|
59
|
+
|
|
60
|
+
## 六、Vue 侧安装约束
|
|
61
|
+
|
|
62
|
+
组件插件生成完成、打包完成或上传成功,并不代表 Vue 页面已经可以直接渲染该组件。
|
|
63
|
+
|
|
64
|
+
如果页面里要真正使用组件型插件,还必须:
|
|
65
|
+
|
|
66
|
+
1. 使用 `@extscreen/es3-core` 的 `useESPlugin()`
|
|
67
|
+
2. 在 `onESCreate` 中 `addListener(pluginInfo, listener)`
|
|
68
|
+
3. 在 `onESDestroy` 中 `removeListener(listener)`
|
|
69
|
+
4. 在组件未注册时调用 `installPlugin({ pkg })`
|
|
70
|
+
5. 优先使用 `useES().isComponentRegistered("<组件完整类名>")` 检查注册状态,再决定是否渲染组件
|
|
71
|
+
|
|
72
|
+
推荐参考:
|
|
73
|
+
|
|
74
|
+
1. `node_modules/@quicktvui/ai/rules/.docs/zh-CN/module/plugin.md`
|
|
75
|
+
2. `node_modules/@quicktvui/ai/rules/.docs/examples/module/plugin/es-basic.vue`
|
|
76
|
+
3. `node_modules/@quicktvui/ai/rules/.source/quicktvui/src/long-image/index.vue`
|
|
77
|
+
|
|
78
|
+
## 七、运行时兼容约束
|
|
79
|
+
|
|
80
|
+
1. 组件骨架默认仍以 `com.quicktvui.sdk.base.component.*` 和 `EsProxy` 的源码结构为准。
|
|
81
|
+
2. 但如果设备日志出现 `ClassNotFoundException: com.quicktvui.sdk.base.core.EsProxy`,或提示缺失 `com.quicktvui.sdk.base.*`,必须把设备日志视为运行时命名空间兼容性的最高优先级信号。
|
|
82
|
+
3. 这说明本地 stub 虽然可编译,但目标 TV 运行时并没有这套类;此时应切换运行时侧注册/导入到设备实际存在的命名空间后重新构建、重传。
|
|
83
|
+
4. 如果设备日志出现 `java.lang.NoSuchMethodError: No static method get()Leskit/sdk/support/core/EsProxy;`,必须把它视为插件注册入口的字节码签名不兼容,而不是页面逻辑问题;应按设备真实 runtime 的 `EsProxy.get()` 签名 / 调用路径调整注册实现后重新构建、重传。
|
|
84
|
+
5. 页面侧安装成功回调后,如果组件注册仍短暂不可见,允许一个简短轮询复查窗口,再决定是否判定失败。
|
|
85
|
+
6. 如果是为修复运行时兼容性而重新上传的新插件版本,复测前必须先重启宿主 / runtime 进程,否则当前进程仍可能持有旧插件字节码。
|
|
86
|
+
|
|
87
|
+
## 八、关键参数
|
|
88
|
+
|
|
89
|
+
| 参数 | 说明 |
|
|
90
|
+
| ---- | ---- |
|
|
91
|
+
| `--description <text>` | 功能描述,必填 |
|
|
92
|
+
| `--class-name <name>` | 显式组件类名 |
|
|
93
|
+
| `--view-class-name <name>` | 显式 View 类名 |
|
|
94
|
+
| `--view-base-class <name>` | View 基类 |
|
|
95
|
+
| `--package-name <pkg>` | 显式包名 |
|
|
96
|
+
| `--props <json|csv>` | 属性列表 |
|
|
97
|
+
| `--events <json|csv>` | 事件列表 |
|
|
98
|
+
| `--functions <json|csv>` | dispatchFunction 列表 |
|
|
99
|
+
| `--docs-dir <path>` | 组件文档目录 |
|
|
100
|
+
| `--native-tag-name <name>` | 原生标签名 |
|
|
101
|
+
| `--wrapper-tag-name <name>` | 包装组件标签名 |
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Plugin Create Module
|
|
3
|
+
lang: zh-CN
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# 插件模块创建
|
|
7
|
+
|
|
8
|
+
## 一、适用范围
|
|
9
|
+
|
|
10
|
+
模块用于无独立原生 UI 的能力封装,例如设备信息、网络能力、Toast、下载、埋点等。
|
|
11
|
+
|
|
12
|
+
如果需要原生 View、属性、UI 事件,应改用 `plugin-create-component`。
|
|
13
|
+
|
|
14
|
+
## 二、源码真值
|
|
15
|
+
|
|
16
|
+
生成模块前,必须优先对照:
|
|
17
|
+
|
|
18
|
+
1. `node_modules/@quicktvui/ai/rules/.source/sdk/base/sdk-base/src/main/java/com/quicktvui/sdk/base/module/IEsModule.java`
|
|
19
|
+
2. `node_modules/@quicktvui/ai/rules/.source/sdk/base/sdk-base/src/main/java/com/quicktvui/sdk/base/core/EsProxy.java`
|
|
20
|
+
|
|
21
|
+
真实接口:
|
|
22
|
+
|
|
23
|
+
```java
|
|
24
|
+
com.quicktvui.sdk.base.module.IEsModule
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## 三、CLI 命令
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
quicktvui-ai plugin-create-module \
|
|
31
|
+
--project plugin/demo-plugin \
|
|
32
|
+
--description "展示设备信息" \
|
|
33
|
+
--methods "showInfo,getInfo"
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## 四、MCP 工具
|
|
37
|
+
|
|
38
|
+
```text
|
|
39
|
+
plugin_module_create
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## 五、生成规则
|
|
43
|
+
|
|
44
|
+
1. `--description` 必填
|
|
45
|
+
2. 类名使用 PascalCase,并追加 `Module`
|
|
46
|
+
3. Java 包名必须合法,不能把 `kebab-case` 直接写入包路径
|
|
47
|
+
4. `--project` 默认应指向项目根目录下可见的 `plugin/<plugin-name>`,不要默认指向隐藏目录
|
|
48
|
+
5. 默认实现 `IEsModule`
|
|
49
|
+
6. 默认不强依赖 `@ESKitAutoRegister`
|
|
50
|
+
7. 默认尝试在 `Application#onCreate` 中注册 `EsProxy.get().registerModule("com.xxx.Module")`
|
|
51
|
+
8. 编译期接口由插件工程内的 `quicktvui-plugin-stubs` 模块提供;运行时依赖仍以模板工程里的 `com.extscreen.runtime:eskit:2.6.0` 为准
|
|
52
|
+
|
|
53
|
+
## 六、Vue 侧安装约束
|
|
54
|
+
|
|
55
|
+
模块插件生成完成、打包完成或上传成功,并不代表 Vue 页面已经可以直接调用该模块。
|
|
56
|
+
|
|
57
|
+
如果页面里要真正使用插件模块,还必须:
|
|
58
|
+
|
|
59
|
+
1. 使用 `@extscreen/es3-core` 的 `useESPlugin()`
|
|
60
|
+
2. 在 `onESCreate` 中 `addListener(pluginInfo, listener)`
|
|
61
|
+
3. 在 `onESDestroy` 中 `removeListener(listener)`
|
|
62
|
+
4. 在插件尚未可用时调用 `installPlugin({ pkg })`
|
|
63
|
+
|
|
64
|
+
推荐参考:
|
|
65
|
+
|
|
66
|
+
1. `node_modules/@quicktvui/ai/rules/.docs/zh-CN/module/plugin.md`
|
|
67
|
+
2. `node_modules/@quicktvui/ai/rules/.docs/examples/module/plugin/es-basic.vue`
|
|
68
|
+
|
|
69
|
+
## 七、运行时兼容约束
|
|
70
|
+
|
|
71
|
+
1. 模块骨架默认仍以 `com.quicktvui.sdk.base.module.IEsModule` 和 `EsProxy` 的源码结构为准。
|
|
72
|
+
2. 但如果设备日志出现 `ClassNotFoundException: com.quicktvui.sdk.base.core.EsProxy`,或提示缺失 `com.quicktvui.sdk.base.*`,必须把设备日志视为运行时命名空间兼容性的最高优先级信号。
|
|
73
|
+
3. 这说明本地 stub 虽然可编译,但目标 TV 运行时并没有这套类;此时应切换运行时侧注册/导入到设备实际存在的命名空间后重新构建、重传。
|
|
74
|
+
4. 如果设备日志出现 `java.lang.NoSuchMethodError: No static method get()Leskit/sdk/support/core/EsProxy;`,必须把它视为插件注册入口的字节码签名不兼容,而不是页面逻辑问题;应按设备真实 runtime 的 `EsProxy.get()` 签名 / 调用路径调整注册实现后重新构建、重传。
|
|
75
|
+
5. 页面侧安装成功回调后,如果模块注册仍短暂不可见,允许一个简短轮询复查窗口,再决定是否判定失败。
|
|
76
|
+
6. 如果是为修复运行时兼容性而重新上传的新插件版本,复测前必须先重启宿主 / runtime 进程,否则当前进程仍可能持有旧插件字节码。
|
|
77
|
+
|
|
78
|
+
## 八、关键参数
|
|
79
|
+
|
|
80
|
+
| 参数 | 说明 |
|
|
81
|
+
| ---- | ---- |
|
|
82
|
+
| `--description <text>` | 功能描述,必填 |
|
|
83
|
+
| `--class-name <name>` | 显式类名 |
|
|
84
|
+
| `--package-name <pkg>` | 显式包名 |
|
|
85
|
+
| `--methods <json|csv>` | 对外暴露方法 |
|
|
86
|
+
| `--register <true|false>` | 是否自动注册 |
|
|
87
|
+
| `--app-file <path>` | 指定 Application 文件 |
|
|
88
|
+
| `--src-root <path>` | 指定源码根目录 |
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Plugin Create Project
|
|
3
|
+
lang: zh-CN
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# 插件工程创建与打包
|
|
7
|
+
|
|
8
|
+
## 一、推荐入口
|
|
9
|
+
|
|
10
|
+
1. 优先使用 MCP:`plugin_project_create`、`plugin_project_build`
|
|
11
|
+
2. 没有 MCP 时,使用 CLI:`quicktvui-ai plugin-create-project`、`quicktvui-ai plugin-build`
|
|
12
|
+
3. 只有两者都不可用时,才手工执行 `git clone` / `gradlew`
|
|
13
|
+
|
|
14
|
+
## 二、创建命令
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
quicktvui-ai plugin-create-project plugin/demo-plugin \
|
|
18
|
+
--workspace-root . \
|
|
19
|
+
--package-name com.qtapp.plugin.demo
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
关键行为:
|
|
23
|
+
|
|
24
|
+
1. 默认模板仓库:`https://gitlab01.huan.tv/weipeng/eskit-plugin-template.git`
|
|
25
|
+
2. 创建成功后写入 `.kyy-plugin-project.json`
|
|
26
|
+
3. 如指定 `--package-name`,会同步改清单、源码包声明和包目录
|
|
27
|
+
4. 会补充本地编译支撑模块 `quicktvui-plugin-stubs`
|
|
28
|
+
5. 会在 `settings.gradle` 中追加 `include ':quicktvui-plugin-stubs'`
|
|
29
|
+
6. 会在 `app/build.gradle` 中追加 `compileOnly project(':quicktvui-plugin-stubs')`
|
|
30
|
+
7. 若创建到子目录且工作区根有 `package.json`,会注入 `build:android-plugin`
|
|
31
|
+
8. 长期保留或准备发布的插件工程,默认放到项目根目录下可见的 `plugin/` 目录,例如 `plugin/demo-plugin`
|
|
32
|
+
9. 不要把插件工程默认放到 `.ai-test/*` 等隐藏目录
|
|
33
|
+
|
|
34
|
+
## 三、更新模式
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
quicktvui-ai plugin-create-project plugin/demo-plugin --mode update
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
说明:
|
|
41
|
+
|
|
42
|
+
1. `update` 仅允许用于已带 `.kyy-plugin-project.json` 的工程
|
|
43
|
+
2. 非插件工程目录拒绝更新,避免误改
|
|
44
|
+
|
|
45
|
+
## 四、打包命令
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
quicktvui-ai plugin-build plugin/demo-plugin
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
固定优先级:
|
|
52
|
+
|
|
53
|
+
1. `npm run build:android-plugin`
|
|
54
|
+
2. `npm run build:plugin`
|
|
55
|
+
3. `npm run build`
|
|
56
|
+
4. `./gradlew assembleGeneralDebug`
|
|
57
|
+
|
|
58
|
+
说明:
|
|
59
|
+
|
|
60
|
+
1. 模板运行时依赖仍以 `com.extscreen.runtime:eskit:2.6.0` 为准
|
|
61
|
+
2. `quicktvui-plugin-stubs` 只用于补齐脚手架生成代码的编译期接口
|
|
62
|
+
3. 构建前会优先从 `ANDROID_SDK_ROOT`、`ANDROID_HOME` 和当前平台默认 Android SDK 目录中自动探测 SDK
|
|
63
|
+
4. 如探测到 SDK 且目标工程缺少 `local.properties` / `sdk.dir`,CLI 会在目标插件工程内自动补齐本地 `local.properties`
|
|
64
|
+
5. `local.properties` 属于开发机本地文件,不应提交到共享仓库
|
|
65
|
+
|
|
66
|
+
## 五、Vue 侧安装约束
|
|
67
|
+
|
|
68
|
+
插件工程创建、打包或插件服务上传成功,并不代表 Vue 页面已经可以直接使用插件。
|
|
69
|
+
|
|
70
|
+
如果业务页面需要真正接入插件,必须额外补齐:
|
|
71
|
+
|
|
72
|
+
1. 使用 `@extscreen/es3-core` 的 `useESPlugin()`
|
|
73
|
+
2. 在 `onESCreate` 中 `addListener(pluginInfo, listener)`
|
|
74
|
+
3. 在 `onESDestroy` 中 `removeListener(listener)`
|
|
75
|
+
4. 在插件尚未可用时调用 `installPlugin({ pkg })`
|
|
76
|
+
5. 如果是组件型插件,优先使用 `useES().isComponentRegistered("<组件完整类名>")` 检查是否已注册,再决定是否安装或渲染
|
|
77
|
+
|
|
78
|
+
推荐参考:
|
|
79
|
+
|
|
80
|
+
1. `node_modules/@quicktvui/ai/rules/.docs/zh-CN/module/plugin.md`
|
|
81
|
+
2. `node_modules/@quicktvui/ai/rules/.docs/examples/module/plugin/es-basic.vue`
|
|
82
|
+
3. `node_modules/@quicktvui/ai/rules/.source/quicktvui/src/long-image/index.vue`
|
|
83
|
+
|
|
84
|
+
## 六、运行时兼容约束
|
|
85
|
+
|
|
86
|
+
1. 脚手架结构默认仍以 `.source/sdk/base/...` 为准。
|
|
87
|
+
2. 但如果设备日志出现 `ClassNotFoundException: com.quicktvui.sdk.base.core.EsProxy`,或启动阶段提示缺失 `com.quicktvui.sdk.base.*`,必须把设备日志视为运行时命名空间兼容性的最高优先级信号。
|
|
88
|
+
3. 这通常意味着“本地 stub 能编译”但“目标 TV 运行时并没有这套类”;此时必须改为适配设备实际存在的运行时命名空间后重新构建、重传。
|
|
89
|
+
4. 如果设备日志出现 `java.lang.NoSuchMethodError: No static method get()Leskit/sdk/support/core/EsProxy;`,必须把它视为插件注册入口的字节码签名不兼容,而不是页面逻辑问题;应按设备真实 runtime 的 `EsProxy.get()` 签名 / 调用路径调整注册实现后重新构建、重传。
|
|
90
|
+
5. 页面侧安装成功回调后,如果组件或模块注册仍短暂不可见,允许一个简短轮询复查窗口,再决定是否判定失败。
|
|
91
|
+
6. 如果是为修复运行时兼容性而重新上传的新插件版本,复测前必须先重启宿主 / runtime 进程,否则当前进程仍可能持有旧插件字节码。
|
|
92
|
+
|
|
93
|
+
## 七、关键参数
|
|
94
|
+
|
|
95
|
+
| 参数 | 说明 |
|
|
96
|
+
| ---- | ---- |
|
|
97
|
+
| `--mode <create|update>` | 创建或更新 |
|
|
98
|
+
| `--template-repo <url>` | 自定义模板仓库 |
|
|
99
|
+
| `--package-name <pkg>` | 目标 Java 包名 |
|
|
100
|
+
| `--workspace-root <path>` | 工作区根目录 |
|
|
101
|
+
|
|
102
|
+
## 八、注意事项
|
|
103
|
+
|
|
104
|
+
1. 文档与实现不一致时,以 `quicktvui-ai-cli/lib/plugin-scaffold.js` 为准。
|
|
105
|
+
2. 创建到子目录时,建议始终传 `--workspace-root`,让根脚本注入更稳定。
|
|
106
|
+
3. 如果插件工程后续需要继续开发、交接或发布,优先使用项目根目录下的 `plugin/<plugin-name>` 路径。
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Plugin Server
|
|
3
|
+
lang: zh-CN
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# 插件服务 CLI 工作流
|
|
7
|
+
|
|
8
|
+
## 一、推荐优先级
|
|
9
|
+
|
|
10
|
+
当 AI 需要联调电视插件服务时,推荐优先级如下:
|
|
11
|
+
|
|
12
|
+
1. 优先使用 `quicktvui-ai-mcp`
|
|
13
|
+
2. 没有 MCP 时,使用 `quicktvui-ai plugin-*`
|
|
14
|
+
3. CLI 也不可用时,再退回手工 `adb` + `curl`
|
|
15
|
+
|
|
16
|
+
## 二、标准命令链路
|
|
17
|
+
|
|
18
|
+
### 2.1 打开 RESTful API
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
quicktvui-ai plugin-enable-api --device <serial>
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
说明:
|
|
25
|
+
|
|
26
|
+
1. 该命令内部会发送 `eskit.sdk.core.ACTION_TOOLKIT_SETTING`
|
|
27
|
+
2. 默认等价于 `RESTFUL_API=true`
|
|
28
|
+
3. 如需关闭,可显式传 `--enabled false`
|
|
29
|
+
|
|
30
|
+
### 2.2 检查服务可用性
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
quicktvui-ai plugin-check --device <serial>
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
说明:
|
|
37
|
+
|
|
38
|
+
1. 会以 `POST` 探测 `/hello`、`/status`、`/uploadSo`、`/uploadPlugin`
|
|
39
|
+
2. 同路径 `GET` 在实测设备上可能返回 `404`,不能据此判断服务未启动
|
|
40
|
+
3. `uploadSo` / `uploadPlugin` 返回缺参 `400` 视为“接口活着”,不是失败
|
|
41
|
+
|
|
42
|
+
### 2.3 查看当前状态
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
quicktvui-ai plugin-status --device <serial>
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### 2.4 上传 So
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
quicktvui-ai plugin-upload-so \
|
|
52
|
+
--device <serial> \
|
|
53
|
+
--tag eskit.so.ffmpeg.command \
|
|
54
|
+
--pkg eskit.so.ffmpeg.command \
|
|
55
|
+
--file docs/plugin/armeabi-v7a.zip
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
说明:
|
|
59
|
+
|
|
60
|
+
1. `--abi` 省略时,CLI 只会在执行 `uploadSo` 的这一刻,从当前插件服务对应设备读取 `ro.product.cpu.abi`
|
|
61
|
+
2. 建议总是同时传 `--tag` 和 `--pkg`
|
|
62
|
+
3. So zip 必须和设备 ABI 一致
|
|
63
|
+
|
|
64
|
+
### 2.5 上传插件 APK
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
quicktvui-ai plugin-upload-plugin \
|
|
68
|
+
--device <serial> \
|
|
69
|
+
--pkg eskit.plugin.imagequality \
|
|
70
|
+
--file docs/plugin/plugin-general-debug.apk
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
说明:
|
|
74
|
+
|
|
75
|
+
1. 上传成功只代表插件包已经进入插件服务缓存,不代表当前宿主进程已经切到新插件字节码
|
|
76
|
+
2. 如果上传的是新构建或覆盖上传的插件包,复测前必须先重启宿主 / runtime 进程
|
|
77
|
+
3. 宿主重启后,再继续做 Vue 页面安装、注册校验或启动验证
|
|
78
|
+
|
|
79
|
+
### 2.6 Vue 侧安装插件
|
|
80
|
+
|
|
81
|
+
`plugin-upload-plugin` 成功,只代表插件包已经进入插件服务缓存;如果页面里需要真正使用插件,还必须在 Vue 侧补齐安装流程。
|
|
82
|
+
|
|
83
|
+
标准约束:
|
|
84
|
+
|
|
85
|
+
1. 使用 `@extscreen/es3-core` 的 `useESPlugin()`
|
|
86
|
+
2. 在 `onESCreate` 中 `addListener(pluginInfo, listener)`
|
|
87
|
+
3. 在 `onESDestroy` 中 `removeListener(listener)`
|
|
88
|
+
4. 在插件尚未可用时调用 `installPlugin({ pkg })`
|
|
89
|
+
5. 如果是组件型插件,优先用 `useES().isComponentRegistered("<组件完整类名>")` 检查是否已注册,再决定是否安装或渲染
|
|
90
|
+
|
|
91
|
+
推荐参考:
|
|
92
|
+
|
|
93
|
+
1. `node_modules/@quicktvui/ai/rules/.docs/zh-CN/module/plugin.md`
|
|
94
|
+
2. `node_modules/@quicktvui/ai/rules/.docs/examples/module/plugin/es-basic.vue`
|
|
95
|
+
3. `node_modules/@quicktvui/ai/rules/.source/quicktvui/src/long-image/index.vue`
|
|
96
|
+
|
|
97
|
+
如果上传成功但插件启动失败,应继续看设备日志;若日志出现 `ClassNotFoundException: com.quicktvui.sdk.base.core.EsProxy` 或缺失 `com.quicktvui.sdk.base.*`,说明问题在运行时命名空间兼容性,而不是上传链路本身。若日志出现 `java.lang.NoSuchMethodError: No static method get()Leskit/sdk/support/core/EsProxy;`,则说明插件注册入口的字节码签名与设备 runtime 不兼容,必须改成匹配设备真实 `EsProxy.get()` 签名 / 调用路径的实现,重新构建、重传,并在复测前重启宿主进程。
|
|
98
|
+
|
|
99
|
+
## 三、关键参数
|
|
100
|
+
|
|
101
|
+
| 参数 | 说明 |
|
|
102
|
+
| ---- | ---- |
|
|
103
|
+
| `--device <serial>` | 目标 adb 设备序列号 |
|
|
104
|
+
| `--device-ip <ip[:port]>` | 先 `adb connect` 再执行命令 |
|
|
105
|
+
| `--plugin-base-url <url>` | 显式覆盖插件服务地址;不传时 CLI 会优先自动探测 |
|
|
106
|
+
| `--timeout-ms <n>` | 请求超时 |
|
|
107
|
+
| `--enabled <true|false>` | `plugin-enable-api` 的值 |
|
|
108
|
+
| `--tag` | So 标识 |
|
|
109
|
+
| `--pkg` | So 或插件包名 |
|
|
110
|
+
| `--abi` | 可选;仅在 `plugin-upload-so` 时使用,不传则按当前服务目标设备按需读取 |
|
|
111
|
+
| `--file` | 本地 zip/apk 文件 |
|
|
112
|
+
| `--file-name` | 覆盖上传文件名 |
|
|
113
|
+
|
|
114
|
+
## 四、地址自动解析与转发行为
|
|
115
|
+
|
|
116
|
+
不传 `--plugin-base-url` 时,CLI 会按下面顺序解析插件服务地址:
|
|
117
|
+
|
|
118
|
+
1. 如果 adb 已连接目标设备:
|
|
119
|
+
- 优先尝试该设备的插件服务地址
|
|
120
|
+
- 若无法从目标设备推断 host,则自动使用 adb 端口转发并回落到 `http://127.0.0.1:36366`
|
|
121
|
+
2. 如果同时连接了多台 adb 设备:
|
|
122
|
+
- 必须显式传 `--device <serial>`,或直接传 `--plugin-base-url`
|
|
123
|
+
3. 如果没有 adb 已连接设备:
|
|
124
|
+
- 交互模式下会提示输入服务 IP / URL
|
|
125
|
+
- 非交互模式下会直接报错,要求显式传 `--plugin-base-url`
|
|
126
|
+
|
|
127
|
+
如果目标是设备本地服务而本机回环地址无法直连,CLI 会自动尝试:
|
|
128
|
+
|
|
129
|
+
```bash
|
|
130
|
+
adb -s <serial> forward tcp:36366 tcp:36366
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
如果你已经知道电视局域网地址,也可以显式指定:
|
|
134
|
+
|
|
135
|
+
```bash
|
|
136
|
+
quicktvui-ai plugin-check --plugin-base-url http://<tv-ip>:36366
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
## 五、推荐测试标识
|
|
140
|
+
|
|
141
|
+
| 类型 | 标识 |
|
|
142
|
+
| ---- | ---- |
|
|
143
|
+
| So 包名 / tag | `eskit.so.ffmpeg.command` |
|
|
144
|
+
| 插件包名 | `eskit.plugin.imagequality` |
|
|
145
|
+
|
|
146
|
+
推荐测试文件:
|
|
147
|
+
|
|
148
|
+
| 文件 | 用途 |
|
|
149
|
+
| ---- | ---- |
|
|
150
|
+
| `docs/plugin/arm64-v8a.zip` | arm64-v8a So 包 |
|
|
151
|
+
| `docs/plugin/armeabi-v7a.zip` | armeabi-v7a So 包 |
|
|
152
|
+
| `docs/plugin/plugin-general-debug.apk` | 插件 APK |
|