@ohos-cpf/3rdloop 0.0.12 → 0.0.13
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/package.json +1 -1
- package/vendor/Server/Routes/controllers/LoopEngineController.js +36 -3
- package/vendor/Server/Routes/controllers/OrchestratorController.js +193 -9
- package/vendor/Server/Skills/flutter-build-test/SKILL.md +252 -0
- package/vendor/Server/Skills/flutter-build-test/assets/BUILDENV_TEMPLATE.md +42 -0
- package/vendor/Server/Skills/flutter-build-test/assets/BUILD_REPORT_TEMPLATE.md +64 -0
- package/vendor/Server/Skills/flutter-build-test/assets/README_SECTION_TEMPLATE.md +78 -0
- package/vendor/Server/Skills/flutter-build-test/references/BUILD_TROUBLESHOOTING.md +128 -0
- package/vendor/Server/Skills/flutter-build-test/references/DOC_UPDATE_GUIDE.md +119 -0
- package/vendor/Server/Skills/flutter-build-test/references/FLVM_GUIDE.md +89 -0
- package/vendor/Server/Skills/flutter-build-test/scripts/build-matrix.cjs +374 -0
- package/vendor/Server/Skills/flutter-build-test/scripts/locate-example.cjs +189 -0
- package/vendor/Server/Skills/flutter-build-test/scripts/update-buildenv.cjs +171 -0
- package/vendor/Server/Skills/flutter-code-use/SKILL.md +316 -0
- package/vendor/Server/Skills/flutter-code-use/references/event-channel.md +440 -0
- package/vendor/Server/Skills/flutter-code-use/references/federated.md +295 -0
- package/vendor/Server/Skills/flutter-code-use/references/ffi-binding-translate.md +130 -0
- package/vendor/Server/Skills/flutter-code-use/references/ffi-compile-from-source.md +169 -0
- package/vendor/Server/Skills/flutter-code-use/references/ffi-fetch-at-build.md +161 -0
- package/vendor/Server/Skills/flutter-code-use/references/ffi-prebuilt-bundle.md +175 -0
- package/vendor/Server/Skills/flutter-code-use/references/ffi-rhttp-guide.md +235 -0
- package/vendor/Server/Skills/flutter-code-use/references/ffi-rust-cross-compile.md +514 -0
- package/vendor/Server/Skills/flutter-code-use/references/ffi.md +220 -0
- package/vendor/Server/Skills/flutter-code-use/references/method-channel.md +643 -0
- package/vendor/Server/Skills/flutter-code-use/references/monorepo.md +188 -0
- package/vendor/Server/Skills/flutter-code-use/references/ohos-api-pitfalls.md +717 -0
- package/vendor/Server/Skills/flutter-code-use/references/platform-view.md +448 -0
- package/vendor/Server/Skills/flutter-code-use/references/pure-dart.md +180 -0
- package/vendor/Server/Skills/flutter-code-use/references/texture.md +459 -0
- package/vendor/Server/Skills/flutter-demo-code-generator/SKILL.md +270 -0
- package/vendor/Server/Skills/flutter-demo-code-generator/assets/PAGE_TEMPLATES.md +544 -0
- package/vendor/Server/Skills/flutter-demo-code-generator/references/CODE_STANDARDS.md +328 -0
- package/vendor/Server/Skills/flutter-demo-code-generator/references/DEMO_DOC_PARSING.md +126 -0
- package/vendor/Server/Skills/flutter-demo-code-generator/references/EXAMPLES.md +629 -0
- package/vendor/Server/Skills/flutter-demo-code-generator/scripts/validate-flutter-demo.cjs +268 -0
- package/vendor/Server/Skills/flutter-demo-doc-generator/SKILL.md +227 -0
- package/vendor/Server/Skills/flutter-demo-doc-generator/assets/DEMO_DOC_TEMPLATE.md +78 -0
- package/vendor/Server/Skills/flutter-demo-doc-generator/references/COVERAGE_REPORT_PARSING.md +174 -0
- package/vendor/Server/Skills/flutter-demo-doc-generator/references/EXAMPLES.md +162 -0
- package/vendor/Server/Skills/flutter-demo-doc-generator/references/MCP_TOOL_GUIDE.md +123 -0
- package/vendor/Server/Skills/flutter-demo-doc-generator/references/OUTPUT_FORMAT.md +190 -0
- package/vendor/Server/Skills/flutter-demo-doc-generator/references/QUALITY_CHECKLIST.md +83 -0
- package/vendor/Server/Skills/flutter-demo-doc-generator/scripts/validate-skill.cjs +259 -0
- package/vendor/Server/Skills/flutter-library-demo-coverage/SKILL.md +175 -0
- package/vendor/VERSION +3 -3
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* update-buildenv.cjs — 按编译矩阵结果更新 buildEnv.sh
|
|
4
|
+
*
|
|
5
|
+
* 行为:
|
|
6
|
+
* 1. 读取 {libRoot}/buildEnv.sh(不存在则按模板新建,含 Apache License 头)
|
|
7
|
+
* 2. FLUTTER_SDK_VERSION ← 最高支持版本实测通过的 flvm 分支名(来自 build-matrix-results.json)
|
|
8
|
+
* 3. BUILD_PKG_DIR ← 实际 example 相对路径(原值正确则不动,可 --pkg-dir 显式指定)
|
|
9
|
+
* 4. 只改变量行,保留 License 头与既有结构
|
|
10
|
+
* 5. 输出变更对照到 {outputDir}/buildenv-update-report.json
|
|
11
|
+
*
|
|
12
|
+
* 用法:
|
|
13
|
+
* node update-buildenv.cjs --source <libRoot> --results <build-matrix-results.json> \
|
|
14
|
+
* [--branch <flvm分支>] [--pkg-dir <example相对路径>] [--example <example绝对路径>]
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
'use strict';
|
|
18
|
+
|
|
19
|
+
const fs = require('node:fs');
|
|
20
|
+
const path = require('node:path');
|
|
21
|
+
|
|
22
|
+
// ── 参数解析 ─────────────────────────────────────────────
|
|
23
|
+
|
|
24
|
+
function parseArgs(argv) {
|
|
25
|
+
if (argv.length > 0 && typeof argv[0] === 'string' && argv[0].startsWith('{')) {
|
|
26
|
+
try { return JSON.parse(argv[0]); } catch (e) { return {}; }
|
|
27
|
+
}
|
|
28
|
+
const args = {};
|
|
29
|
+
for (let i = 0; i < argv.length; i++) {
|
|
30
|
+
switch (argv[i]) {
|
|
31
|
+
case '--source': args.source = argv[++i]; break;
|
|
32
|
+
case '--results': args.results = argv[++i]; break;
|
|
33
|
+
case '--branch': args.branch = argv[++i]; break;
|
|
34
|
+
case '--pkg-dir': args.pkgDir = argv[++i]; break;
|
|
35
|
+
case '--example': args.example = argv[++i]; break;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return args;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// ── buildEnv.sh 模板(新建时使用) ────────────────────────
|
|
42
|
+
|
|
43
|
+
const BUILDENV_TEMPLATE = [
|
|
44
|
+
'#!/bin/bash',
|
|
45
|
+
' # Copyright (C) 2026 Huawei Device Co., Ltd.',
|
|
46
|
+
' # Licensed under the Apache License, Version 2.0 (the "License");',
|
|
47
|
+
' # you may not use this file except in compliance with the License.',
|
|
48
|
+
' # You may obtain a copy of the License at',
|
|
49
|
+
' #',
|
|
50
|
+
' # http://www.apache.org/licenses/LICENSE-2.0',
|
|
51
|
+
' #',
|
|
52
|
+
' # Unless required by applicable law or agreed to in writing, software',
|
|
53
|
+
' # distributed under the License is distributed on an "AS IS" BASIS,',
|
|
54
|
+
' # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.',
|
|
55
|
+
' # See the License for the specific language governing permissions and',
|
|
56
|
+
' # limitations under the License.',
|
|
57
|
+
' #/',
|
|
58
|
+
' ',
|
|
59
|
+
' BUILD_PKG_DIR=example',
|
|
60
|
+
' FLUTTER_SDK_VERSION=oh-3.35.7-dev',
|
|
61
|
+
'',
|
|
62
|
+
].join('\n');
|
|
63
|
+
|
|
64
|
+
// ── 主流程 ───────────────────────────────────────────────
|
|
65
|
+
|
|
66
|
+
function main() {
|
|
67
|
+
const args = parseArgs(process.argv.slice(2));
|
|
68
|
+
const libRoot = args.source ? path.resolve(args.source) : null;
|
|
69
|
+
if (!libRoot || !fs.existsSync(libRoot)) {
|
|
70
|
+
console.error('[update-buildenv] 错误: --source 必须为存在的目录');
|
|
71
|
+
process.exit(1);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// 读取编译结果,确定最高支持版本分支
|
|
75
|
+
let results = null;
|
|
76
|
+
if (args.results && fs.existsSync(args.results)) {
|
|
77
|
+
try { results = JSON.parse(fs.readFileSync(args.results, 'utf-8')); } catch (e) {
|
|
78
|
+
console.error(`[update-buildenv] 错误: results 文件解析失败: ${args.results}`);
|
|
79
|
+
process.exit(1);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
let targetBranch = args.branch || null;
|
|
84
|
+
let bestVersion = null;
|
|
85
|
+
if (!targetBranch && results) {
|
|
86
|
+
const pass = Object.values(results.versions || {}).filter((v) => v.status === 'pass' && v.branch);
|
|
87
|
+
if (pass.length > 0) {
|
|
88
|
+
pass.sort((a, b) => parseFloat(a.version) - parseFloat(b.version));
|
|
89
|
+
bestVersion = pass[pass.length - 1];
|
|
90
|
+
targetBranch = bestVersion.branch;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
if (!targetBranch) {
|
|
95
|
+
console.error('[update-buildenv] 错误: 无法确定目标分支(results 中无通过版本且未指定 --branch)');
|
|
96
|
+
console.error('[update-buildenv] 所有版本均失败时不应修改 FLUTTER_SDK_VERSION,请在报告中标注');
|
|
97
|
+
process.exit(1);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// 确定 BUILD_PKG_DIR
|
|
101
|
+
let pkgDir = args.pkgDir || null;
|
|
102
|
+
if (!pkgDir && results && results.exampleDir && results.libRoot) {
|
|
103
|
+
const rel = path.relative(path.resolve(results.libRoot), path.resolve(results.exampleDir));
|
|
104
|
+
if (rel && !rel.startsWith('..')) pkgDir = rel.split(path.sep).join('/');
|
|
105
|
+
}
|
|
106
|
+
if (!pkgDir && args.example) {
|
|
107
|
+
const rel = path.relative(libRoot, path.resolve(args.example));
|
|
108
|
+
if (rel && !rel.startsWith('..')) pkgDir = rel.split(path.sep).join('/');
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
const envFile = path.join(libRoot, 'buildEnv.sh');
|
|
112
|
+
const existed = fs.existsSync(envFile);
|
|
113
|
+
const before = existed ? fs.readFileSync(envFile, 'utf-8') : null;
|
|
114
|
+
|
|
115
|
+
// 解析现有值
|
|
116
|
+
const oldPkgDir = before ? ((before.match(/^\s*BUILD_PKG_DIR\s*=\s*(.+)$/m) || [])[1] || '').trim().replace(/^["']|["']$/g, '') : null;
|
|
117
|
+
const oldSdk = before ? ((before.match(/^\s*FLUTTER_SDK_VERSION\s*=\s*(.+)$/m) || [])[1] || '').trim().replace(/^["']|["']$/g, '') : null;
|
|
118
|
+
|
|
119
|
+
let content;
|
|
120
|
+
if (existed) {
|
|
121
|
+
content = before;
|
|
122
|
+
// FLUTTER_SDK_VERSION 必改(保留行首缩进)
|
|
123
|
+
if (/^\s*FLUTTER_SDK_VERSION\s*=.*$/m.test(content)) {
|
|
124
|
+
content = content.replace(/^(\s*)FLUTTER_SDK_VERSION\s*=.*$/m, `$1FLUTTER_SDK_VERSION=${targetBranch}`);
|
|
125
|
+
} else {
|
|
126
|
+
content = `${content.replace(/\s*$/, '')}\nFLUTTER_SDK_VERSION=${targetBranch}\n`;
|
|
127
|
+
}
|
|
128
|
+
// BUILD_PKG_DIR:显式指定或原值缺失才改(保留行首缩进)
|
|
129
|
+
if (pkgDir && (!oldPkgDir || oldPkgDir !== pkgDir)) {
|
|
130
|
+
if (args.pkgDir || !oldPkgDir) {
|
|
131
|
+
if (/^\s*BUILD_PKG_DIR\s*=.*$/m.test(content)) {
|
|
132
|
+
content = content.replace(/^(\s*)BUILD_PKG_DIR\s*=.*$/m, `$1BUILD_PKG_DIR=${pkgDir}`);
|
|
133
|
+
} else {
|
|
134
|
+
content = `${content.replace(/\s*$/, '')}\nBUILD_PKG_DIR=${pkgDir}\n`;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
} else {
|
|
139
|
+
content = BUILDENV_TEMPLATE;
|
|
140
|
+
if (pkgDir && pkgDir !== 'example') {
|
|
141
|
+
content = content.replace('BUILD_PKG_DIR=example', `BUILD_PKG_DIR=${pkgDir}`);
|
|
142
|
+
}
|
|
143
|
+
content = content.replace('FLUTTER_SDK_VERSION=oh-3.35.7-dev', `FLUTTER_SDK_VERSION=${targetBranch}`);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
fs.writeFileSync(envFile, content, 'utf-8');
|
|
147
|
+
fs.chmodSync(envFile, 0o755);
|
|
148
|
+
|
|
149
|
+
// 变更报告
|
|
150
|
+
const report = {
|
|
151
|
+
file: envFile,
|
|
152
|
+
created: !existed,
|
|
153
|
+
changes: [
|
|
154
|
+
{ key: 'FLUTTER_SDK_VERSION', before: oldSdk, after: targetBranch, changed: oldSdk !== targetBranch },
|
|
155
|
+
],
|
|
156
|
+
buildPkgDir: { before: oldPkgDir, after: pkgDir || oldPkgDir, changed: !!pkgDir && oldPkgDir !== pkgDir && (args.pkgDir || !oldPkgDir) },
|
|
157
|
+
basis: bestVersion ? { highestPassVersion: bestVersion.version, branchUsed: bestVersion.branch } : { explicitBranch: args.branch },
|
|
158
|
+
};
|
|
159
|
+
const outputDir = args.results ? path.dirname(path.resolve(args.results)) : libRoot;
|
|
160
|
+
const reportFile = path.join(outputDir, 'buildenv-update-report.json');
|
|
161
|
+
fs.writeFileSync(reportFile, JSON.stringify(report, null, 2), 'utf-8');
|
|
162
|
+
|
|
163
|
+
console.log(`[update-buildenv] ${existed ? '已更新' : '已新建'}: ${envFile}`);
|
|
164
|
+
console.log(`[update-buildenv] FLUTTER_SDK_VERSION: ${oldSdk || '(无)'} → ${targetBranch}`);
|
|
165
|
+
if (bestVersion) console.log(`[update-buildenv] 依据: 最高支持版本 ${bestVersion.version}(实测通过分支 ${bestVersion.branch})`);
|
|
166
|
+
if (report.buildPkgDir.changed) console.log(`[update-buildenv] BUILD_PKG_DIR: ${oldPkgDir || '(无)'} → ${report.buildPkgDir.after}`);
|
|
167
|
+
else console.log(`[update-buildenv] BUILD_PKG_DIR: 保持 ${oldPkgDir || pkgDir || 'example'}`);
|
|
168
|
+
console.log(`[update-buildenv] 变更报告: ${reportFile}`);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
main();
|
|
@@ -0,0 +1,316 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: flutter-code-use
|
|
3
|
+
description: Flutter 三方插件 HarmonyOS(ohos) 平台适配编码指导。读取 .ohos-adaptation 分析产物确定 plugin_type,按类型分发加载 MethodChannel/EventChannel/FFI/PlatformView/Texture/纯 Dart/联合插件/Monorepo 指导文件,严格按「工程配置→编码实现→编译错误修复」三部分执行,并用官方文档查证 Kit API 与运行时权限。当需要为 Flutter 插件新增 ohos 平台实现、编写 ohos/ 目录原生 ArkTS 代码、配置 ohos 工程产物,或修复 ohos 适配编译错误时使用。
|
|
4
|
+
license: Apache-2.0
|
|
5
|
+
compatibility: 需要 Flutter OHOS 分支 SDK(支持 --platforms ohos 与 Platform.isOhos)、DevEco Studio + OHOS SDK、hvigor/ohpm 构建环境;可选 MCP Gateway 运行中(script_deveco_docs 文档查证、kb_search 知识库检索)
|
|
6
|
+
metadata:
|
|
7
|
+
author: LoopEngine
|
|
8
|
+
version: "1.0.0"
|
|
9
|
+
category: code-generation
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
# Flutter Code Use — Flutter 插件鸿蒙适配编码指导
|
|
13
|
+
|
|
14
|
+
本技能用于**为 Flutter 三方插件编写 HarmonyOS(ohos) 平台适配代码**。核心流程:解析插件类型 → 分发加载类型指导 → 工程配置 → 编码实现 → 编译验证修复 → 交付自检。
|
|
15
|
+
|
|
16
|
+
> ⚠️ **核心原则:所有适配代码必须同时满足三条底线——① 公开 API 兼容(保持原 Flutter 公开调用方式与行为不变,辅助承载层/桥接层可封装在插件内部,不因适配改变对外契约);② 按类型分发(严格按分发表加载指导文件并执行其三部分结构,不凭记忆臆造工程配置);③ API 使用有据可查(HarmonyOS Kit 的 import 路径、签名、权限、API Level 经官方文档查证,user_grant 权限必须实现完整运行时申请流程)。**
|
|
17
|
+
|
|
18
|
+
> 📁 **路径约定**:本SKILL内所有文件引用路径均相对本SKILL根目录(如 `references/method-channel.md`)。
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## 任务参数
|
|
23
|
+
|
|
24
|
+
| 参数 | 类型 | 必填 | 说明 |
|
|
25
|
+
|------|------|------|------|
|
|
26
|
+
| `repoPath` | string | ✅ | Flutter 插件仓库根目录(含 `pubspec.yaml`),适配代码写入该仓库 |
|
|
27
|
+
| `analysisFile` | string | ❌ | 分析产物路径,默认 `{repoPath}/.ohos-adaptation/01-analysis.json`。不存在时现场回源码判定插件类型 |
|
|
28
|
+
| `planningFile` | string | ❌ | 规划产物路径,默认 `{repoPath}/.ohos-adaptation/02-planning.json`。FFI 类型必读(`ffi_strategy`/`ffi_strategy_caveat` 字段) |
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
## 输入依赖
|
|
33
|
+
|
|
34
|
+
- **前置SKILL**: 无。可作为独立任务调用;若上游分析/规划阶段已产出 `.ohos-adaptation/*.json` 则直接消费
|
|
35
|
+
- **输入文件**: 插件仓库(`pubspec.yaml`、`lib/`、`android/`/`ios/` 原生实现等);`.ohos-adaptation/01-analysis.json`(如已产出,关注 `plugin_type`、平台能力、依赖、权限、native 代码和 Example 覆盖范围)
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## 工作流程概览
|
|
40
|
+
|
|
41
|
+
```
|
|
42
|
+
Phase 1: 输入解析与插件类型识别
|
|
43
|
+
↓
|
|
44
|
+
Phase 2: 指导文件分发加载(类型分发表 + 组合能力/仓库形态/API 陷阱信号)
|
|
45
|
+
↓
|
|
46
|
+
Phase 3: 工程配置(第一部分)
|
|
47
|
+
↓
|
|
48
|
+
Phase 4: 编码实现(第二部分,含通用硬规则与 API 查证)
|
|
49
|
+
↓
|
|
50
|
+
Phase 5: 编译验证与错误修复(第三部分)
|
|
51
|
+
↓
|
|
52
|
+
Phase 6: 交付自检
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
## Phase 1:输入解析与插件类型识别
|
|
58
|
+
|
|
59
|
+
### 1.1 读取分析产物
|
|
60
|
+
|
|
61
|
+
读取 `analysisFile`(默认 `.ohos-adaptation/01-analysis.json`),提取:
|
|
62
|
+
|
|
63
|
+
| 字段 | 用途 |
|
|
64
|
+
|------|------|
|
|
65
|
+
| `plugin_type` | Phase 2 分发入口(类型分发表) |
|
|
66
|
+
| 平台能力 / native 代码 | 组合能力信号判定(Phase 2.2) |
|
|
67
|
+
| 依赖 / 权限 | 工程配置输入(ohpm 依赖映射、`requestPermissions`) |
|
|
68
|
+
| Example 覆盖范围 | 验证阶段回归范围 |
|
|
69
|
+
|
|
70
|
+
FFI 类型(`plugin_type` 为 `ffi`)另读 `planningFile` 的 `ffi_strategy` 与 `ffi_strategy_caveat` 字段。
|
|
71
|
+
|
|
72
|
+
### 1.2 类型缺失时回源码判定
|
|
73
|
+
|
|
74
|
+
`plugin_type` 为 `unknown` 或无分析产物时,回源码判定:
|
|
75
|
+
|
|
76
|
+
| 源码信号 | 判定类型 |
|
|
77
|
+
|----------|---------|
|
|
78
|
+
| `MethodChannel(`/`MethodCall` | method-channel(主通道) |
|
|
79
|
+
| `EventChannel(` | event-channel |
|
|
80
|
+
| `dart:ffi` / `DynamicLibrary` / `Cargo.toml` / `CMakeLists.txt` | ffi |
|
|
81
|
+
| `PlatformViewFactory` / `registerViewFactory` / `viewType` | platform-view |
|
|
82
|
+
| `TextureRegistry` / `createSurface` / `surfaceId` | texture |
|
|
83
|
+
| 无 `android/`、`ios/` 目录且纯 Dart | pure-dart |
|
|
84
|
+
|
|
85
|
+
### 1.3 适配边界判定
|
|
86
|
+
|
|
87
|
+
- 目标库为 rhttp 或基于 flutter_rust_bridge 的 HTTP 客户端 → 补读 [references/ffi-rhttp-guide.md](references/ffi-rhttp-guide.md)(实战验证的决策路径)
|
|
88
|
+
- FFI 不可适配判定(预编译二进制无源码且无 arm64、深度依赖 Android/iOS 专有系统库、ABI 不兼容)→ 按 [references/ffi.md](references/ffi.md) 的「FFI 不可适配判定」节处理,标记 `not_supported` 并在分析/规划产物中记录原因
|
|
89
|
+
- **必须先查 `flutter-adapted-library` Skill 数据库**,确认是否已有适配版本,避免重复适配
|
|
90
|
+
|
|
91
|
+
---
|
|
92
|
+
|
|
93
|
+
## Phase 2:指导文件分发加载
|
|
94
|
+
|
|
95
|
+
> **目标:只加载必需的指导文件(渐进式披露),不要全量加载。**
|
|
96
|
+
|
|
97
|
+
### 2.1 类型分发表(基础入口,只加载一份)
|
|
98
|
+
|
|
99
|
+
| `plugin_type` | 加载文件 | 说明 |
|
|
100
|
+
|---------------|----------|------|
|
|
101
|
+
| `plugin_method_channel` | [references/method-channel.md](references/method-channel.md) | MethodChannel 主通道插件 |
|
|
102
|
+
| `plugin_event_channel` | [references/event-channel.md](references/event-channel.md) | EventChannel 流式数据插件 |
|
|
103
|
+
| `ffi` | [references/ffi.md](references/ffi.md) | dart:ffi C/C++ 插件(先分诊再加载配方,见 2.4) |
|
|
104
|
+
| `plugin_platform_view` | [references/platform-view.md](references/platform-view.md) | PlatformView 原生视图插件 |
|
|
105
|
+
| `plugin_texture` | [references/texture.md](references/texture.md) | 外接纹理插件(视频/相机) |
|
|
106
|
+
| `dart` | [references/pure-dart.md](references/pure-dart.md) | 纯 Dart 包 |
|
|
107
|
+
| `plugin_mixed` | 先读 method-channel.md,再按能力补读相关文件 | 多种能力混合的插件 |
|
|
108
|
+
| `unknown` | 先回源码判断类型(Phase 1.2),再加载对应文件 | 类型暂不明确的插件 |
|
|
109
|
+
|
|
110
|
+
### 2.2 组合能力信号补读
|
|
111
|
+
|
|
112
|
+
`plugin_type` 只决定基础指导入口,不代表完整实现边界。出现下列信号时**必须**额外读取对应文件,不要只靠基础类型文件自行推断:
|
|
113
|
+
|
|
114
|
+
| 信号 | 补读文件 |
|
|
115
|
+
|------|---------|
|
|
116
|
+
| `PlatformView`、`viewType`、`registerViewFactory`、原生视图嵌入、ArkUI 承载组件 | [references/platform-view.md](references/platform-view.md) |
|
|
117
|
+
| `Texture`、`TextureRegistry`、`surfaceId`、外接纹理、渲染表面、预览层 | [references/texture.md](references/texture.md) |
|
|
118
|
+
| `EventChannel`、监听器、持续回调、状态流、进度流 | [references/event-channel.md](references/event-channel.md) |
|
|
119
|
+
| `ffi`、`so`、`napi`、`CMake`、C/C++ 复用 | [references/ffi.md](references/ffi.md) |
|
|
120
|
+
|
|
121
|
+
主方案由多种能力共同组成时,把基础类型文件作为脚手架,再组合辅助类型文件完成实现;不要因存在辅助实现层而改变原 Flutter 公开 API。
|
|
122
|
+
|
|
123
|
+
### 2.3 仓库形态补读
|
|
124
|
+
|
|
125
|
+
| 信号 | 补读文件 |
|
|
126
|
+
|------|---------|
|
|
127
|
+
| 联合插件、federated plugin、`platform_interface`、多个平台实现包 | [references/federated.md](references/federated.md) |
|
|
128
|
+
| 多包仓库、workspace、melos、多个 package 共同发布 | [references/monorepo.md](references/monorepo.md) |
|
|
129
|
+
|
|
130
|
+
### 2.4 FFI 策略配方分发
|
|
131
|
+
|
|
132
|
+
FFI 类型须先执行 [references/ffi.md](references/ffi.md) 的 §0 分诊(按 `ffi_strategy` 加载唯一配方)+ §G 反检验清单(校验策略与仓库实际内容一致)+ §F caveat 长尾处理:
|
|
133
|
+
|
|
134
|
+
| `ffi_strategy` | 加载配方 |
|
|
135
|
+
|---|---|
|
|
136
|
+
| `compile_from_source` | [references/ffi-compile-from-source.md](references/ffi-compile-from-source.md) |
|
|
137
|
+
| `rust_cross_compile` | [references/ffi-rust-cross-compile.md](references/ffi-rust-cross-compile.md) |
|
|
138
|
+
| `prebuilt_bundle` | [references/ffi-prebuilt-bundle.md](references/ffi-prebuilt-bundle.md) |
|
|
139
|
+
| `fetch_at_build` | [references/ffi-fetch-at-build.md](references/ffi-fetch-at-build.md) |
|
|
140
|
+
|
|
141
|
+
配方中触发 `@Native` 绑定翻译时补读 [references/ffi-binding-translate.md](references/ffi-binding-translate.md)。
|
|
142
|
+
|
|
143
|
+
### 2.5 API 陷阱信号补读
|
|
144
|
+
|
|
145
|
+
插件涉及以下场景时,必须额外读取 [references/ohos-api-pitfalls.md](references/ohos-api-pitfalls.md) 的对应章节:
|
|
146
|
+
|
|
147
|
+
| 场景信号 | 加载章节 | 说明 |
|
|
148
|
+
|----------|----------|------|
|
|
149
|
+
| SoundPool、短音频、提示音、beep | 第 1 章:音频 — SoundPool | 默认音量为 0、callback 形式优先 |
|
|
150
|
+
| AVPlayer、音频播放、视频播放、预加载 | 第 2 章:音频 — AVPlayer 状态机 | prepare 期间不能调 play/seek、onError 回环 |
|
|
151
|
+
| Toast、轻提示、showToast、弹窗提示 | 第 3 章:UI 提示 | 系统 Toast 与 CustomDialog 选型、SDK 版本边界 |
|
|
152
|
+
| 异步 API、Promise、callback | 第 4 章:异步 API | callback 与 Promise 行为差异 |
|
|
153
|
+
| MethodChannel 无参方法、生命周期回调 | 第 5 章:参数安全 | call.args 可能为 null |
|
|
154
|
+
| 传感器 | 第 6 章:传感器 | SensorResponse 必须属性访问、后台禁止调用传感器 |
|
|
155
|
+
| `url_launcher`、`launchUrl`、WebView、外部浏览器、默认打开模式 | 第 9 章:平台敏感默认模式 | 禁止依赖 OHOS 隐式默认映射,必须显式选择打开方式 |
|
|
156
|
+
| 状态栏、导航栏、fullscreen、avoid area、window、windowStage | 第 11 章:Window / WindowStage 生命周期 | `mainWindow` 不能只在 attach 时初始化一次,业务调用时要懒获取 |
|
|
157
|
+
| Share Kit、系统分享、ACTION_SEND、分享面板、ShareCompat | 第 12 章:Share Kit | UTD 类型、SharedRecord 类型、HAR import 限制 |
|
|
158
|
+
| AVTranscoder、视频转码、视频压缩、AVMetadataExtractor、AVFileDescriptor、fdSrc | 第 13 章:MediaKit — AVFileDescriptor 与 AVTranscoder | fdSrc 必须含 offset/length,视频尺寸必须偶数且在合法范围内 |
|
|
159
|
+
| PixelMap、图片编码、图片解码、Clipboard 图片、截图、Image.memory、ImagePacker、createImageSource、readPixelsToBuffer | 第 15 章:图片处理 — PixelMap 与 ImagePacker | readPixelsToBuffer 是裸像素,createImageSource 需要 ArrayBuffer |
|
|
160
|
+
|
|
161
|
+
---
|
|
162
|
+
|
|
163
|
+
## Phase 3:工程配置(第一部分)
|
|
164
|
+
|
|
165
|
+
> **目标:基于脚手架做增量配置,禁止凭空手写工程文件。**
|
|
166
|
+
|
|
167
|
+
### 3.1 脚手架生成
|
|
168
|
+
|
|
169
|
+
`ohos/` 目录由 Flutter OHOS SDK 的 `flutter create` 自动生成:
|
|
170
|
+
|
|
171
|
+
```bash
|
|
172
|
+
flutter create -t plugin --platforms ohos . # 普通插件
|
|
173
|
+
flutter create -t plugin_ffi --platforms ohos . # FFI 插件
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
**不要手动创建** `build-profile.json5`、`hvigorfile.ts`、`module.json5` 等配置文件,只对生成结果做自定义配置。
|
|
177
|
+
|
|
178
|
+
### 3.2 通用配置要点
|
|
179
|
+
|
|
180
|
+
以下为各类型共性的配置项(详细步骤以已加载类型文件的「第一部分:工程配置」为准):
|
|
181
|
+
|
|
182
|
+
| 配置项 | 要点 |
|
|
183
|
+
|--------|------|
|
|
184
|
+
| `pubspec.yaml` | `flutter create` 不会自动添加 ohos 平台声明,须手动补 `platforms.ohos`(`package`/`pluginClass`,FFI 为 `ffiPlugin: true`) |
|
|
185
|
+
| `ohos/oh-package.json5` | 按需追加 ohpm 三方依赖;`@ohos/flutter_ohos` 由构建工具自动注入,**禁止手动添加**(FFI 场景生成 `file:./libs/flutter.har` 时必须移除) |
|
|
186
|
+
| `build-profile.json5` | Bytecode HAR 依赖须开 `useNormalizedOHMUrl`;依赖要求更高 SDK 时升级 `compatibleSdkVersion`;FFI 须补 `externalNativeOptions` |
|
|
187
|
+
| `modelVersion` 一致性 | `example/ohos/hvigor/hvigor-config.json5` 与两级 `oh-package.json5` 的 `modelVersion` 必须完全一致,否则 hvigor 构建直接阻断 |
|
|
188
|
+
| `module.json5` | 按 `requestPermissions` 声明权限(清单来自分析产物 + Phase 4.2 查证结论) |
|
|
189
|
+
|
|
190
|
+
---
|
|
191
|
+
|
|
192
|
+
## Phase 4:编码实现(第二部分)
|
|
193
|
+
|
|
194
|
+
> 📐 本阶段生成的 ArkTS/ETS 代码须遵循已加载类型文件的「第二部分:编码实现」中的代码结构、import 语句、核心模式与类型映射。
|
|
195
|
+
|
|
196
|
+
### 4.1 公开 API 兼容
|
|
197
|
+
|
|
198
|
+
- Dart 层公开 API(类名、方法签名、行为语义)保持与上游一致,ohos 实现只做内部承载
|
|
199
|
+
- 平台检测统一使用 `Platform.isOhos`(与 Android 合并处理),**禁止**排除法(`!isAndroid && !isIOS`)或 `Platform.operatingSystem == 'ohos'` 字符串比较
|
|
200
|
+
|
|
201
|
+
### 4.2 通用硬规则(全类型适用)
|
|
202
|
+
|
|
203
|
+
**Kit 导入**:业务代码中使用 HarmonyOS Kit 模块时,在文件顶部静态导入(如 `import { dataSharePredicates } from '@kit.ArkData';`)。禁止在 MethodChannel、回调、循环或业务方法内部使用 `await import('@kit.Xxx')` 动态导入。
|
|
204
|
+
|
|
205
|
+
**运行时权限**:`module.json5` 中声明的权限属于 `user_grant` 类型时,必须实现完整申请流程:实现 `AbilityAware` → 获取 `UIAbilityContext` → 调用 `requestPermissionsFromUser()` → 处理用户拒绝。仅调用 `verifyAccessToken()` 不够(只检查不申请)。常见 `user_grant` 权限:`CAMERA`、`MICROPHONE`、`READ_PASTEBOARD`(API 12+)、`ACCESS_BLUETOOTH`、`APPROXIMATELY_LOCATION`、`LOCATION`、`READ_IMAGEVIDEO`、`WRITE_IMAGEVIDEO`、`READ_AUDIO`、`WRITE_AUDIO`。
|
|
206
|
+
|
|
207
|
+
**位置权限特别规则**:涉及 `geoLocationManager`、定位、位置监听、Location Kit 时,`ohos.permission.APPROXIMATELY_LOCATION` 是基础可用权限,`ohos.permission.LOCATION` 是精确定位增强权限。用户只授权模糊位置时也应允许单次定位和位置监听继续执行;权限状态查询、`authResults` 处理、EventChannel 启动前校验均按 `APPROXIMATELY_LOCATION || LOCATION` 任一授权判断,不能只看 `LOCATION` 或固定数组下标。
|
|
208
|
+
|
|
209
|
+
**FFI `.so` 命名**(FFI 类型):OHOS 安装器只识别 `.so` 后缀,会丢弃 `libxxx.so.2` 等带版本号文件;打包前必须重命名为 `libxxx.so`,详见 [references/ffi.md](references/ffi.md) §H。
|
|
210
|
+
|
|
211
|
+
### 4.3 Kit API 查证(MCP,按优先级)
|
|
212
|
+
|
|
213
|
+
| 优先级 | 工具 | 适用 |
|
|
214
|
+
|--------|------|------|
|
|
215
|
+
| 1 | MCP Gateway `script_deveco_docs`(action=search / read) | 检索+精读 HarmonyOS 官方 API 参考:import 路径(`@kit.*`/`@ohos.*`)、方法签名、枚举成员、权限、API Level |
|
|
216
|
+
| 2 | MCP Gateway `kb_search` / `kb-server_search_knowledge` | 补充鸿蒙平台经验知识与已知陷阱 |
|
|
217
|
+
| 3 | MCP Gateway `script_flutter_extract_interfaces` | 提取插件 Dart 公开接口规格,核对公开 API 兼容性(Phase 4.1) |
|
|
218
|
+
|
|
219
|
+
查证结论以表格记录(功能点 / import 路径 / 关键签名 / 权限 / since / 结论),作为编码依据;禁止凭记忆臆造 Kit API。
|
|
220
|
+
|
|
221
|
+
### 4.4 实现与落盘
|
|
222
|
+
|
|
223
|
+
按已加载类型文件的「第二部分」执行代码结构、import、核心模式与类型映射;组合型插件以基础类型文件为脚手架,组合辅助类型文件完成实现。
|
|
224
|
+
|
|
225
|
+
---
|
|
226
|
+
|
|
227
|
+
## Phase 5:编译验证与错误修复(第三部分)
|
|
228
|
+
|
|
229
|
+
> **目标:编译通过是交付的硬性前置条件。**
|
|
230
|
+
|
|
231
|
+
### 5.1 验证命令
|
|
232
|
+
|
|
233
|
+
| 类型 | 命令 | 通过标准 |
|
|
234
|
+
|------|------|---------|
|
|
235
|
+
| 含原生实现的插件 | `flutter build hap --debug`(ohos 实现包目录下;Windows 环境用 powershell/cmd 执行) | 构建成功无 ERROR |
|
|
236
|
+
| 纯 Dart 包 | `flutter pub get` | 成功且无 Dart 分析错误(无需 `flutter build hap`) |
|
|
237
|
+
| 依赖调整后 | `ohpm install` 后重新编译 | 同上 |
|
|
238
|
+
|
|
239
|
+
### 5.2 错误修复
|
|
240
|
+
|
|
241
|
+
优先查已加载类型文件的「第三部分:常见编译错误与修复」(各类型特有错误的修复方案速查);未覆盖的错误按以下顺序排查:
|
|
242
|
+
|
|
243
|
+
1. 对照 Phase 2.5 已识别场景,查 [references/ohos-api-pitfalls.md](references/ohos-api-pitfalls.md) 对应章节
|
|
244
|
+
2. 用 `script_deveco_docs` 查证 API 正确用法(import 路径、签名、`@since` 版本)
|
|
245
|
+
3. 检查工程配置项(Phase 3.2 通用要点:modelVersion 一致性、useNormalizedOHMUrl、externalNativeOptions)
|
|
246
|
+
|
|
247
|
+
### 5.3 修复循环纪律
|
|
248
|
+
|
|
249
|
+
```
|
|
250
|
+
LOOP(上限 5 轮):
|
|
251
|
+
1. 编译验证(5.1)
|
|
252
|
+
2. 收集全部 ERROR(一次修复全部已知错误,避免逐个重跑)
|
|
253
|
+
3. 按速查表/陷阱文档/API 查证修复
|
|
254
|
+
4. 重新验证
|
|
255
|
+
5. 构建通过 → 进入 Phase 6
|
|
256
|
+
超过 5 轮未通过:停止并向用户报告当前错误清单与已尝试方案
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
---
|
|
260
|
+
|
|
261
|
+
## Phase 6:交付自检
|
|
262
|
+
|
|
263
|
+
### 6.1 交付前自查清单
|
|
264
|
+
|
|
265
|
+
**公开 API 兼容**
|
|
266
|
+
- [ ] Dart 层公开 API(类名/方法签名/行为)与上游一致,无因适配引入的破坏性变更
|
|
267
|
+
- [ ] 平台检测统一 `Platform.isOhos`,无排除法、无字符串比较
|
|
268
|
+
|
|
269
|
+
**工程配置**
|
|
270
|
+
- [ ] `pubspec.yaml` 已声明 ohos 平台;`module.json5` 权限齐全(含 Phase 4.3 查证结论)
|
|
271
|
+
- [ ] `modelVersion` 三处一致;Bytecode HAR / FFI `externalNativeOptions` 按需配置
|
|
272
|
+
- [ ] 未手动创建脚手架本应生成的工程文件
|
|
273
|
+
|
|
274
|
+
**编码规范**
|
|
275
|
+
- [ ] Kit 模块全部文件顶部静态导入,无动态 `await import`
|
|
276
|
+
- [ ] `user_grant` 权限实现完整运行时申请流程(含用户拒绝处理)
|
|
277
|
+
- [ ] 位置权限按 `APPROXIMATELY_LOCATION || LOCATION` 任一授权判断
|
|
278
|
+
- [ ] 已按 Phase 2.5 信号表规避对应 API 陷阱
|
|
279
|
+
|
|
280
|
+
**编译验证**
|
|
281
|
+
- [ ] Phase 5.1 验证命令通过(`flutter build hap --debug` / `flutter pub get`)
|
|
282
|
+
- [ ] 所有系统 API 经文档查证,无臆造 API、无 deprecated 接口
|
|
283
|
+
|
|
284
|
+
### 6.2 输出交付物
|
|
285
|
+
|
|
286
|
+
- ohos 平台适配代码(`ohos/` 目录、`pubspec.yaml` 变更等)
|
|
287
|
+
- API 查证结论表(Phase 4.3)
|
|
288
|
+
- 验证结果:验证命令、最终状态、修复的错误清单
|
|
289
|
+
- 未实现或降级处理的功能点说明(如有,含 `not_supported` 判定原因)
|
|
290
|
+
|
|
291
|
+
---
|
|
292
|
+
|
|
293
|
+
## 参考资料
|
|
294
|
+
|
|
295
|
+
**类型指导(Phase 2.1 分发)**
|
|
296
|
+
- [MethodChannel 插件鸿蒙适配](references/method-channel.md) — 主通道插件完整三部分指导
|
|
297
|
+
- [EventChannel 插件鸿蒙适配](references/event-channel.md) — 流式数据插件(监听器生命周期、背压)
|
|
298
|
+
- [PlatformView 插件鸿蒙适配](references/platform-view.md) — 原生视图嵌入(ArkUI 承载)
|
|
299
|
+
- [Texture 插件鸿蒙适配](references/texture.md) — 外接纹理(视频/相机预览)
|
|
300
|
+
- [纯 Dart 包鸿蒙适配](references/pure-dart.md) — 平台判断兼容、依赖链检查
|
|
301
|
+
- [FFI 插件鸿蒙适配路由](references/ffi.md) — §0 分诊 / §F caveat / §G 反检验 / §H 全模式通用规则
|
|
302
|
+
|
|
303
|
+
**FFI 配方(Phase 2.4 分发)**
|
|
304
|
+
- [ffi-compile-from-source](references/ffi-compile-from-source.md) — C/C++ 源码编译接入
|
|
305
|
+
- [ffi-rust-cross-compile](references/ffi-rust-cross-compile.md) — Rust 交叉编译(含 TLS/HTTP3 风险缓解)
|
|
306
|
+
- [ffi-prebuilt-bundle](references/ffi-prebuilt-bundle.md) — 预编译 .so 打包
|
|
307
|
+
- [ffi-fetch-at-build](references/ffi-fetch-at-build.md) — 构建期下载
|
|
308
|
+
- [ffi-binding-translate](references/ffi-binding-translate.md) — @Native 绑定翻译
|
|
309
|
+
- [ffi-rhttp-guide](references/ffi-rhttp-guide.md) — rhttp 实战案例(flutter_rust_bridge HTTP 客户端)
|
|
310
|
+
|
|
311
|
+
**仓库形态(Phase 2.3 补读)**
|
|
312
|
+
- [联合插件适配](references/federated.md) — platform_interface / 多平台实现包
|
|
313
|
+
- [Monorepo 适配](references/monorepo.md) — workspace / melos 多包仓库
|
|
314
|
+
|
|
315
|
+
**陷阱参考(Phase 2.5 按需)**
|
|
316
|
+
- [OHOS API 陷阱](references/ohos-api-pitfalls.md) — 音频/UI 提示/异步/参数安全/传感器/Window/Share Kit/MediaKit/图片处理等 15 章陷阱与修复
|