@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,295 @@
|
|
|
1
|
+
# 联合插件鸿蒙适配
|
|
2
|
+
|
|
3
|
+
## 适用条件
|
|
4
|
+
|
|
5
|
+
- 插件采用 Federated Plugin 架构
|
|
6
|
+
- 有独立的 `xxx_platform_interface` 包
|
|
7
|
+
- 各平台有独立实现包(`xxx_android`、`xxx_ios`)
|
|
8
|
+
- 需要创建新的 `xxx_ohos` 包
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## 第一部分:工程搭建
|
|
13
|
+
|
|
14
|
+
### 工程创建
|
|
15
|
+
|
|
16
|
+
在插件仓库根目录(与 `xxx_android` 同级)创建 ohos 实现包:
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
flutter create -t plugin --platforms ohos {plugin_name}_ohos
|
|
20
|
+
cd {plugin_name}_ohos
|
|
21
|
+
rm -rf .dart_tool .idea
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
`flutter create` 会自动生成完整的 ohos HAR 模块脚手架(`ohos/hvigorfile.ts`、`ohos/oh-package.json5`、`ohos/build-profile.json5`、`ohos/src/main/module.json5`、`ohos/index.ets`、插件模板代码等)。
|
|
25
|
+
|
|
26
|
+
### flutter create 后的配置保护(重要)
|
|
27
|
+
|
|
28
|
+
> 当前 Flutter OHOS 使用 `flutter-hvigor-plugin` 自动注入依赖。**`flutter create` 生成的构建配置文件已包含正确内容,严禁修改。**
|
|
29
|
+
|
|
30
|
+
| 文件 | 禁止操作 |
|
|
31
|
+
|------|---------|
|
|
32
|
+
| `ohos/hvigorfile.ts` | 不要添加 `flutter-ohos`、`PluginConfig`、`FlutterOhosHar` 导入 |
|
|
33
|
+
| `ohos/build-profile.json5` | 不要改为 HAP 格式(`app`/`products`/`modules`) |
|
|
34
|
+
| `ohos/oh-package.json5` | 不要手动添加 `@ohos/flutter_ohos` 依赖或引用 `flutter.har` |
|
|
35
|
+
|
|
36
|
+
**已知致命错误**——以下操作会导致 `Cannot find module 'flutter-ohos'` 编译失败:
|
|
37
|
+
- `hvigorfile.ts` 中写 `import { PluginConfig, FlutterOhosHar } from 'flutter-ohos'`
|
|
38
|
+
- `oh-package.json5` 中写 `"@ohos/flutter_ohos": "file:./har/flutter.har"` 或 `"file:./libs/flutter.har"`
|
|
39
|
+
- 手动创建 `har/` 或 `libs/` 目录放置 `flutter.har`
|
|
40
|
+
|
|
41
|
+
> 构建模式详情参考 `flutter-docs-lookup` Skill → `04_development/使用hvigor插件方式编译flutter项目.md`
|
|
42
|
+
|
|
43
|
+
### 目录结构
|
|
44
|
+
|
|
45
|
+
```
|
|
46
|
+
{repo_root}/
|
|
47
|
+
├── {plugin_name}/ # 主包(app-facing package)
|
|
48
|
+
│ └── pubspec.yaml # 需修改:添加 ohos default_package
|
|
49
|
+
├── {plugin_name}_platform_interface/ # 平台接口包
|
|
50
|
+
├── {plugin_name}_android/ # Android 实现
|
|
51
|
+
├── {plugin_name}_ios/ # iOS 实现
|
|
52
|
+
└── {plugin_name}_ohos/ # 新建的 OHOS 实现
|
|
53
|
+
├── lib/
|
|
54
|
+
│ └── {plugin_name}_ohos.dart # Dart 层 platform 实现
|
|
55
|
+
├── ohos/ # flutter create 自动生成,配置文件不要修改
|
|
56
|
+
│ ├── hvigorfile.ts
|
|
57
|
+
│ ├── oh-package.json5
|
|
58
|
+
│ ├── index.ets
|
|
59
|
+
│ └── src/main/ets/components/plugin/
|
|
60
|
+
│ └── XxxOhosPlugin.ets # ETS 原生实现
|
|
61
|
+
└── pubspec.yaml # 需配置 implements + platforms.ohos
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### Dart 层配置(ohos 实现包)
|
|
65
|
+
|
|
66
|
+
**{plugin_name}_ohos/pubspec.yaml**:
|
|
67
|
+
```yaml
|
|
68
|
+
name: {plugin_name}_ohos
|
|
69
|
+
description: OHOS implementation of {plugin_name}
|
|
70
|
+
version: 0.0.1
|
|
71
|
+
|
|
72
|
+
environment:
|
|
73
|
+
sdk: ">=3.0.0 <4.0.0"
|
|
74
|
+
flutter: ">=3.3.0"
|
|
75
|
+
|
|
76
|
+
flutter:
|
|
77
|
+
plugin:
|
|
78
|
+
implements: {plugin_name}
|
|
79
|
+
platforms:
|
|
80
|
+
ohos:
|
|
81
|
+
package: com.example.{plugin_name}_ohos
|
|
82
|
+
pluginClass: XxxOhosPlugin
|
|
83
|
+
|
|
84
|
+
dependencies:
|
|
85
|
+
flutter:
|
|
86
|
+
sdk: flutter
|
|
87
|
+
{plugin_name}_platform_interface:
|
|
88
|
+
path: ../{plugin_name}_platform_interface
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### 主插件集成
|
|
92
|
+
|
|
93
|
+
修改主插件 **{plugin_name}/pubspec.yaml**,添加 ohos 平台声明和依赖:
|
|
94
|
+
|
|
95
|
+
```yaml
|
|
96
|
+
flutter:
|
|
97
|
+
plugin:
|
|
98
|
+
platforms:
|
|
99
|
+
android:
|
|
100
|
+
default_package: {plugin_name}_android
|
|
101
|
+
ios:
|
|
102
|
+
default_package: {plugin_name}_ios
|
|
103
|
+
ohos:
|
|
104
|
+
default_package: {plugin_name}_ohos
|
|
105
|
+
|
|
106
|
+
dependencies:
|
|
107
|
+
{plugin_name}_ohos:
|
|
108
|
+
path: ../{plugin_name}_ohos
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### oh-package.json5 — 添加三方依赖(按需)
|
|
112
|
+
|
|
113
|
+
如需额外的 ohpm 三方包(来自 `02-planning.json` 的 `native_dependency_mapping`),在 `ohos/oh-package.json5` 的 `dependencies` 中追加:
|
|
114
|
+
|
|
115
|
+
```json5
|
|
116
|
+
{
|
|
117
|
+
"dependencies": {
|
|
118
|
+
"@ohos/some_package": "^1.0.0"
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
> `@ohos/flutter_ohos` 由 Flutter 构建工具自动注入,**不要手动添加**。
|
|
124
|
+
|
|
125
|
+
### module.json5 — 添加权限声明(按需)
|
|
126
|
+
|
|
127
|
+
如需系统权限,在 `ohos/src/main/module.json5` 的 `module` 下追加 `requestPermissions`:
|
|
128
|
+
|
|
129
|
+
```json5
|
|
130
|
+
{
|
|
131
|
+
"module": {
|
|
132
|
+
"name": "{plugin_name}_ohos",
|
|
133
|
+
"type": "har",
|
|
134
|
+
"deviceTypes": ["default", "tablet"],
|
|
135
|
+
"requestPermissions": [
|
|
136
|
+
{
|
|
137
|
+
"name": "ohos.permission.INTERNET",
|
|
138
|
+
"reason": "$string:internet_reason",
|
|
139
|
+
"usedScene": { "abilities": ["EntryAbility"], "when": "always" }
|
|
140
|
+
}
|
|
141
|
+
]
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
### 配置检查清单
|
|
147
|
+
|
|
148
|
+
- [ ] `{plugin_name}_ohos/pubspec.yaml` 中 `implements: {plugin_name}` 正确
|
|
149
|
+
- [ ] `{plugin_name}_ohos/pubspec.yaml` 中 `platforms.ohos.pluginClass` 与 ETS 类名一致
|
|
150
|
+
- [ ] `{plugin_name}_ohos/pubspec.yaml` 中 `{plugin_name}_platform_interface` 依赖路径正确
|
|
151
|
+
- [ ] 主插件 `pubspec.yaml` 中 `platforms.ohos.default_package: {plugin_name}_ohos` 存在
|
|
152
|
+
- [ ] 主插件 `pubspec.yaml` 中 `dependencies.{plugin_name}_ohos` path 依赖正确
|
|
153
|
+
- [ ] `ohos/hvigorfile.ts` 保持 `flutter create` 生成的原始内容(`harTasks` 简单导出)
|
|
154
|
+
- [ ] `ohos/oh-package.json5` 中**无** `@ohos/flutter_ohos` 依赖(由构建工具自动注入)
|
|
155
|
+
- [ ] `ohos/oh-package.json5` 中已添加实际需要的 ohpm 三方包(如有)
|
|
156
|
+
- [ ] `ohos/src/main/module.json5` 中已添加所需权限(如有)
|
|
157
|
+
|
|
158
|
+
---
|
|
159
|
+
|
|
160
|
+
## 第二部分:编码实现
|
|
161
|
+
|
|
162
|
+
### 查看 platform_interface 接口
|
|
163
|
+
|
|
164
|
+
编码前必须阅读 `{plugin_name}_platform_interface` 包:
|
|
165
|
+
|
|
166
|
+
- `{plugin_name}_platform_interface.dart` — 所有需要实现的**抽象方法签名**
|
|
167
|
+
- `method_channel_{plugin_name}.dart` — 默认 MethodChannel 实现(参考方法名、参数格式)
|
|
168
|
+
|
|
169
|
+
同时必须对照 PRD 的公开 API、功能模块、参数类型、平台差异和使用示例,确认 Android/iOS/Darwin 平台实现包中的公开 class、controller 方法、extension、typedef、enum 和参数类型是否需要在 OHOS 实现包中提供等价能力。`platform_interface` 不是 federated 插件的完整公开能力边界;开发者可直接 import / 调用的平台专属 API 不能因为不在 `platform_interface` 中而遗漏。
|
|
170
|
+
|
|
171
|
+
如果当前仓库根包没有 `android/` 和 `ios/` 目录,不要判定为无原生实现。先根据 app-facing 包 `pubspec.yaml` 的 `default_package`、依赖关系和同级目录名定位 `{plugin_name}_android`、`{plugin_name}_ios` / `{plugin_name}_darwin` 等平台实现包,再读取其 `lib/` 公开导出。若平台实现包不在当前仓库或本地工作区,必须继续根据 `pubspec.lock`、`.dart_tool/package_config.json`、本机 pub cache、依赖的 git/url/path、pub.dev 或仓库 `repository` 信息自行定位源码;定位到源码后再扫描公开 API。最终实现边界以 app-facing 包、`platform_interface` 包、各平台实现包公开 API 的并集为准。
|
|
172
|
+
|
|
173
|
+
注意区分两类 API:
|
|
174
|
+
- `@override` 方法通常来自 `platform_interface`,OHOS 实现包必须实现。
|
|
175
|
+
- 非 `@override` 的平台实现包 public 方法不会出现在 `platform_interface` 中,但仍可能是开发者直接使用的能力。例如 `AndroidWebViewController.setOnShowFileSelector` 是 Android 平台实现包公开 controller method,不是 extension,也不在 `webview_flutter_platform_interface` 中;只扫 platform_interface 会漏掉网页上传文件选择能力。
|
|
176
|
+
|
|
177
|
+
### Dart 层实现
|
|
178
|
+
|
|
179
|
+
```dart
|
|
180
|
+
import 'package:flutter/foundation.dart';
|
|
181
|
+
import 'package:flutter/services.dart';
|
|
182
|
+
import 'package:{plugin_name}_platform_interface/{plugin_name}_platform_interface.dart';
|
|
183
|
+
|
|
184
|
+
class {PluginName}Ohos extends {PluginName}Platform {
|
|
185
|
+
@visibleForTesting
|
|
186
|
+
final methodChannel = const MethodChannel('{channel_name}');
|
|
187
|
+
|
|
188
|
+
static void registerWith() {
|
|
189
|
+
{PluginName}Platform.instance = {PluginName}Ohos();
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
@override
|
|
193
|
+
Future<String?> getPlatformVersion() async {
|
|
194
|
+
final version = await methodChannel.invokeMethod<String>('getPlatformVersion');
|
|
195
|
+
return version;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
// 实现 platform_interface 中所有抽象方法
|
|
199
|
+
// 未实现的方法抛出 UnimplementedError
|
|
200
|
+
}
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
**关键要点**:
|
|
204
|
+
- `registerWith()` 是静态方法,Flutter 框架通过反射调用,**方法名不能改**
|
|
205
|
+
- 必须实现 `{PluginName}Platform` 中所有抽象方法
|
|
206
|
+
- Channel 名称必须与 ETS 端完全一致
|
|
207
|
+
|
|
208
|
+
### ETS 原生层实现
|
|
209
|
+
|
|
210
|
+
ETS 层编码模式与 MethodChannel 插件相同,参考同目录下 **`method-channel.md`** 获取完整指导(Context 获取、AbilityAware、参数提取、异步处理、混合模式、类型映射表等)。
|
|
211
|
+
|
|
212
|
+
基本结构:
|
|
213
|
+
|
|
214
|
+
```ets
|
|
215
|
+
import {
|
|
216
|
+
FlutterPlugin,
|
|
217
|
+
FlutterPluginBinding,
|
|
218
|
+
MethodCall,
|
|
219
|
+
MethodCallHandler,
|
|
220
|
+
MethodChannel,
|
|
221
|
+
MethodResult,
|
|
222
|
+
} from '@ohos/flutter_ohos';
|
|
223
|
+
|
|
224
|
+
export default class XxxOhosPlugin implements FlutterPlugin, MethodCallHandler {
|
|
225
|
+
private channel: MethodChannel | null = null;
|
|
226
|
+
|
|
227
|
+
getUniqueClassName(): string {
|
|
228
|
+
return "XxxOhosPlugin";
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
onAttachedToEngine(binding: FlutterPluginBinding): void {
|
|
232
|
+
this.channel = new MethodChannel(binding.getBinaryMessenger(), "{channel_name}");
|
|
233
|
+
this.channel.setMethodCallHandler(this);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
onDetachedFromEngine(binding: FlutterPluginBinding): void {
|
|
237
|
+
if (this.channel != null) {
|
|
238
|
+
this.channel.setMethodCallHandler(null);
|
|
239
|
+
}
|
|
240
|
+
this.channel = null;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
onMethodCall(call: MethodCall, result: MethodResult): void {
|
|
244
|
+
switch (call.method) {
|
|
245
|
+
case "getPlatformVersion":
|
|
246
|
+
result.success("OpenHarmony");
|
|
247
|
+
break;
|
|
248
|
+
default:
|
|
249
|
+
result.notImplemented();
|
|
250
|
+
break;
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
> ETS API 详细文档参考 `flutter-docs-lookup` Skill → `11_flutter_api_docs/`(MethodChannel、EventChannel、FlutterPlugin 等完整 API)
|
|
257
|
+
|
|
258
|
+
### 编译目标
|
|
259
|
+
|
|
260
|
+
联合插件的编译在 ohos 实现包目录下执行:
|
|
261
|
+
|
|
262
|
+
```bash
|
|
263
|
+
cd {plugin_name}_ohos
|
|
264
|
+
flutter pub get && flutter build hap --debug
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
如果 ohos 实现包没有 example,需先创建:
|
|
268
|
+
```bash
|
|
269
|
+
cd {plugin_name}_ohos
|
|
270
|
+
flutter create --platforms ohos example
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
---
|
|
274
|
+
|
|
275
|
+
## 第三部分:常见编译错误与修复
|
|
276
|
+
|
|
277
|
+
### 构建配置错误
|
|
278
|
+
|
|
279
|
+
| 错误 | 原因 | 修复 |
|
|
280
|
+
|------|------|------|
|
|
281
|
+
| `Cannot find module 'flutter-ohos'` | `hvigorfile.ts` 中错误导入了 `flutter-ohos` 模块 | 恢复为 `flutter create` 生成的标准 `harTasks` 导出 |
|
|
282
|
+
| `ENOENT: ...flutter.har` | `oh-package.json5` 引用了不存在的 `flutter.har` | 移除 `@ohos/flutter_ohos` 依赖(由构建工具自动注入) |
|
|
283
|
+
|
|
284
|
+
### 联合插件特有错误
|
|
285
|
+
|
|
286
|
+
| 错误 | 原因 | 修复 |
|
|
287
|
+
|------|------|------|
|
|
288
|
+
| `Could not resolve package '{plugin_name}_platform_interface'` | `pubspec.yaml` 中 path 路径不对 | 路径应为 `path: ../{plugin_name}_platform_interface`(相对于 ohos 包目录) |
|
|
289
|
+
| `The plugin doesn't have a main class defined in ... ohos` | `pluginClass` 与 ETS 类名不匹配 | 两者必须大小写完全一致 |
|
|
290
|
+
| `'registerWith' is not defined` | Dart 层缺少 `registerWith` 静态方法 | 添加 `static void registerWith()` |
|
|
291
|
+
| `Missing concrete implementation of 'xxxMethod'` | platform_interface 抽象方法未全部实现 | 逐一实现,暂不支持的抛 `UnimplementedError` |
|
|
292
|
+
| `Duplicate plugin registration` | `implements` 名称不匹配 | 值应为 `{plugin_name}`(不含 `_ohos`) |
|
|
293
|
+
| `flutter pub get` 失败(主插件) | 主插件中 ohos 包的 path 路径不对 | 路径应为 `path: ../{plugin_name}_ohos` |
|
|
294
|
+
|
|
295
|
+
> 其他 ETS 编译错误(类型错误、import 错误、API 不存在等)参考同目录下 **`method-channel.md`** 第三部分。
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
# FFI Binding Translate: @Native → DynamicLibrary 旁路注入
|
|
2
|
+
|
|
3
|
+
## 根因
|
|
4
|
+
|
|
5
|
+
Flutter OHOS 工具链未接入 Dart native asset 系统。`@Native` 注解编译期合法,但运行时符号解析失败:
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
Couldn't resolve native function 'probe_add'
|
|
9
|
+
No asset with id 'package:xxx/xxx.dart' found.
|
|
10
|
+
No available native assets.
|
|
11
|
+
Attempted to fallback to process lookup.
|
|
12
|
+
do_dlsym failed: Symbol not found: probe_add
|
|
13
|
+
so=/system/bin/appspawn ← fallback 查错了进程
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
- `@Native` 依赖 native asset 机制(Dart 3.x,通过 hook/build.dart 注入符号→.so 映射)
|
|
17
|
+
- Flutter Android/iOS 工具链完整接入 → 正常
|
|
18
|
+
- Flutter OHOS 未实现 → fallback 到 process lookup → 查到 appspawn 而非已加载的 .so → 失败
|
|
19
|
+
- 对照组 `DynamicLibrary.lookup()` 调同一 .so 同一符号 → 成功
|
|
20
|
+
|
|
21
|
+
## 翻译策略:旁路注入,不替换
|
|
22
|
+
|
|
23
|
+
**保留原 `@Native` 不动**(避免与 Android/iOS 分歧),新增 OHOS 专属绑定文件,调用点用 `Platform.isOhos` 分流。
|
|
24
|
+
|
|
25
|
+
### 文件结构
|
|
26
|
+
|
|
27
|
+
```
|
|
28
|
+
lib/
|
|
29
|
+
├── src/ffi/
|
|
30
|
+
│ ├── original_bindings.dart # 原文件,含 @Native(不动)
|
|
31
|
+
│ └── xxx_ohos_ffi.dart # 新增,OHOS 旁路 FFI
|
|
32
|
+
└── xxx.dart # 入口,加 Platform.isOhos 分流
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### 模板
|
|
36
|
+
|
|
37
|
+
#### 1. OHOS 旁路文件(`lib/src/ffi/xxx_ohos_ffi.dart`)
|
|
38
|
+
|
|
39
|
+
```dart
|
|
40
|
+
import 'dart:ffi' as ffi;
|
|
41
|
+
import 'dart:io' show Platform;
|
|
42
|
+
|
|
43
|
+
class OhosBindings {
|
|
44
|
+
static final instance = OhosBindings._();
|
|
45
|
+
|
|
46
|
+
OhosBindings._() : _lib = ffi.DynamicLibrary.open('libxxx.so');
|
|
47
|
+
|
|
48
|
+
final ffi.DynamicLibrary _lib;
|
|
49
|
+
|
|
50
|
+
late final int Function(int, int) myAdd = _lib
|
|
51
|
+
.lookup<ffi.NativeFunction<ffi.Int32 Function(ffi.Int32, ffi.Int32)>>('my_add')
|
|
52
|
+
.asFunction<int Function(int, int)>();
|
|
53
|
+
|
|
54
|
+
// ... 其他方法同理
|
|
55
|
+
}
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
#### 2. 原文件调用点分流(`lib/xxx.dart`)
|
|
59
|
+
|
|
60
|
+
```dart
|
|
61
|
+
// 原文件(不改声明,只在调用层分流)
|
|
62
|
+
@Native<Int32 Function(Int32, Int32)>(symbol: 'my_add', isLeaf: true)
|
|
63
|
+
external int myAddNative(int a, int b);
|
|
64
|
+
|
|
65
|
+
import 'src/ffi/xxx_ohos_ffi.dart';
|
|
66
|
+
import 'dart:io' show Platform;
|
|
67
|
+
|
|
68
|
+
int myAdd(int a, int b) => Platform.isOhos
|
|
69
|
+
? OhosBindings.instance.myAdd(a, b)
|
|
70
|
+
: myAddNative(a, b);
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### 翻译规则
|
|
74
|
+
|
|
75
|
+
`@Native<T>(symbol: 'x') external R fn(Args)` 机械映射为:
|
|
76
|
+
|
|
77
|
+
```dart
|
|
78
|
+
late final R Function(Args) fn = _lib
|
|
79
|
+
.lookup<ffi.NativeFunction<T>>('x')
|
|
80
|
+
.asFunction<R Function(Args)>();
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
类型映射:
|
|
84
|
+
|
|
85
|
+
| @Native 原始类型 | Dart 类型 |
|
|
86
|
+
|------------------|----------|
|
|
87
|
+
| `ffi.Int32` / `ffi.Uint32` | `int` |
|
|
88
|
+
| `ffi.Int8` / `ffi.Uint8` / `ffi.Int16` / `ffi.Uint16` / `ffi.Size` / `ffi.IntPtr` | `int` |
|
|
89
|
+
| `ffi.Float` / `ffi.Double` | `double` |
|
|
90
|
+
| `ffi.Pointer<T>` | `ffi.Pointer<T>` |
|
|
91
|
+
| `ffi.Bool` | `bool` |
|
|
92
|
+
| `ffi.Void` | `void` |
|
|
93
|
+
|
|
94
|
+
`isLeaf: true` 无需特殊处理,`asFunction` 默认支持。
|
|
95
|
+
|
|
96
|
+
### 批量处理(大量 @Native 声明)
|
|
97
|
+
|
|
98
|
+
若原文件有大量 `@Native` 声明(如 sodium 有数百个),编写生成脚本:
|
|
99
|
+
|
|
100
|
+
```dart
|
|
101
|
+
// tool/generate_ohos_ffi.dart
|
|
102
|
+
// 参考:repos/sodium/tool/generate_ohos_ffi.dart
|
|
103
|
+
//
|
|
104
|
+
// 核心逻辑:
|
|
105
|
+
// 1. 读取原 FFI 绑定文件
|
|
106
|
+
// 2. 正则提取 @Native 声明(nativeType、returnType、funcName、params)
|
|
107
|
+
// 3. 为每个声明生成 lookupFunction 代码
|
|
108
|
+
// 4. 输出到 lib/src/ffi/xxx_ohos_ffi.dart
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### 参考:sodium 完整实现
|
|
112
|
+
|
|
113
|
+
- 原绑定:`repos/sodium/lib/src/ffi/bindings/libsodium.ffi.dart`(含大量 `@Native`)
|
|
114
|
+
- 生成脚本:`repos/sodium/tool/generate_ohos_ffi.dart`
|
|
115
|
+
- OHOS 旁路:`repos/sodium/lib/src/ffi/bindings/libsodium_ohos.ffi.dart`
|
|
116
|
+
- 入口分流:`repos/sodium/lib/src/ffi/bindings/libsodium.ffi.wrapper.dart` 中 `Platform.isOhos`
|
|
117
|
+
|
|
118
|
+
## 硬约束
|
|
119
|
+
|
|
120
|
+
1. **不删除原有 `@Native`**:保留原文件不动,避免与 Android/iOS 分歧
|
|
121
|
+
2. **不替换原有 `@Native`**:不要把原文件的 `@Native` 改写为 `lookupFunction`
|
|
122
|
+
3. **旁路注入**:新增 OHOS 专用文件 + `Platform.isOhos` 分流
|
|
123
|
+
4. **命名约定**:OHOS 旁路文件统一命名为 `xxx_ohos_ffi.dart` 或 `xxx_ohos.ffi.dart`
|
|
124
|
+
|
|
125
|
+
## 触发条件
|
|
126
|
+
|
|
127
|
+
此文件仅在 `primary-03-coding-library.md` 的 type-ffi 分支末尾被加载:
|
|
128
|
+
- 执行 `grep -r '@Native<' lib/`
|
|
129
|
+
- 有命中 → 加载本文件
|
|
130
|
+
- 无命中 → 跳过
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
# FFI Strategy: compile_from_source
|
|
2
|
+
|
|
3
|
+
## 适用条件
|
|
4
|
+
|
|
5
|
+
仓库内包含 C/C++ 源码(`src/` 目录下有 `.c` / `.cpp` / `.h` 文件),且有 CMakeLists.txt 或类似构建配置,无 Rust Cargo.toml。
|
|
6
|
+
|
|
7
|
+
## 工程搭建
|
|
8
|
+
|
|
9
|
+
### 1. 创建 ohos 工程
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
flutter create -t plugin_ffi --platforms ohos .
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
### 2. CMakeLists.txt 配置
|
|
16
|
+
|
|
17
|
+
鸿蒙 CMakeLists.txt 与 Android 有显著差异:
|
|
18
|
+
|
|
19
|
+
```cmake
|
|
20
|
+
cmake_minimum_required(VERSION 3.13)
|
|
21
|
+
project(xxx_library)
|
|
22
|
+
|
|
23
|
+
set(NATIVERENDER_ROOT_PATH ${CMAKE_CURRENT_SOURCE_DIR})
|
|
24
|
+
|
|
25
|
+
add_library(xxx SHARED
|
|
26
|
+
${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/xxx.c
|
|
27
|
+
${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/yyy.c
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
target_include_directories(xxx PRIVATE
|
|
31
|
+
${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
target_link_libraries(xxx PUBLIC libace_napi.z.so)
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### 3. Android NDK → OHOS 系统库映射
|
|
38
|
+
|
|
39
|
+
| Android | OHOS | 用途 |
|
|
40
|
+
|---------|------|------|
|
|
41
|
+
| `log` (`__android_log_print`) | `libhilog_ndk.z.so` (`OH_LOG_Print`) | 日志 |
|
|
42
|
+
| `android` (`libandroid.so`) | — | OHOS 无对等,需用 IPC Kit / Window Kit 等 |
|
|
43
|
+
| `EGL` / `GLESv2` | `EGL` / `GLESv3.0`(鸿蒙保留) | 图形 |
|
|
44
|
+
| `mediandk` | — | 媒体,需查 `@ohos.multimedia` Kit |
|
|
45
|
+
| `OpenSLES` | `OH_AudioKit` | 音频 |
|
|
46
|
+
| `jnigraphics` | `libnative_drawing.so` | 位图 |
|
|
47
|
+
| JNI (`<jni.h>`) | NAPI (`<napi/native_api.h>`) | 原生接口 |
|
|
48
|
+
| CMake 工具链 | `android.toolchain.cmake` | 鸿蒙 SDK 内置 |
|
|
49
|
+
| ABI | `armeabi-v7a`, `arm64-v8a` | `arm64-v8a`(鸿蒙主要支持 arm64) |
|
|
50
|
+
|
|
51
|
+
### 4. oh-package.json5
|
|
52
|
+
|
|
53
|
+
FFI 插件通常不需要额外 ohpm 依赖。
|
|
54
|
+
|
|
55
|
+
> **`@ohos/flutter_ohos` 依赖由 Flutter 构建工具自动注入,无需手动添加。** 如果 `flutter create` 生成了 `"@ohos/flutter_ohos": "file:./libs/flutter.har"`,**必须将其移除**(将 dependencies 设为 `{}`),否则会导致 `Failed to resolve OhmUrl` 编译错误。
|
|
56
|
+
|
|
57
|
+
## 编码实现
|
|
58
|
+
|
|
59
|
+
### .so 加载路径
|
|
60
|
+
|
|
61
|
+
```dart
|
|
62
|
+
import 'dart:ffi';
|
|
63
|
+
import 'dart:io' show Platform;
|
|
64
|
+
|
|
65
|
+
DynamicLibrary _openLibrary() {
|
|
66
|
+
if (Platform.isAndroid || Platform.isLinux || Platform.isOhos) {
|
|
67
|
+
return DynamicLibrary.open('libxxx.so');
|
|
68
|
+
}
|
|
69
|
+
if (Platform.isIOS || Platform.isMacOS) {
|
|
70
|
+
return DynamicLibrary.process();
|
|
71
|
+
}
|
|
72
|
+
if (Platform.isWindows) {
|
|
73
|
+
return DynamicLibrary.open('xxx.dll');
|
|
74
|
+
}
|
|
75
|
+
throw UnsupportedError('Unsupported platform: ${Platform.operatingSystem}');
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### 日志替换
|
|
80
|
+
|
|
81
|
+
```c
|
|
82
|
+
#if defined(__ANDROID__)
|
|
83
|
+
#include <android/log.h>
|
|
84
|
+
#define LOG_TAG "xxx"
|
|
85
|
+
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
|
|
86
|
+
#elif defined(__OHOS__)
|
|
87
|
+
#include <hilog/log.h>
|
|
88
|
+
#define LOG_TAG "xxx"
|
|
89
|
+
#define LOGI(...) OH_LOG_Print(LOG_INFO, LOG_APP, 0, LOG_TAG, __VA_ARGS__)
|
|
90
|
+
#else
|
|
91
|
+
#define LOGI(...) printf(__VA_ARGS__)
|
|
92
|
+
#endif
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### 条件编译宏
|
|
96
|
+
|
|
97
|
+
鸿蒙 NDK 预定义宏:
|
|
98
|
+
- `__OHOS__` — 鸿蒙平台标识
|
|
99
|
+
- `__aarch64__` — ARM64 架构
|
|
100
|
+
|
|
101
|
+
```c
|
|
102
|
+
#if defined(__OHOS__)
|
|
103
|
+
// 鸿蒙特定代码
|
|
104
|
+
#elif defined(__ANDROID__)
|
|
105
|
+
// Android 特定代码
|
|
106
|
+
#endif
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
### 不兼容系统调用替代
|
|
110
|
+
|
|
111
|
+
| 不可用的 API | 鸿蒙替代 | 说明 |
|
|
112
|
+
|-------------|---------|------|
|
|
113
|
+
| `pthread_setname_np` | 可用,签名相同 | |
|
|
114
|
+
| `dlopen` / `dlsym` | 可用 | 动态库加载 |
|
|
115
|
+
| `mmap` / `munmap` | 可用 | 内存映射 |
|
|
116
|
+
| Android Binder | 不可用 | 鸿蒙使用 IPC Kit |
|
|
117
|
+
| `/proc/self/maps` | 路径不同 | 进程信息获取方式不同 |
|
|
118
|
+
|
|
119
|
+
### pubspec.yaml 平台声明
|
|
120
|
+
|
|
121
|
+
```yaml
|
|
122
|
+
flutter:
|
|
123
|
+
plugin:
|
|
124
|
+
platforms:
|
|
125
|
+
ohos:
|
|
126
|
+
ffiPlugin: true
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
## 常见编译错误与修复
|
|
130
|
+
|
|
131
|
+
### 1. `undefined reference to '__android_log_print'`
|
|
132
|
+
|
|
133
|
+
C/C++ 代码中使用了 Android 专用日志函数。
|
|
134
|
+
修复:添加 `__OHOS__` 条件编译,链接 `libhilog_ndk.z.so`。
|
|
135
|
+
|
|
136
|
+
### 2. `fatal error: 'android/xxx.h' file not found`
|
|
137
|
+
|
|
138
|
+
包含了 Android NDK 专用头文件。
|
|
139
|
+
修复:用 `#ifdef __ANDROID__ ... #endif` 包裹,鸿蒙对应头文件通常在不同路径。
|
|
140
|
+
|
|
141
|
+
### 3. `CMake Error: Cannot find source file`
|
|
142
|
+
|
|
143
|
+
CMakeLists.txt 中源文件路径不对。
|
|
144
|
+
修复:路径相对于 `ohos/src/main/cpp/`,插件源码通常用 `../../../../src/` 访问。
|
|
145
|
+
|
|
146
|
+
### 4. `undefined symbol: xxx` (链接错误)
|
|
147
|
+
|
|
148
|
+
缺少系统库链接。
|
|
149
|
+
修复:在 CMakeLists.txt 中添加:
|
|
150
|
+
```cmake
|
|
151
|
+
target_link_libraries(xxx PUBLIC
|
|
152
|
+
libace_napi.z.so
|
|
153
|
+
libhilog_ndk.z.so
|
|
154
|
+
)
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
### 5. `error: use of undeclared identifier '__OHOS__'`
|
|
158
|
+
|
|
159
|
+
编译器没有预定义 `__OHOS__` 宏。
|
|
160
|
+
修复:确认使用鸿蒙 NDK,或手动添加 `add_definitions(-D__OHOS__)`。
|
|
161
|
+
|
|
162
|
+
### 6. Dart 层 `DynamicLibrary.open` 失败
|
|
163
|
+
|
|
164
|
+
.so 文件名不对或未正确打包。
|
|
165
|
+
修复:确认 CMakeLists.txt 中 `add_library` 库名与 Dart 层加载名一致。`add_library(xxx SHARED ...)` 生成 `libxxx.so`。
|
|
166
|
+
|
|
167
|
+
### 7. `Platform.isOhos` 不存在
|
|
168
|
+
|
|
169
|
+
需要使用 Flutter OHOS 版本。Flutter OHOS 分支已原生支持 `Platform.isOhos`。
|