deveco_hmigbot 0.21.5

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 (101) hide show
  1. package/LICENSE +26 -0
  2. package/README.md +50 -0
  3. package/agents/hmigbot-worker.md +61 -0
  4. package/agents/hmigbot.md +22 -0
  5. package/agents/workflow-subagent.md +55 -0
  6. package/commands/hmigbot.md +17 -0
  7. package/dist/index.js +1 -0
  8. package/manifest.json +19 -0
  9. package/package.json +29 -0
  10. package/skills/migrate-core/FILES.md +26 -0
  11. package/skills/migrate-core/SKILL.md +484 -0
  12. package/skills/migrate-core/references/README.md +64 -0
  13. package/skills/migrate-core/references/flow/arkts-vector-gate.md +55 -0
  14. package/skills/migrate-core/references/flow/build-error-patterns.md +52 -0
  15. package/skills/migrate-core/references/flow/conventions-template.md +244 -0
  16. package/skills/migrate-core/references/flow/navigation-migration.md +42 -0
  17. package/skills/migrate-core/references/flow/platform-api-guards.md +59 -0
  18. package/skills/migrate-core/references/flow/platform-model-gaps.md +43 -0
  19. package/skills/migrate-core/references/flow/resource-conversion.md +46 -0
  20. package/skills/migrate-core/references/flow/ui-layout-semantics.md +124 -0
  21. package/skills/migrate-core/references/flow/unit-breakdown.md +42 -0
  22. package/skills/migrate-core/references/host-capabilities.md +24 -0
  23. package/skills/migrate-core/references/topics/app-identity.md +214 -0
  24. package/skills/migrate-core/references/topics/env-doctor.md +245 -0
  25. package/skills/migrate-core/references/topics/i18n/README.md +458 -0
  26. package/skills/migrate-core/references/topics/i18n/references/code-examples.md +304 -0
  27. package/skills/migrate-core/references/topics/i18n/references/common-pitfalls.md +354 -0
  28. package/skills/migrate-core/references/topics/i18n/references/dynamic-language-switch.md +464 -0
  29. package/skills/migrate-core/references/topics/i18n/references/language-codes.md +104 -0
  30. package/skills/migrate-core/references/topics/icon-sizing.md +98 -0
  31. package/skills/migrate-core/references/topics/library-migration/README.md +234 -0
  32. package/skills/migrate-core/references/topics/library-migration/closed-source-sdk.md +128 -0
  33. package/skills/migrate-core/references/topics/library-migration/download-api-decision.md +84 -0
  34. package/skills/migrate-core/references/topics/library-migration/library-mapping-table.md +100 -0
  35. package/skills/migrate-core/references/topics/library-migration/napi-compile-guide.md +84 -0
  36. package/skills/migrate-core/references/topics/library-migration/ohpm-search-guide.md +73 -0
  37. package/skills/migrate-core/references/topics/library-migration/stdlib-mapping-table.md +34 -0
  38. package/skills/migrate-core/references/topics/resources/aar-decompile.md +25 -0
  39. package/skills/migrate-core/references/topics/resources/conversion-rules.md +625 -0
  40. package/skills/migrate-core/references/topics/resources/dependency-analysis-rules.md +328 -0
  41. package/skills/migrate-core/references/topics/resources/material-design-icons.md +173 -0
  42. package/skills/migrate-core/references/topics/resources/svg-fix-patterns.md +175 -0
  43. package/skills/migrate-core/references/topics/resources/xml-drawable-to-svg-rules.md +513 -0
  44. package/skills/migrate-core/references/topics/system-capabilities/README.md +331 -0
  45. package/skills/migrate-core/references/topics/system-capabilities/avplayer-guide.md +161 -0
  46. package/skills/migrate-core/references/topics/system-capabilities/background-tasks.md +403 -0
  47. package/skills/migrate-core/references/topics/system-capabilities/browser-intent.md +121 -0
  48. package/skills/migrate-core/references/topics/system-capabilities/camera-picker.md +118 -0
  49. package/skills/migrate-core/references/topics/system-capabilities/document-picker.md +246 -0
  50. package/skills/migrate-core/references/topics/system-capabilities/file-utils.md +131 -0
  51. package/skills/migrate-core/references/topics/system-capabilities/permission-helper.md +112 -0
  52. package/skills/migrate-core/references/topics/system-capabilities/photo-access-helper.md +208 -0
  53. package/skills/migrate-core/references/topics/system-capabilities/print-management.md +213 -0
  54. package/skills/migrate-core/references/topics/system-capabilities/share-panel.md +177 -0
  55. package/skills/migrate-core/references/topics/system-capabilities/system-settings.md +322 -0
  56. package/skills/migrate-core/references/topics/system-capabilities/telephony-dial.md +49 -0
  57. package/skills/migrate-core/references/topics/system-capabilities/video-playback.md +42 -0
  58. package/skills/migrate-core/references/topics/system-capabilities/webview-patterns.md +38 -0
  59. package/skills/migrate-core/references/topics/ui-alignment/README.md +344 -0
  60. package/skills/migrate-core/references/topics/ui-alignment/references/dark-mode.md +47 -0
  61. package/skills/migrate-core/references/topics/ui-alignment/references/layout-mapping.md +301 -0
  62. package/skills/migrate-core/references/topics/ui-alignment/references/visual-patterns.md +411 -0
  63. package/skills/migrate-core/scripts/closure/check-anchors.mjs +186 -0
  64. package/skills/migrate-core/scripts/closure/check-api-guards.mjs +175 -0
  65. package/skills/migrate-core/scripts/closure/check-consumers.mjs +301 -0
  66. package/skills/migrate-core/scripts/closure/check-permissions.mjs +165 -0
  67. package/skills/migrate-core/scripts/closure/check-resources.mjs +130 -0
  68. package/skills/migrate-core/scripts/closure/check-routes.mjs +527 -0
  69. package/skills/migrate-core/scripts/closure/check-safearea.mjs +122 -0
  70. package/skills/migrate-core/scripts/closure/check-stubs.mjs +69 -0
  71. package/skills/migrate-core/scripts/closure/closure-suite.mjs +256 -0
  72. package/skills/migrate-core/scripts/closure/idioms.json +105 -0
  73. package/skills/migrate-core/scripts/convert/convert-resources.mjs +437 -0
  74. package/skills/migrate-core/scripts/feasibility/feasibility.mjs +235 -0
  75. package/skills/migrate-core/scripts/feasibility/tables/cross-platform.json +11 -0
  76. package/skills/migrate-core/scripts/feasibility/tables/deprecated-api.json +10 -0
  77. package/skills/migrate-core/scripts/feasibility/tables/imported-arkts-core.json +425 -0
  78. package/skills/migrate-core/scripts/feasibility/tables/lib-equivalence.json +206 -0
  79. package/skills/migrate-core/scripts/feasibility/tables/system-capabilities.json +22 -0
  80. package/skills/migrate-core/scripts/front.mjs +107 -0
  81. package/skills/migrate-core/scripts/interface/ark-extract.mjs +172 -0
  82. package/skills/migrate-core/scripts/interface/interface.mjs +152 -0
  83. package/skills/migrate-core/scripts/ledger/ledger.mjs +383 -0
  84. package/skills/migrate-core/scripts/ledger/parse-cards.mjs +98 -0
  85. package/skills/migrate-core/scripts/lib/literals.mjs +37 -0
  86. package/skills/migrate-core/scripts/lib/scan.mjs +315 -0
  87. package/skills/migrate-core/scripts/smoke/align-sdk.mjs +118 -0
  88. package/skills/migrate-core/scripts/smoke/ensure-sign.mjs +53 -0
  89. package/skills/migrate-core/scripts/smoke/smoke.mjs +238 -0
  90. package/skills/migrate-core/scripts/smoke/verdict.mjs +31 -0
  91. package/skills/migrate-core/scripts/smoke/walk.mjs +480 -0
  92. package/skills/migrate-core/scripts/transpile/mapping.json +76 -0
  93. package/skills/migrate-core/scripts/transpile/transpile-layout.mjs +404 -0
  94. package/skills/migrate-core/scripts/vectors/run-arkts-vectors.mjs +107 -0
  95. package/skills/migrate-core/scripts/vectors/setup-arkts-test.mjs +90 -0
  96. package/skills/migrate-core/scripts/wire/extractors.mjs +258 -0
  97. package/skills/migrate-core/scripts/wire/wire-routes.mjs +507 -0
  98. package/skills/migrate-core/templates/acceptance.js +365 -0
  99. package/skills/migrate-core/templates/explore.js +86 -0
  100. package/skills/migrate-core/templates/implement.js +211 -0
  101. package/skills/migrate-core/templates/mig_slices.js +491 -0
@@ -0,0 +1,49 @@
1
+ # 电话拨号(Telephony Kit)
2
+
3
+ > 拉起系统拨号界面(显示待拨号码)用 Telephony Kit 的 `call.makeCall`——**不是** `Want + startAbility`。这与浏览器/URL 跳转(`browser-intent.md`,走 `viewData`)是**不同机制**,勿混用。
4
+
5
+ ---
6
+
7
+ ## 基本导入
8
+
9
+ ```typescript
10
+ import { call } from '@kit.TelephonyKit'
11
+ import { BusinessError } from '@kit.BasicServicesKit'
12
+ ```
13
+
14
+ ---
15
+
16
+ ## 拉起系统拨号界面
17
+
18
+ > ✅ **验证状态**:已 probe 编译通过(`call.makeCall('10086')`,BUILD SUCCESSFUL)
19
+
20
+ ```typescript
21
+ // makeCall(phoneNumber: string): Promise<void>
22
+ // 号码作为 string 实参直接传入;跳转到系统拨号界面并显示待拨号码。
23
+ // 只支持在 UIAbility 中调用;可能失败(如设备无电话能力),须接 .catch。
24
+ function dialNumber(phoneNumber: string): void {
25
+ call.makeCall(phoneNumber)
26
+ .then(() => {
27
+ hilog.info(DOMAIN, TAG, `Dialer opened for ${phoneNumber}`)
28
+ })
29
+ .catch((err: BusinessError) => {
30
+ hilog.error(DOMAIN, TAG, `makeCall failed: code=${err.code}, message=${err.message}`)
31
+ })
32
+ }
33
+ ```
34
+
35
+ ---
36
+
37
+ ## 关键约定
38
+
39
+ - **用 `call.makeCall(phoneNumber)`**,号码是纯字符串(如 `'1234567890'`),**不带 `tel:` 前缀**。
40
+ - **不要**把拨号走 `Want{action:'ohos.want.action.viewData', uri:'tel:<号码>'}` + `startAbility`——那条隐式路径非正解。
41
+ - **不要**用已废弃的 `call.dial(...)`(自 API 9 起废弃,替代能力仅对系统应用开放);应用侧拉起拨号界面用 `makeCall`。
42
+ - `call` 从 `@kit.TelephonyKit` 导入,不要从 `@kit.AbilityKit` / Want 相关模块导入。
43
+ - syscap `SystemCapability.Applications.Contacts`(since API 7);`makeCall` 只是拉起拨号界面(不直接拨出),本身无需额外权限。
44
+
45
+ ---
46
+
47
+ ## module.json5 配置
48
+
49
+ 拉起系统拨号界面(`makeCall`)**无需**在 module.json5 声明 action/entity——直接调用即可(区别于隐式 Want 拉起需声明 skills 的场景)。
@@ -0,0 +1,42 @@
1
+ # 视频播放(AVPlayer + XComponent)
2
+
3
+ > 视频特化层:AVPlayer 状态机/fd:// 协议/倍速等音视频通用基础见 avplayer-guide.md;本篇只写视频独有工程问题。断言来源为生产迁移复盘,未逐条复验,首用按 SDK 查证。
4
+
5
+ ## 1. Surface 时序(最高频坑)
6
+
7
+ - `XComponent(type: SURFACE)` 的 `onLoad` 拿 surfaceId 与 AVPlayer 初始化需**双向等待**:surfaceId 已设 + player 已 Initialized 都满足才 attach;surfaceId 在 Initialized 之后、`prepare` 之前设置。
8
+ - `prepared` 前收到的 `seek` 请求先暂存、prepared 后重放。
9
+ - 时长用 `durationUpdate` 事件获取,不用 getDuration。
10
+ - 启播参数由调用方**透传 videoUrl**(进页面再反查详情接口 = 部分子项返空 + ~700ms 延迟);业务详情走 `fromJson` 反序列化(plain object 字段 setter 静默失败);`router.pushUrl` 路径下 `@Param` 不注入,用 AppStorageV2/显式透传兜底。
11
+
12
+ ## 2. 后台与横屏
13
+
14
+ - **有声视频后台续播可申请 AUDIO_PLAYBACK 长时任务**(官方该类型覆盖"音频、视频在后台播放");**无声/静音视频页不要申请**——系统一致性校验检测不到播放会拒批或挂起;后台只需展示画面的走画中画 PiP(另见 background-tasks.md 同条)。
15
+ - 进/退横屏必须**成对** set/restore orientation(aboutToAppear/aboutToDisappear 配对);沉浸全屏 + `setSpecificSystemBarEnabled('navigationIndicator', false)` 防进度条最右段被系统手势横条遮挡。
16
+ - 返回挽留 Dialog 拦截 `onBackPress`。
17
+
18
+ ## 3. Letterbox(保留原始宽高比)
19
+
20
+ - 禁 XComponent `width/height('100%')` 直接拉伸;按视频宽高比算实际 `xcWidthVp/xcHeightVp` 与偏移 `videoOffsetXVp/Y`。
21
+ - 顶/底控制栏 position **钉到视频帧**(用 videoOffset 偏移),不钉屏幕边、不用外层 `alignContent: Center`(Center 会让顶栏漂移、黑边上挂按钮);外层 Stack 用 `TopStart`。
22
+
23
+ ## 4. 控件层
24
+
25
+ - 控件 3.5s 自动隐藏,定时器覆盖 PLAYING / PAUSED / PREPARED 三态。
26
+ - XComponent 之上放**透明点击层**接收点击唤出控件(XComponent 自身不接)。
27
+ - 按钮图标直拷 Android 原工程 webp,禁用 Unicode 字形/手搓黑圆(两端字形不一致)。
28
+ - dp→vp 1:1 直拷;`layout_centerVertical` = `top:'50%'` + `translate(y:-halfH)`。
29
+
30
+ ## 5. 视频专属错误速记
31
+
32
+ | 错误 | 正确做法 |
33
+ |---|---|
34
+ | linearGradient 用 0xAARRGGBB number(吞 alpha) | 用 `'rgba()'` 字符串或带 alpha 颜色 |
35
+ | 无声视频页加 AUDIO_PLAYBACK | 后台画面走 PiP;有声续播才申请 |
36
+ | 横屏方向只 set 不 restore | 成对管理 |
37
+ | XComponent 100% 拉伸 | letterbox 计算实际宽高 |
38
+ | 顶/底栏钉屏幕边/Center 对齐 | 钉视频帧偏移 |
39
+ | XComponent 上无透明点击层 | 加透明层接点击 |
40
+
41
+ ---
42
+ 蒸馏自 corpus/candidates/arkts-video-playback,2026-09 吸收
@@ -0,0 +1,38 @@
1
+ # WebView 工程模式(Web 组件 + WebviewController)
2
+
3
+ > 嵌 WebView 场景(不限浏览器)的已验证模式。`Web()`/`WebviewController` API 与状态体系 V1/V2 无关。断言未逐条复验,首用按 SDK 查证。
4
+
5
+ ## 1. JS 执行四原则
6
+
7
+ 1. **IIFE 包裹**:注入 JS 一律 `(function(){ ... })()`,防全局污染。
8
+ 2. **catch 兜底**:`runJavaScript()` 返回 Promise,必须 `.catch()`——页面异常否则带崩应用。
9
+ 3. **大文件分块**:rawfile 加载的 JS/CSS(如 Readability.js)用分块 `uint8ArrayToString()`(每 8192 字节一块),`String.fromCharCode(...spread)` 会栈溢出。
10
+ 4. **返回值反序列化**:`runJavaScript` 返回的是表达式结果的 **JSON 字符串化**形式——字符串被外层引号包裹、内部引号/换行被转义,需手动 strip + unescape;JS 返回 Promise 时会自动等待 resolve 再返回。
11
+
12
+ ## 2. CSS 注入(幂等)
13
+
14
+ `runJavaScript` 创建带唯一 ID 的 `<style>`:查 `getElementById(styleId)`,无则 createElement 挂 head,有则只更新 `textContent`——多次注入不叠加;注入前对 CSS 做 `\` `` ` `` `$` 转义。移除 = 按 ID remove。
15
+
16
+ ## 3. 样式持久化
17
+
18
+ 页面导航后注入的 `<style>` 全丢。方案:`onPageEnd` 回调里统一 `reapplyStyles()`(检查所有样式开关状态、重注已开启项),比逐 toggle 分别持久化干净。
19
+
20
+ ## 4. WebView 内 fetch 调外部 API
21
+
22
+ "读取 DOM → 调外部服务 → 回写 DOM"类功能(原地翻译/摘要/标注)优先在 WebView JS 环境内 `fetch()` 完成,一次 runJavaScript 走完全流程——不走 ArkTS native HTTP(省多轮 ArkTS↔JS 通信与序列化映射)。
23
+
24
+ ## 5. 双 WebView 通信(分屏)
25
+
26
+ 两个 WebView 无法直接通信。已验证通道:**借 `document.title`**——发送方 JS 设 `document.title = '__MSG_TYPE__' + payload`;接收方在 `onTitleReceive` 检测前缀拦截处理、不更新真实标题。
27
+
28
+ ## 6. ArkTS 环境差异速查
29
+
30
+ | 问题 | 处置 |
31
+ |---|---|
32
+ | 无全局 TextEncoder/TextDecoder | `import { util } from '@kit.ArkTS'` → `new util.TextEncoder()` |
33
+ | 无全局 URL 类 | 手动解析字符串(`indexOf('://')` 等),不能 `new URL(str)` |
34
+ | 无 `{ ...obj }` 展开 | 逐字段构造新对象 |
35
+ | rawfile 返回 Uint8Array | 分块转字符串(见 §1.3) |
36
+
37
+ ---
38
+ 蒸馏自 corpus/candidates/arkts-webview,2026-09 吸收
@@ -0,0 +1,344 @@
1
+ <!-- 原技能 arkts-ui-alignment,已吸收为 migrate-core 语料专题,不再单独注册 -->
2
+ > 将 Android UI 设计迁移到 ArkTS/HarmonyOS 的等价实现。当用户需要匹配 Android Material Design 视觉效果、把 Android 布局/控件映射到 ArkTS 等价物(含 SymbolGlyph 图标体系、颜色/间距/字号对齐)时触发。即使只说"还原这个安卓界面""图标怎么对应"也应触发。不适用于 ArkTS 原创组件设计。
3
+
4
+ # ArkTS UI Alignment — Android UI 迁移对齐
5
+
6
+ ## API 版本
7
+
8
+ 本 skill 基于 **API 12+**(HarmonyOS 5.0.0+)。UI 相关导入:
9
+
10
+ - ArkUI 组件:内置,无需额外导入
11
+ - SymbolGlyph:内置,资源引用 `$r('sys.symbol.xxx')`
12
+ - 弹窗/轻提示:`this.getUIContext().getPromptAction()`,无需额外导入
13
+
14
+ 不确定的平台行为查官方文档确认(devecocli docs),不凭记忆写。
15
+
16
+ ---
17
+
18
+ ## 生成约定:本项目锁 ArkUI V2
19
+
20
+ 本 skill 的产物是**可运行的迁移页面**,一律用 **ArkUI V2** 声明式外壳(本 skill 讲的是视觉/控件对齐,不改这条):
21
+
22
+ - 页面 struct = `@Entry @ComponentV2`(**不是** `@Component`);状态用 `@Local`/`@Param`/`@Once`/`@Event`/`@Monitor`/`@Provider`/`@Consumer`(**绝不**用 V1 的 `@State`/`@Prop`/`@Link`/`@Watch`/`@Provide`/`@Consume`)。
23
+ - 本文档下方示例若出现 V1 装饰器,一律按 V2 改写;**映射/颜色/symbol/间距等对齐事实不变,只换装饰器外壳**。
24
+ - **迁移还原场景**:源 XML/dimens 有实际值时以源值为准(1:1 还原);本文的颜色系统映射与 4vp 间距体系仅在源值缺失时兜底。
25
+
26
+ ```typescript
27
+ @Entry
28
+ @ComponentV2
29
+ struct Index {
30
+ @Local selected: string = ''
31
+ build() { /* 迁移后的 UI */ }
32
+ }
33
+ ```
34
+
35
+ ---
36
+
37
+ ## Android → ArkTS 组件映射表
38
+
39
+ | Android 元素 | ArkTS 组件 | 备注 |
40
+ |-------------|-----------|------|
41
+ | `BottomNavigationView` | 自定义 `Row` + `@Builder tabBarItem` | 不用 `Tabs` 在 Navigation 内部 |
42
+ | `BottomSheetDialogFragment` | `NavDestination` (全屏) 或 `Sheet` | 视需求选择 |
43
+ | `DrawerLayout` | `SideBarContainer` | 侧边栏 |
44
+ | `RecyclerView` | `List` + `LazyForEach` | 虚拟列表 |
45
+ | `ViewPager2` | `Swiper` | 翻页 |
46
+ | `CoordinatorLayout` | `Stack` + 自定义手势 | 需手动实现 |
47
+ | `CardView` | `Column` + `borderRadius` + `shadow` | 卡片 |
48
+ | `FloatingActionButton` | `Button` + `Stack` 右下对齐(`Alignment.BottomEnd`) | FAB;勿写死 position 坐标 |
49
+ | `ProgressBar` (Linear) | `Progress({ type: ProgressType.Linear })` | 进度条 |
50
+ | `ProgressBar` (Circular) | `Progress({ type: ProgressType.Ring })` | 进度环 |
51
+ | `Toolbar` / `ActionBar` | `NavDestination` 标题栏 | 自动 |
52
+ | `AlertDialog` | `getUIContext().getPromptAction().showDialog()` / `openCustomDialog` | 弹窗(全局 `AlertDialog.show` 已废弃;禁 @CustomDialog+CustomDialogController,V2 宿主运行时 controller 不绑定) |
53
+ | `PopupMenu` | `Menu` + `MenuItem` | 菜单 |
54
+ | `Snackbar` | `getUIContext().getPromptAction().showToast()` | 轻提示(全局 `promptAction.*` 已废弃) |
55
+ | `ImageView` + Glide | `Image(url)` 或 `@ohos/imageknife` | 图片加载 |
56
+ | `EditText` | `TextInput` / `TextArea`(多行) | 输入框 |
57
+ | `CheckBox` | `Checkbox` | 多选 |
58
+ | `RadioButton` + `RadioGroup` | `Radio`(同 group) | 单选 |
59
+ | `Switch` / `SwitchCompat` | `Toggle({ type: ToggleType.Switch })` | 开关 |
60
+ | `SeekBar` | `Slider` | 滑块 |
61
+ | `Spinner` | `Select` | 下拉选择 |
62
+ | `SwipeRefreshLayout` | `Refresh` | 下拉刷新 |
63
+
64
+ > 详细映射 + 代码示例见 `references/layout-mapping.md`
65
+
66
+ ---
67
+
68
+ ## SymbolGlyph 图标体系
69
+
70
+ ### 已验证可用名称(编译验证通过,按类别速查)
71
+
72
+ 以下名称经 DevEco Studio 真机编译验证**存在**,可直接 `$r('sys.symbol.<名>')` 使用:
73
+
74
+ - **导航/箭头**:`house` `chevron_left` `chevron_right` `chevron_up` `chevron_down` `arrow_left` `arrow_right` `arrow_up` `arrow_down` `arrow_2_circlepath`
75
+ - **列表/布局**:`list_bullet` `line_3_horizontal` `square_grid_2x2`
76
+ - **媒体控制**:`play_fill` `pause_fill` `playpause_fill` `backward_fill` `forward_end_fill` `backward_end_fill` `speaker_wave_2_fill` `mic` `mic_fill` `repeat` `repeat_1` `shuffle`
77
+ - **账户/隐私**:`person` `person_fill` `person_2` `lock` `eye` `eye_slash`(密码框显示/隐藏 = `eye` / `eye_slash`)
78
+ - **状态/标记**:`checkmark` `checkmark_circle` `checkmark_circle_fill` `xmark` `xmark_circle` `xmark_circle_fill` `plus` `plus_circle` `minus_circle` `info_circle` `exclamationmark_circle` `questionmark_circle`
79
+ - **常用操作**:`magnifyingglass` `trash` `gearshape` `envelope` `bell` `bell_fill` `heart` `heart_fill` `star` `star_fill` `bookmark` `bookmark_fill` `link` `paperplane` `paperplane_fill` `hand_thumbsup`
80
+ - **内容/时间**:`doc` `folder` `folder_fill` `calendar` `calendar_badge_plus` `clock` `camera` `camera_fill` `map` `flag` `bolt`
81
+ - **电商**:`cart` `cart_fill` `bag` `bag_fill` `gift` `gift_fill` `creditcard`
82
+ - **其它**:`wifi` `sun_max` `moon` `cloud`
83
+
84
+ ### 已验证【不存在】+ 替代方案(编译报 `Unknown resource name`)
85
+
86
+ | 猜测名称(不存在) | 替代 |
87
+ |---|---|
88
+ | `forward_fill` | **`forward_end_fill`**(前进/下一首;`forward_fill` 本身不存在) |
89
+ | `ellipsis` / `dot_3_horizontal` | `line_3_horizontal` |
90
+ | `square_and_arrow_up`(分享) | `paperplane` / `paperplane_fill` |
91
+ | `tray_arrow_down` | `envelope` |
92
+ | `chart_bar` | `square_grid_2x2` |
93
+ | `eye_fill` / `eye_slash_fill` | `eye` / `eye_slash`(无 `_fill` 后缀) |
94
+ | `location` / `location_fill` | `map`(无 `location` 裸名) |
95
+ | `photo` | `doc` / `square_grid_2x2` |
96
+ | `music_note` | `speaker_wave_2_fill` |
97
+ | `tag` / `doc_fill` / `person_circle` / `slider_horizontal_3` | 改用上方已验证名 |
98
+
99
+ ### 使用规范
100
+
101
+ ```typescript
102
+ // 标准用法
103
+ SymbolGlyph($r('sys.symbol.house'))
104
+ .fontSize(22)
105
+ .fontColor([Color.Black])
106
+
107
+ // 条件颜色(选中/未选中)
108
+ SymbolGlyph($r('sys.symbol.play_fill'))
109
+ .fontSize(20)
110
+ .fontColor(this.isActive ? [Color.Black] : ['#99182431'])
111
+ ```
112
+
113
+ **铁律**:
114
+ - 统一使用 `SymbolGlyph`;**绝不**把 Unicode emoji 或符号字(`♂` `♀` `✓` `★` 等)塞进 `Text` 当图标——那破坏视觉对齐、不是图标
115
+ - `fontColor` 参数是**数组**:`[Color.Black]` 不是 `Color.Black`
116
+ - **只用上方已验证清单里的名字**。图标不在清单时**按序回退**:① 清单里**语义最近的合法 symbol**(人物/性别→`person`/`person_fill`/`person_2`、搜索→`magnifyingglass`、分享→`paperplane`)→ ② 确需精确图形且工程自带矢量图才用 `Image` → ③ **绝不** emoji/Unicode 符号字,**绝不**凭猜发未验证 `sys.symbol.*`(编译必报 `Unknown resource name` 致整页失败;"先标 `[待验证]` 再发"挡不住)。
117
+ - ⚠️ 系统库**无**专用性别符号(`male`/`female`/`person_badge`/`figure_stand` probe 实证不存在)→ 性别男/女一律用通用 `person`/`person_2`(区分靠右侧文字标签),**别**回退 `Text('♂'/'♀')`。
118
+
119
+ ### `ohos_` 前缀命名空间(HarmonyOS 原生图标)
120
+
121
+ 除上面的裸名(源自 SF Symbols 命名体系)外,系统还预置一小撮 **`ohos_` 前缀**的鸿蒙原生图标。编译验证存在的有:`ohos_wifi` `ohos_lock` `ohos_trash` `ohos_star` `ohos_photo` `ohos_mic`。某些图标两种形并存(如 `wifi` 与 `ohos_wifi` 都可用)。**绝大多数常见动作没有 ohos_ 形**(`ohos_add`/`ohos_delete`/`ohos_settings`/`ohos_share`/`ohos_search`… 全部**不存在**,仍用裸名)。规则同上:**只用编译验证过的 `ohos_` 名**,不要凭猜造 `ohos_xxx`。遇到鸿蒙系统设置类页面的原生图标(WiFi/锁/相册等)可优先考虑对应 `ohos_` 名。
122
+
123
+ ---
124
+
125
+ ## 颜色系统映射
126
+
127
+ | Material 语义 | HarmonyOS 色值 | 用途 |
128
+ |-------------|---------------|------|
129
+ | primaryColor | `#007DFF` | 品牌蓝、主操作按钮 |
130
+ | surface | `#FAFAFA` | 卡片/面板背景 |
131
+ | background | `#FFFFFF` | 页面背景 |
132
+ | onSurface | `#182431` | 深色主文字 |
133
+ | onSurfaceVariant | `#99182431` | 次要文字(60% 不透明度) |
134
+ | divider | `#E0E0E0` | 分割线 |
135
+ | error | `#E84026` | 错误提示 |
136
+ | disabled | `#66182431` | 禁用态文字 |
137
+ | overlay | `#1A000000` | 蒙层/阴影(10% 黑) |
138
+ | pillBg | `#1F000000` | 药丸指示器背景(12% 黑) |
139
+
140
+ ### 系统颜色资源
141
+
142
+ ```typescript
143
+ // 推荐使用系统语义色(随深色模式自动切换)
144
+ $r('sys.color.ohos_id_color_text_primary') // 主文字
145
+ $r('sys.color.ohos_id_color_text_secondary') // 次要文字
146
+ $r('sys.color.ohos_id_color_background') // 背景色
147
+ ```
148
+
149
+ ---
150
+
151
+ ## 间距系统
152
+
153
+ 采用 **4vp 基数**,保持视觉一致性:
154
+
155
+ | 级别 | 值 | 用途 |
156
+ |------|---|------|
157
+ | xs | 4vp | 紧凑间距 |
158
+ | sm | 8vp | 列表项内间距 |
159
+ | md | 12vp | 组件间距 |
160
+ | lg | 16vp | 区域间距、标准 padding |
161
+ | xl | 20vp | 大区域间距 |
162
+ | xxl | 24vp | 页面边距 |
163
+
164
+ ```typescript
165
+ // 示例
166
+ Row() { ... }
167
+ .padding({ left: 16, right: 16, top: 8, bottom: 8 })
168
+ .margin({ top: 12 })
169
+ ```
170
+
171
+ ---
172
+
173
+ ## Tab 栏方案
174
+
175
+ > **先分清两种 Tab,别一刀切**:下面"别把 `Tabs` 放进 `Navigation`"的告诫**只针对底部主导航 + Navigation 路由**这一种场景。**顶部分段切换(Android `TabLayout` + `ViewPager2`,不在 Navigation 内)应直接用原生 `Tabs`**,不要手搓 `Row` 页签 + `Swiper` 同步(那是回避、还原度差):
176
+ >
177
+ > ```typescript
178
+ > Tabs({ barPosition: BarPosition.Start, index: this.idx }) {
179
+ > TabContent() { FirstPage() }.tabBar('推荐')
180
+ > TabContent() { SecondPage() }.tabBar('关注')
181
+ > }
182
+ > .onChange((i: number) => { this.idx = i }) // 点击/滑动双向同步由 Tabs 自带,无需自管手势
183
+ > ```
184
+ >
185
+ > 顶部三段式/中部分类 Tab = `Tabs({barPosition: BarPosition.Start}) + TabContent().tabBar(...)`;横向滚动多 Tab 加 `.barMode(BarMode.Scrollable)`。
186
+
187
+ ### Tabs 与 Navigation 的层次:照源码,不预设
188
+
189
+ `Tabs` 放在 `Navigation` 内部时,`NavDestination` 子页面会覆盖整个区域(包括 Tab 栏)——这正是安卓多数应用
190
+ (Activity 压栈 / NavHost 覆盖 BottomNavigationView)的既有行为,**默认就这么做**,Tab 页仍是 route_map 注册的
191
+ NavDestination(见 flow/navigation-migration.md,Index 壳冻结、页面只经 AppRouter 到达)。
192
+ 只有源码里子页面**保留底栏可见**(BottomNavigationView 在 Activity 根布局、NavHost 只占内容区,子页在同一 NavHost 内)
193
+ 时,才把自定义 Tab 栏放到 Navigation 外部,且外部 Tab 页也必须是注册页(Tab 切换 = 替换到对应路由),不能写成
194
+ `if (index === …)` 的未注册分支。
195
+
196
+ ### 源码保留底栏时的写法:自定义 Tab 栏放在 Navigation 外部
197
+
198
+ ```typescript
199
+ Column() {
200
+ // 内容区(Navigation 占满剩余空间)
201
+ Navigation(this.navPathStack) {
202
+ // Tab 内容根据 currentTabIndex 切换
203
+ if (this.currentTabIndex === 0) { HomeComponent() }
204
+ else if (this.currentTabIndex === 1) { QueueComponent() }
205
+ // ...
206
+ }
207
+ .navDestination(this.routerMap)
208
+ .mode(NavigationMode.Stack)
209
+ .layoutWeight(1)
210
+
211
+ // MiniPlayer(Navigation 外部,不被覆盖)
212
+ if (this.isPlayerVisible && !this.isFullPlayerVisible) {
213
+ MiniPlayerArea()
214
+ }
215
+
216
+ // 自定义 Tab 栏(Navigation 外部,不被覆盖)
217
+ if (!this.isFullPlayerVisible) {
218
+ CustomTabBar()
219
+ }
220
+ }
221
+ ```
222
+
223
+ ---
224
+
225
+ ## 药丸指示器 Tab 样式
226
+
227
+ Material 3 风格的底部 Tab 栏(药丸形背景指示选中态):
228
+
229
+ ```typescript
230
+ @Builder
231
+ tabBarItem(index: number, title: Resource, icon: Resource) {
232
+ Column() {
233
+ // 药丸形背景
234
+ Column() {
235
+ SymbolGlyph(icon)
236
+ .fontSize(22)
237
+ .fontColor(this.currentTabIndex === index ?
238
+ [Color.Black] : ['#99182431'])
239
+ }
240
+ .width(48)
241
+ .height(28)
242
+ .borderRadius(14)
243
+ .backgroundColor(this.currentTabIndex === index ?
244
+ '#1F000000' : '#00000000')
245
+ .justifyContent(FlexAlign.Center)
246
+
247
+ Text(title)
248
+ .fontSize(10)
249
+ .fontColor(this.currentTabIndex === index ?
250
+ '#182431' : '#99182431')
251
+ .margin({ top: 2 })
252
+ }
253
+ .layoutWeight(1)
254
+ .justifyContent(FlexAlign.Center)
255
+ .height('100%')
256
+ .onClick(() => { this.currentTabIndex = index; })
257
+ }
258
+ ```
259
+
260
+ > 完整代码见 `references/visual-patterns.md`
261
+
262
+ ---
263
+
264
+ ## 封面图 + Fallback 模式
265
+
266
+ 网络图片 + 文字首字母占位符:
267
+
268
+ ```typescript
269
+ if (this.coverUrl.length > 0) {
270
+ Image(this.coverUrl)
271
+ .width(40).height(40)
272
+ .borderRadius(6)
273
+ .objectFit(ImageFit.Cover)
274
+ } else {
275
+ Column() {
276
+ Text(this.title.length > 0 ?
277
+ this.title.charAt(0).toUpperCase() : '?')
278
+ .fontSize(18)
279
+ .fontWeight(FontWeight.Bold)
280
+ .fontColor(Color.White)
281
+ }
282
+ .width(40).height(40)
283
+ .borderRadius(6)
284
+ .backgroundColor('#BDBDBD')
285
+ .justifyContent(FlexAlign.Center)
286
+ }
287
+ ```
288
+
289
+ ---
290
+
291
+ ## 常见错误
292
+
293
+ ### 1. Emoji vs SymbolGlyph 混用
294
+ ```typescript
295
+ // ❌ emoji 大小不可控
296
+ Text('📋').fontSize(22) // 实际渲染大小不确定
297
+
298
+ // ✓ SymbolGlyph 大小精确可控
299
+ SymbolGlyph($r('sys.symbol.list_bullet'))
300
+ .fontSize(22)
301
+ .fontColor([Color.Black])
302
+ ```
303
+
304
+ ### 2. 使用不存在的 symbol 名称
305
+ ```typescript
306
+ // ❌ 编译报 Unknown resource name
307
+ SymbolGlyph($r('sys.symbol.tray_arrow_down'))
308
+
309
+ // ✓ 使用已验证的名称或查阅清单
310
+ SymbolGlyph($r('sys.symbol.envelope'))
311
+ ```
312
+
313
+ ### 3. Tabs 与 Navigation 的层次
314
+ ```typescript
315
+ // 默认(源码子页覆盖底栏):Tabs 在 Navigation 内,子页 NavDestination 覆盖整区 —— 与安卓一致,不是缺陷
316
+ Navigation() {
317
+ Tabs() { ... }
318
+ }
319
+
320
+ // 仅当源码子页保留底栏可见:Tab 栏放在 Navigation 外部,Tab 页仍走注册路由
321
+ Column() {
322
+ Navigation() { ... }.layoutWeight(1)
323
+ CustomTabBar() // 始终可见
324
+ }
325
+ ```
326
+
327
+ ---
328
+
329
+ ## 生成检查清单
330
+
331
+ - [ ] Android 组件已查对照表找到 ArkTS 等价物
332
+ - [ ] 图标统一使用 SymbolGlyph(不使用 emoji)
333
+ - [ ] Symbol 名称来自已验证清单
334
+ - [ ] 颜色/间距按源码 1:1(本文色值表与 4vp 基数只在源码没给值时兜底)
335
+ - [ ] Tabs 层次照源码:子页覆盖底栏用默认形态;源码保留底栏才把 Tab 栏放 Navigation 外
336
+ - [ ] 封面图有 fallback 占位
337
+
338
+ ---
339
+
340
+ ## References
341
+
342
+ - `references/layout-mapping.md` — Android→ArkTS 组件映射详细版 + 代码示例 + 单位转换
343
+ - `references/visual-patterns.md` — 药丸 Tab 栏 + 封面 fallback + MiniPlayer + SymbolGlyph + 阴影卡片
344
+ - `references/dark-mode.md` — 深色模式适配(双资源目录/媒体深浅版本)
@@ -0,0 +1,47 @@
1
+ # 深浅色适配(dark-mode)
2
+
3
+ > ⚠ 本文样例中 `getContext(this)` 为已废弃写法:组件内一律改 `this.getUIContext().getHostContext()`;Ability 内用 `this.context`。
4
+
5
+
6
+ > 支持深浅色的工程必读;conventions §E 的"状态栏/自绘不自动切换"两条的细则出处。
7
+
8
+ ## 1. 心智模型
9
+
10
+ - ColorMode 三值(`ConfigurationConstant.ColorMode`):`NOT_SET(-1)`=跟随系统(默认)、`DARK(0)`、`LIGHT(1)`。应用固定一种用 `getApplicationContext().setColorMode(...)`;一旦应用主动设过,系统切换不再覆盖本应用。读当前值:`getContext(this).config.colorMode`(多窗口下每个 UI 实例各自感知,别依赖全局单例)。
11
+ - 第一原则**不写具体颜色值**,引用语义 token:文字 `$r('sys.color.font_primary|font_secondary|…')`、图标 `icon_primary|icon_on_primary`、背景 `comp_background_primary|comp_divider`、交互态 `interactive_hover|interactive_click`。业务自定义色放 `base/element/color.json` + `dark/element/color.json` 同名覆写,引用 `$r('app.color.xxx')`。
12
+ - `$r()` 的刷新机制:框架保留 resource 引用、切主题时重新解析。属性透传链路必须保留 `Resource` 类型——中途解成 `Color` 数值再传 = 首次正确、切换后不刷新。
13
+
14
+ ## 2. 资源限定词目录
15
+
16
+ ```
17
+ resources/base/element/color.json # 浅色基线
18
+ resources/dark/element/color.json # 深色覆写(同 name 覆盖)
19
+ resources/dark/media/icon.svg # 深色图标覆写
20
+ resources/2in1-dark/element/… # 2in1 深色(不是 2in1/)
21
+ ```
22
+
23
+ 反模式:`icon_dark.svg`/`icon_night.png` 文件名后缀区分主题——绕过限定词匹配,深色下不命中。
24
+ HSP/HAR 每个模块须独立提供自己的 `src/main/resources/dark/`,主包 dark/ 覆盖不到模块内部资源("HSP 深色失效、主包正常"先查这条)。
25
+
26
+ ## 3. 框架不自动处理的三处
27
+
28
+ 1. **状态栏/导航栏前景色**:不随页面 ColorMode 自动变。主题变化回调里显式调 `window.setWindowSystemBarProperties({ statusBarContentColor, navigationBarContentColor })`。
29
+ 2. **Canvas/Web/XComponent 自绘内容**:订阅 `mediaquery.matchMediaSync('(dark-mode: true)')` 的 change 事件(或组件 `onColorModeChange` 回调)触发重绘。
30
+ 3. **Menu/Popup 等浮层**:`MenuOptions.colorMode` 未显式设置时可能与宿主不一致。
31
+
32
+ ## 4. 症状 → 优先怀疑
33
+
34
+ | 现象 | 优先怀疑 |
35
+ |---|---|
36
+ | 按压/悬浮态两种模式一个样 | 硬编码 `'rgba(0,0,0,0.1)'` 类字面值 |
37
+ | 深色下整页仍浅色底 | 根布局 `.backgroundColor(Color.White)`/`'#FFFFFF'` |
38
+ | 图标深色下看不见 | Image 没设 `.fillColor($r('sys.color.icon_primary'))`;SVG 用 stroke 非 fill |
39
+ | 切主题不变、重进才对 | 透传丢 Resource 引用 / 自绘未订阅切换 |
40
+ | 想固定深色被系统切走 | 没走 `ApplicationContext.setColorMode` |
41
+ | 状态栏文字看不清 | 没调 `setWindowSystemBarProperties` |
42
+
43
+ 排查顺序:读 colorMode → 切主题验证(完全不刷新=丢引用/未订阅;刷新但色不对=缺 dark 副本/硬编码)→ Inspector 抓实际颜色值 → 查 dark/ 目录(含每个 HSP)。
44
+ grep 定位:`Color\.`、`'#[0-9A-Fa-f]{3,8}'`、`rgba?\(`、`*_dark.*` 文件名、`setWindowSystemBarProperties`。
45
+
46
+ ---
47
+ 蒸馏自 corpus/candidates/arkts-dark-mode,2026-09 吸收