@ohos-cpf/3rdloop 0.0.11 → 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.
Files changed (46) hide show
  1. package/lib/cli.js +2 -2
  2. package/package.json +1 -1
  3. package/vendor/Server/Routes/controllers/LoopEngineController.js +36 -3
  4. package/vendor/Server/Routes/controllers/OrchestratorController.js +193 -9
  5. package/vendor/Server/Skills/flutter-build-test/SKILL.md +252 -0
  6. package/vendor/Server/Skills/flutter-build-test/assets/BUILDENV_TEMPLATE.md +42 -0
  7. package/vendor/Server/Skills/flutter-build-test/assets/BUILD_REPORT_TEMPLATE.md +64 -0
  8. package/vendor/Server/Skills/flutter-build-test/assets/README_SECTION_TEMPLATE.md +78 -0
  9. package/vendor/Server/Skills/flutter-build-test/references/BUILD_TROUBLESHOOTING.md +128 -0
  10. package/vendor/Server/Skills/flutter-build-test/references/DOC_UPDATE_GUIDE.md +119 -0
  11. package/vendor/Server/Skills/flutter-build-test/references/FLVM_GUIDE.md +89 -0
  12. package/vendor/Server/Skills/flutter-build-test/scripts/build-matrix.cjs +374 -0
  13. package/vendor/Server/Skills/flutter-build-test/scripts/locate-example.cjs +189 -0
  14. package/vendor/Server/Skills/flutter-build-test/scripts/update-buildenv.cjs +171 -0
  15. package/vendor/Server/Skills/flutter-code-use/SKILL.md +316 -0
  16. package/vendor/Server/Skills/flutter-code-use/references/event-channel.md +440 -0
  17. package/vendor/Server/Skills/flutter-code-use/references/federated.md +295 -0
  18. package/vendor/Server/Skills/flutter-code-use/references/ffi-binding-translate.md +130 -0
  19. package/vendor/Server/Skills/flutter-code-use/references/ffi-compile-from-source.md +169 -0
  20. package/vendor/Server/Skills/flutter-code-use/references/ffi-fetch-at-build.md +161 -0
  21. package/vendor/Server/Skills/flutter-code-use/references/ffi-prebuilt-bundle.md +175 -0
  22. package/vendor/Server/Skills/flutter-code-use/references/ffi-rhttp-guide.md +235 -0
  23. package/vendor/Server/Skills/flutter-code-use/references/ffi-rust-cross-compile.md +514 -0
  24. package/vendor/Server/Skills/flutter-code-use/references/ffi.md +220 -0
  25. package/vendor/Server/Skills/flutter-code-use/references/method-channel.md +643 -0
  26. package/vendor/Server/Skills/flutter-code-use/references/monorepo.md +188 -0
  27. package/vendor/Server/Skills/flutter-code-use/references/ohos-api-pitfalls.md +717 -0
  28. package/vendor/Server/Skills/flutter-code-use/references/platform-view.md +448 -0
  29. package/vendor/Server/Skills/flutter-code-use/references/pure-dart.md +180 -0
  30. package/vendor/Server/Skills/flutter-code-use/references/texture.md +459 -0
  31. package/vendor/Server/Skills/flutter-demo-code-generator/SKILL.md +270 -0
  32. package/vendor/Server/Skills/flutter-demo-code-generator/assets/PAGE_TEMPLATES.md +544 -0
  33. package/vendor/Server/Skills/flutter-demo-code-generator/references/CODE_STANDARDS.md +328 -0
  34. package/vendor/Server/Skills/flutter-demo-code-generator/references/DEMO_DOC_PARSING.md +126 -0
  35. package/vendor/Server/Skills/flutter-demo-code-generator/references/EXAMPLES.md +629 -0
  36. package/vendor/Server/Skills/flutter-demo-code-generator/scripts/validate-flutter-demo.cjs +268 -0
  37. package/vendor/Server/Skills/flutter-demo-doc-generator/SKILL.md +227 -0
  38. package/vendor/Server/Skills/flutter-demo-doc-generator/assets/DEMO_DOC_TEMPLATE.md +78 -0
  39. package/vendor/Server/Skills/flutter-demo-doc-generator/references/COVERAGE_REPORT_PARSING.md +174 -0
  40. package/vendor/Server/Skills/flutter-demo-doc-generator/references/EXAMPLES.md +162 -0
  41. package/vendor/Server/Skills/flutter-demo-doc-generator/references/MCP_TOOL_GUIDE.md +123 -0
  42. package/vendor/Server/Skills/flutter-demo-doc-generator/references/OUTPUT_FORMAT.md +190 -0
  43. package/vendor/Server/Skills/flutter-demo-doc-generator/references/QUALITY_CHECKLIST.md +83 -0
  44. package/vendor/Server/Skills/flutter-demo-doc-generator/scripts/validate-skill.cjs +259 -0
  45. package/vendor/Server/Skills/flutter-library-demo-coverage/SKILL.md +175 -0
  46. package/vendor/VERSION +3 -3
@@ -0,0 +1,448 @@
1
+ # PlatformView 插件鸿蒙适配
2
+
3
+ ## 适用条件
4
+
5
+ - 插件使用 `PlatformView` 在 Flutter 中嵌入原生视图
6
+ - 典型场景:地图、WebView、视频播放器、相机预览、广告视图
7
+
8
+ ---
9
+
10
+ ## 第一部分:工程搭建
11
+
12
+ ### 工程创建
13
+
14
+ ```bash
15
+ flutter create -t plugin --platforms ohos .
16
+ ```
17
+
18
+ ### 目录结构
19
+
20
+ PlatformView 插件通常需要多个 ETS 文件:
21
+ ```
22
+ ohos/src/main/ets/components/plugin/
23
+ ├── XxxPlugin.ets # 插件主入口(注册 Factory + MethodChannel)
24
+ ├── XxxPlatformView.ets # PlatformView 实现
25
+ ├── XxxViewFactory.ets # PlatformView 工厂
26
+ └── XxxComponent.ets # ArkUI 组件(可选,也可放在 PlatformView 文件中)
27
+ ```
28
+
29
+ ### 额外配置
30
+
31
+ PlatformView 可能需要在 `module.json5` 中配置额外能力(视具体功能而定,如 WebView 需要网络权限)。
32
+
33
+ ---
34
+
35
+ ## 第二部分:编码实现
36
+
37
+ ## PlatformView 约束
38
+
39
+ `@ohos/flutter_ohos` 的 `Params` 属于 framework 桥接对象,不是业务参数容器。
40
+
41
+ 禁止:
42
+ - 继承或实例化 `Params`
43
+ - 向 `Params` 挂载 `viewId`、`context`、controller、channel 等业务状态
44
+ - 未核验本地源码就假设 builder 参数包含自定义字段
45
+
46
+ 规则:
47
+ - 业务状态保存在 `XxxPlatformView` 自身或插件自有状态对象中
48
+ - `Builder` / `Component` 访问业务状态时,通过 `params.platformView as XxxPlatformView` 反查实例
49
+ - 文档或示例与当前已安装本地源码冲突时,以本地源码为准
50
+
51
+ ### PlatformView 四件套
52
+
53
+ 鸿蒙平台实现 PlatformView 需要四个组件:
54
+
55
+ #### 1. PlatformView 实现
56
+
57
+ ```ets
58
+ import { PlatformView } from '@ohos/flutter_ohos/src/main/ets/plugin/platform/PlatformView';
59
+ import common from '@ohos.app.ability.common';
60
+
61
+ @Observed
62
+ export class Params {
63
+ viewId: number = 0;
64
+ creationParams: Map<string, Object> | null = null;
65
+ // 根据需要添加其他参数,如回调函数引用
66
+ }
67
+
68
+ export class XxxPlatformView extends PlatformView {
69
+ private params: Params;
70
+
71
+ constructor(context: common.Context, viewId: number, args: Object) {
72
+ super();
73
+ this.params = new Params();
74
+ this.params.viewId = viewId;
75
+ // 解析创建参数
76
+ if (args !== null && args !== undefined) {
77
+ this.params.creationParams = args as Map<string, Object>;
78
+ }
79
+ }
80
+
81
+ getView(): WrappedBuilder<[Params]> {
82
+ return new WrappedBuilder(buildXxxView);
83
+ }
84
+
85
+ dispose(): void {
86
+ // 释放视图相关资源
87
+ }
88
+ }
89
+ ```
90
+
91
+ #### 2. 视图构建函数 + ArkUI 组件
92
+
93
+ ```ets
94
+ @Builder
95
+ function buildXxxView(params: Params) {
96
+ XxxComponent({ params: params })
97
+ }
98
+
99
+ @Component
100
+ struct XxxComponent {
101
+ @ObjectLink params: Params;
102
+
103
+ build() {
104
+ Column() {
105
+ // 构建原生视图内容
106
+ // 例如 WebView:
107
+ // Web({ src: this.params.url, controller: this.params.controller })
108
+ // .width('100%')
109
+ // .height('100%')
110
+ }
111
+ .width('100%')
112
+ .height('100%')
113
+ }
114
+ }
115
+ ```
116
+
117
+ **`@Observed` 和 `@ObjectLink` 用法要点**:
118
+ - `Params` 类必须用 `@Observed` 装饰,使其属性变化可被观察
119
+ - 组件中用 `@ObjectLink` 引用 Params 实例,实现数据变化自动刷新 UI
120
+ - `@Observed` 类中的属性必须有初始值
121
+ - `@ObjectLink` 变量不能在组件内重新赋值(只能修改其属性)
122
+
123
+ #### 3. PlatformViewFactory
124
+
125
+ ```ets
126
+ import { PlatformViewFactory } from '@ohos/flutter_ohos/src/main/ets/plugin/platform/PlatformViewFactory';
127
+ import { PlatformView } from '@ohos/flutter_ohos/src/main/ets/plugin/platform/PlatformView';
128
+ import common from '@ohos.app.ability.common';
129
+
130
+ export class XxxViewFactory extends PlatformViewFactory {
131
+ create(context: common.Context, viewId: number, args: Object): PlatformView {
132
+ return new XxxPlatformView(context, viewId, args);
133
+ }
134
+ }
135
+ ```
136
+
137
+ #### 4. 插件主入口(注册 Factory)
138
+
139
+ ```ets
140
+ import {
141
+ FlutterPlugin,
142
+ FlutterPluginBinding
143
+ } from '@ohos/flutter_ohos/src/main/ets/embedding/engine/plugins/FlutterPlugin';
144
+ import MethodChannel, {
145
+ MethodCallHandler,
146
+ MethodResult
147
+ } from '@ohos/flutter_ohos/src/main/ets/plugin/common/MethodChannel';
148
+ import MethodCall from '@ohos/flutter_ohos/src/main/ets/plugin/common/MethodCall';
149
+
150
+ export default class XxxPlugin implements FlutterPlugin, MethodCallHandler {
151
+ private channel: MethodChannel | null = null;
152
+
153
+ onAttachedToEngine(binding: FlutterPluginBinding): void {
154
+ // 注册 PlatformView Factory
155
+ binding.getPlatformViewRegistry()
156
+ .registerViewFactory("view_type_id", new XxxViewFactory());
157
+
158
+ // 注册 MethodChannel(用于控制视图)
159
+ this.channel = new MethodChannel(binding.getBinaryMessenger(), "channel_name");
160
+ this.channel.setMethodCallHandler(this);
161
+ }
162
+
163
+ onDetachedFromEngine(binding: FlutterPluginBinding): void {
164
+ this.channel?.setMethodCallHandler(null);
165
+ this.channel = null;
166
+ }
167
+
168
+ onMethodCall(call: MethodCall, result: MethodResult): void {
169
+ switch (call.method) {
170
+ // 视图控制方法(如 loadUrl、scrollTo 等)
171
+ default:
172
+ result.notImplemented();
173
+ break;
174
+ }
175
+ }
176
+ }
177
+ ```
178
+
179
+ ### viewType 一致性校验
180
+
181
+ **这是 PlatformView 最常见的问题**。Dart 层和 ETS 端的 viewType 字符串必须完全一致:
182
+
183
+ Dart 端(通常在 `_build` 方法中):
184
+ ```dart
185
+ AndroidView(viewType: 'com.example/xxx_view') // Android
186
+ UiKitView(viewType: 'com.example/xxx_view') // iOS
187
+ // OHOS 上也用相同的 viewType
188
+ ```
189
+
190
+ ETS 端:
191
+ ```ets
192
+ binding.getPlatformViewRegistry()
193
+ .registerViewFactory("com.example/xxx_view", new XxxViewFactory());
194
+ // ^^^^^^^^^^^^^^^^^^^^^^ 必须一致
195
+ ```
196
+
197
+ **校验步骤**:
198
+ 1. 在 Dart 代码中搜索 `AndroidView` 或 `UiKitView` 的 `viewType` 参数值
199
+ 2. 在 ETS 代码中确认 `registerViewFactory` 的第一个参数使用了相同的字符串
200
+
201
+ ### 带 MethodChannel 的 PlatformView 通信模式
202
+
203
+ PlatformView 通常需要通过 MethodChannel 与 Dart 端双向通信(如控制视图滚动、获取视图状态):
204
+
205
+ ```ets
206
+ // 每个视图实例有独立的 Channel(按 viewId 区分)
207
+ onAttachedToEngine(binding: FlutterPluginBinding): void {
208
+ binding.getPlatformViewRegistry()
209
+ .registerViewFactory("view_type_id", new XxxViewFactory(binding.getBinaryMessenger()));
210
+ }
211
+ ```
212
+
213
+ 在 Factory 中传入 BinaryMessenger,视图实例创建时建立独立 Channel:
214
+ ```ets
215
+ export class XxxPlatformView extends PlatformView implements MethodCallHandler {
216
+ private channel: MethodChannel;
217
+
218
+ constructor(messenger: BinaryMessenger, context: common.Context, viewId: number, args: Object) {
219
+ super();
220
+ // 每个视图实例有独立 Channel
221
+ this.channel = new MethodChannel(messenger, "view_type_id_" + viewId);
222
+ this.channel.setMethodCallHandler(this);
223
+ }
224
+
225
+ onMethodCall(call: MethodCall, result: MethodResult): void {
226
+ // 处理单个视图实例的控制命令
227
+ }
228
+
229
+ dispose(): void {
230
+ this.channel.setMethodCallHandler(null);
231
+ }
232
+ }
233
+ ```
234
+
235
+ ### ArkUI Controller attach 生命周期硬规则
236
+
237
+ 如果 PlatformView 使用 ArkUI controller 类对象,所有依赖组件绑定状态的 controller 调用必须等待 ArkUI 组件完成绑定。ArkWeb `webview.WebviewController` 是该规则的典型场景。
238
+
239
+ 该规则用于解决 controller 早于 ArkUI 组件绑定时被调用的时序问题。对于 ArkWeb `webview.WebviewController`,典型表现是 `The WebviewController must be associated with a Web component`、`Init error`;在 JS 执行、回调注册、滚动或状态查询链路中,也可能表现为空返回、调用无效、渲染侧异常或 JS crash。
240
+
241
+ 错误写法:在 MethodChannel 分支中直接调用 controller。该写法在 `Web.onControllerAttached` 之前执行时,可能触发 controller 未关联组件的初始化错误。
242
+
243
+ ```ets
244
+ case "currentUrl":
245
+ result.success(controller.getUrl());
246
+ break;
247
+ ```
248
+
249
+ 正确写法:建立统一 attach 队列,`onControllerAttached` 后统一 flush。带返回值的 MethodChannel 方法也必须在队列任务中完成 `MethodResult`。
250
+
251
+ ```ets
252
+ type ControllerTask = () => void;
253
+
254
+ private isControllerAttached: boolean = false;
255
+ private taskQueue: ControllerTask[] = [];
256
+
257
+ private runWhenControllerAttached(task: ControllerTask): void {
258
+ if (this.isControllerAttached) {
259
+ task();
260
+ return;
261
+ }
262
+ this.taskQueue.push(task);
263
+ }
264
+
265
+ onControllerAttached(): void {
266
+ this.isControllerAttached = true;
267
+ let tasks: ControllerTask[] = this.taskQueue;
268
+ this.taskQueue = [];
269
+ for (let index: number = 0; index < tasks.length; index++) {
270
+ tasks[index]();
271
+ }
272
+ }
273
+ ```
274
+
275
+ ```ets
276
+ case "currentUrl":
277
+ this.runWhenControllerAttached((): void => {
278
+ try {
279
+ result.success(controller.getUrl());
280
+ } catch (e) {
281
+ let error = e as Error;
282
+ result.error("ERROR", error.message, null);
283
+ }
284
+ });
285
+ break;
286
+ ```
287
+
288
+ ArkUI 组件必须在绑定回调中通知 PlatformView:
289
+
290
+ ```ets
291
+ Web({ src: this.initialUrl, controller: this.controller })
292
+ .onControllerAttached((): void => {
293
+ this.platformView?.onControllerAttached();
294
+ })
295
+ ```
296
+
297
+ 硬规则:
298
+ - 不允许只给 `loadUrl`、`registerJavaScriptProxy` 等个别方法特判队列。
299
+ - `currentUrl`、`runJavaScript`、`goBack`、`goForward`、`reload`、`scrollTo`、`scrollBy`、`getUserAgent`、`clearCache` 等所有 controller API 都必须经过统一 attach 队列。
300
+ - 带返回值的 MethodChannel 方法也要延迟完成 `MethodResult`,不得在未绑定时直接调用 controller。
301
+
302
+ ### 参考文档
303
+
304
+ 通过 **flutter-docs-lookup** Skill 检索「PlatformView 使用指南」「如何使用PlatformView」获取详细实现说明。
305
+
306
+ ---
307
+
308
+ ## 第三部分:常见编译错误与修复
309
+
310
+ ### 1. `Struct 'XxxComponent' does not comply with the struct syntax`
311
+
312
+ **原因**:ArkUI 组件(struct)语法不正确。
313
+
314
+ **修复**:
315
+ - `struct` 必须用 `@Component` 装饰
316
+ - `struct` 中必须有 `build()` 方法
317
+ - `struct` 不能有构造函数,用 `@ObjectLink` 或 `@Prop` 传参
318
+ - `struct` 中的方法不能使用 `private` / `public` 修饰符
319
+
320
+ ### 2. `'@Observed' decorator can only be used with class declarations`
321
+
322
+ **原因**:`@Observed` 用在了非 class 声明上。
323
+
324
+ **修复**:`@Observed` 只能修饰 `class`,不能修饰 `struct` 或 `interface`:
325
+ ```ets
326
+ @Observed
327
+ class Params { // 正确:class
328
+ viewId: number = 0;
329
+ }
330
+
331
+ // @Observed
332
+ // struct Xxx { } // 错误:struct 不能用 @Observed
333
+ ```
334
+
335
+ ### 3. `'@ObjectLink' decorated variable must be of the '@Observed' decorated class type`
336
+
337
+ **原因**:`@ObjectLink` 引用的类型没有用 `@Observed` 装饰。
338
+
339
+ **修复**:确保 Params 类带有 `@Observed` 装饰器:
340
+ ```ets
341
+ @Observed
342
+ class Params { ... }
343
+
344
+ @Component
345
+ struct XxxComponent {
346
+ @ObjectLink params: Params; // Params 必须是 @Observed class
347
+ }
348
+ ```
349
+
350
+ ### 4. `Cannot find name 'WrappedBuilder'`
351
+
352
+ **原因**:`WrappedBuilder` 是 ArkUI 内置类型,不需要导入但需要正确使用。
353
+
354
+ **修复**:
355
+ - `WrappedBuilder` 在 ArkTS 中是全局可用的,无需 import
356
+ - 泛型参数必须匹配 @Builder 函数的参数类型:
357
+ ```ets
358
+ @Builder
359
+ function buildXxxView(params: Params) { ... }
360
+
361
+ getView(): WrappedBuilder<[Params]> {
362
+ return new WrappedBuilder(buildXxxView);
363
+ }
364
+ ```
365
+
366
+ ### 5. `Property 'getPlatformViewRegistry' does not exist`
367
+
368
+ **原因**:`FlutterPluginBinding` 导入路径不正确或版本不匹配。
369
+
370
+ **修复**:确保从正确路径导入:
371
+ ```ets
372
+ import {
373
+ FlutterPlugin,
374
+ FlutterPluginBinding
375
+ } from '@ohos/flutter_ohos/src/main/ets/embedding/engine/plugins/FlutterPlugin';
376
+ ```
377
+
378
+ ### 6. PlatformView 不显示 / 白屏
379
+
380
+ **原因**(编译通过但运行异常,预防性说明):
381
+ - viewType 不一致(最常见)
382
+ - `getView()` 返回的 WrappedBuilder 参数类型不匹配
383
+ - ArkUI 组件没有设置宽高
384
+
385
+ **修复**:
386
+ - 检查 viewType 一致性
387
+ - 确保组件设置了 `.width('100%').height('100%')`
388
+ - 确保 `@Builder` 函数参数类型与 `WrappedBuilder<[T]>` 的泛型 T 一致
389
+
390
+ ### 7. `@ObjectLink` 变量初始化错误
391
+
392
+ **原因**:`@ObjectLink` 变量不能有默认初始值。
393
+
394
+ **修复**:
395
+ ```ets
396
+ @Component
397
+ struct XxxComponent {
398
+ @ObjectLink params: Params; // 正确:不赋初始值
399
+ // @ObjectLink params: Params = new Params(); // 错误:不能有初始值
400
+ }
401
+ ```
402
+
403
+ ### 8. `@Builder` 函数参数与 `@ObjectLink` 类型边界不一致
404
+
405
+ **原因**:`@Builder` 函数从 `PlatformView.getView()` 接收参数时,参数类型是 `Params`(`@Observed class`),但如果在 builder 内部使用 `params as MapViewParams` 这样的强转,ArkTS 无法证明类型兼容性,导致传给 `@ObjectLink` 的赋值失败。
406
+
407
+ **常见错误模式**:
408
+ ```ets
409
+ // ❌ 错误:builder 中强转参数类型
410
+ @Builder
411
+ function buildMapView(params: Params) {
412
+ MapComponent({ params: params as MapViewParams }) // 类型不兼容
413
+ }
414
+ ```
415
+
416
+ **修复**:确保整条链路类型一致 — `PlatformView` 构造中创建的 Params 类型、`getView()` 返回的 `WrappedBuilder` 泛型参数、`@Builder` 函数参数类型、`@Component struct` 中 `@ObjectLink` 声明类型,四者**必须是同一个 `@Observed class`**:
417
+
418
+ ```ets
419
+ @Observed
420
+ export class MapViewParams { // 唯一 Params 类型
421
+ viewId: number = 0;
422
+ mapController: MapComponentController | null = null;
423
+ }
424
+
425
+ @Builder
426
+ function buildMapView(params: MapViewParams) { // 直接用 MapViewParams
427
+ MapComponent({ params: params }) // 无需强转
428
+ }
429
+
430
+ @Component
431
+ struct MapComponent {
432
+ @ObjectLink params: MapViewParams; // 同一类型
433
+ build() { /* ... */ }
434
+ }
435
+
436
+ export class MapPlatformView extends PlatformView {
437
+ private params: MapViewParams; // 同一类型
438
+ constructor(...) {
439
+ super();
440
+ this.params = new MapViewParams();
441
+ }
442
+ getView(): WrappedBuilder<[MapViewParams]> { // 同一类型
443
+ return new WrappedBuilder(buildMapView);
444
+ }
445
+ }
446
+ ```
447
+
448
+ > **关键原则**:不要在 `@Builder` 和 `@Component` 之间引入额外的类型转换。如果需要传递控制器等原生对象,直接作为 `@Observed class` 的属性,在 PlatformView 构造函数中赋值。
@@ -0,0 +1,180 @@
1
+ # 纯 Dart 包鸿蒙适配
2
+
3
+ ## 适用条件
4
+
5
+ - 包类型为纯 Dart(无 `android/`、`ios/` 目录)
6
+ - 但可能依赖了有平台特定代码的包
7
+ - 或使用了 `dart:io` 中的平台判断逻辑
8
+
9
+ ---
10
+
11
+ ## 第一部分:工程搭建
12
+
13
+ ### 无需创建工程
14
+
15
+ 纯 Dart 包不需要 `flutter create`,主要工作是:
16
+ 1. 检查依赖链中是否有不支持 OHOS 的包
17
+ 2. 修改平台判断逻辑
18
+ 3. 确保 `flutter pub get` 能成功
19
+
20
+ ### pubspec.yaml 检查
21
+
22
+ 确认 `pubspec.yaml` 中:
23
+ - 没有用 `platforms:` 字段限制平台支持范围
24
+ - 如果有 `flutter.plugin.platforms` 配置,添加 `ohos` 条目
25
+
26
+ ### 编译验证命令
27
+
28
+ 纯 Dart 包没有原生代码,无需 `flutter build hap`,编译验证为:
29
+ ```bash
30
+ flutter pub get
31
+ ```
32
+
33
+ 如果 `flutter pub get` 成功且无 Dart 分析错误,即视为编译通过。
34
+
35
+ ---
36
+
37
+ ## 第二部分:编码实现
38
+
39
+ ### 平台判断兼容
40
+
41
+ 如果代码中使用了 `Platform.isXxx` 判断,需要添加 OHOS 支持。
42
+
43
+ > **必须遵循 CLAUDE.md 中的「平台检测标准」**:直接使用 `Platform.isOhos`,不使用排除法或字符串比较。
44
+
45
+ ```dart
46
+ import 'dart:io' show Platform;
47
+
48
+ // 修改前:缺少 OHOS 分支
49
+ if (Platform.isAndroid) {
50
+ // Android 逻辑
51
+ } else if (Platform.isIOS) {
52
+ // iOS 逻辑
53
+ }
54
+
55
+ // 修改后:添加 OHOS 分支
56
+ if (Platform.isAndroid) {
57
+ // Android 逻辑
58
+ } else if (Platform.isIOS) {
59
+ // iOS 逻辑
60
+ } else if (Platform.isOhos) {
61
+ // OHOS 逻辑(通常与 Android 逻辑相近)
62
+ }
63
+ ```
64
+
65
+ ### 条件导入
66
+
67
+ 如果使用了条件导入,需要确认 OHOS 能正确匹配:
68
+
69
+ ```dart
70
+ // OHOS 属于 dart:io 平台,会匹配 dart.library.io 条件
71
+ import 'stub.dart'
72
+ if (dart.library.io) 'io.dart'
73
+ if (dart.library.html) 'web.dart';
74
+ ```
75
+
76
+ 通常无需额外修改,因为 OHOS 支持 `dart:io`。
77
+
78
+ ### 依赖链检查
79
+
80
+ 检查所有传递依赖中是否有平台原生插件:
81
+
82
+ ```bash
83
+ flutter pub deps
84
+ ```
85
+
86
+ 对输出结果中的每个包,检查其 `pubspec.yaml` 是否有 `flutter.plugin.platforms` 配置。
87
+ 不支持 OHOS 的平台原生插件会导致运行时 `MissingPluginException`(编译时不报错)。
88
+
89
+ **常见需要处理的依赖**:
90
+
91
+ | 依赖包 | 问题 | 处理方式 |
92
+ |--------|------|---------|
93
+ | `path_provider` | 无 OHOS 实现 | 用 `Directory.systemTemp`(dart:io)替代 |
94
+ | `shared_preferences` | 无 OHOS 实现 | 用内存缓存替代或移除 |
95
+ | `url_launcher` | 无 OHOS 实现 | 通过 MethodChannel 调用 OHOS Want |
96
+ | `package_info_plus` | 无 OHOS 实现 | 硬编码或通过 MethodChannel 获取 |
97
+
98
+ ### 处理不支持 OHOS 的传递依赖
99
+
100
+ **方案 A:try-catch 包裹**
101
+ ```dart
102
+ Future<String> getSomePath() async {
103
+ try {
104
+ final dir = await getApplicationDocumentsDirectory();
105
+ return dir.path;
106
+ } catch (_) {
107
+ return Directory.systemTemp.path;
108
+ }
109
+ }
110
+ ```
111
+
112
+ **方案 B:平台判断跳过**
113
+ ```dart
114
+ if (!Platform.isOhos) {
115
+ await _initSharedPreferences();
116
+ }
117
+ ```
118
+
119
+ **方案 C:提供默认值**
120
+ ```dart
121
+ String get storagePath {
122
+ if (Platform.isOhos) {
123
+ return '/data/storage/el2/base/haps/entry/files';
124
+ }
125
+ return _nativeStoragePath;
126
+ }
127
+ ```
128
+
129
+ ---
130
+
131
+ ## 第三部分:常见编译错误与修复
132
+
133
+ ### 1. `The getter 'isOhos' isn't defined for the class 'Platform'`
134
+
135
+ **原因**:标准 Dart SDK 未定义 `Platform.isOhos`,需要使用 Flutter OHOS 分支。
136
+
137
+ **修复**:
138
+ - 确认使用的是 Flutter OHOS 版本(`flutter --version` 应显示 OpenHarmony 相关信息)
139
+ - Flutter OHOS 分支已原生支持 `Platform.isOhos`,直接使用即可
140
+
141
+ ### 2. `A value of type 'Future<xxx>' can't be assigned to a variable of type 'yyy'`
142
+
143
+ **原因**:添加 try-catch 后改变了返回类型。
144
+
145
+ **修复**:确保 try-catch 的返回类型与原始方法一致:
146
+ ```dart
147
+ Future<Directory> getDir() async {
148
+ try {
149
+ return await getApplicationDocumentsDirectory();
150
+ } catch (_) {
151
+ return Directory.systemTemp; // 返回类型一致
152
+ }
153
+ }
154
+ ```
155
+
156
+ ### 3. `Target of URI doesn't exist: 'package:xxx/xxx.dart'`
157
+
158
+ **原因**:传递依赖包缺失。
159
+
160
+ **修复**:
161
+ - 运行 `flutter pub get` 重新获取依赖
162
+ - 检查 `pubspec.yaml` 中的依赖版本约束是否正确
163
+ - 如果是路径依赖,检查路径是否存在
164
+
165
+ ### 4. `flutter pub get` 报版本冲突
166
+
167
+ **原因**:不同依赖包对同一依赖要求的版本范围不兼容。
168
+
169
+ **修复**:
170
+ - 在 `pubspec.yaml` 中添加 `dependency_overrides` 强制使用特定版本
171
+ - 或调整版本约束范围
172
+ - 检查是否有多个包依赖不同版本的 `platform_interface`
173
+
174
+ ### 5. Dart 分析报 `dead_code` 或 `unreachable_switch_case`
175
+
176
+ **原因**:添加 OHOS 平台分支后可能触发静态分析警告。
177
+
178
+ **修复**:
179
+ - 如果是 `Platform.isXxx` 枚举式判断,确保覆盖所有平台或添加 `else` 默认分支
180
+ - 警告不影响编译,但建议修复以保持代码质量