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,331 @@
1
+ <!-- 原技能 arkts-system-capabilities,已吸收为 migrate-core 语料专题,不再单独注册 -->
2
+ > HarmonyOS 系统 API 使用指南。当用户需要使用 photoAccessHelper 媒体查询、abilityAccessCtrl 权限申请、fileIo 文件操作、后台任务(workScheduler/ContinuousTask)、沙箱路径、相册访问、文件读写、权限检查、前台服务等系统能力时,务必触发此 skill。即使只说"怎么获取相册图片""怎么申请权限"也应触发。AVPlayer 完整生命周期见本目录 avplayer-guide.md/video-playback.md;下载队列见 background-tasks.md。
3
+
4
+ # ArkTS System Capabilities — 系统能力指南
5
+
6
+ ## API 版本
7
+
8
+ 本 skill 基于 **API 12+**(HarmonyOS 5.0.0+)。系统 API 导入使用 `@kit.*` 格式:
9
+
10
+ - 媒体库:`import { photoAccessHelper } from '@kit.MediaLibraryKit'`
11
+ - 权限:`import { abilityAccessCtrl, Permissions } from '@kit.AbilityKit'`
12
+ - 文件:`import { fileIo } from '@kit.CoreFileKit'`
13
+ - 后台任务:`import { backgroundTaskManager } from '@kit.BackgroundTasksKit'`
14
+
15
+ 遇到版本兼容性或其他不确定的 ArkTS 知识点:grep 本机 SDK `.d.ts` 声明为准。
16
+
17
+ ---
18
+
19
+ ## 生成约定:本项目锁 ArkUI V2
20
+
21
+ **把系统能力调用包成页面时,组件壳一律用 V2 装饰器,绝不用 V1。**
22
+
23
+ - 页面:`@Entry @ComponentV2 struct`;状态用 `@Local`;入参用 `@Param`(可配 `@Once`);事件回调用 `@Event`;派生监听用 `@Monitor`。
24
+ - **禁用 V1**:`@Component` / `@State` / `@Prop` / `@Link` / `@Watch`。
25
+ - 系统能力 API(`startBackgroundRunning` / `picker.*` / `call.makeCall` / `systemShare` 等)**用法本身不变**——照常写在 V2 组件的 `onClick` / `aboutToAppear` 里,只是承载它的组件壳换成 V2。references 里的 API 片段直接放进下面的壳即可。
26
+
27
+ 极简 V2 壳(把任意系统能力片段放进 `onClick` 即可):
28
+
29
+ ```typescript
30
+ @Entry
31
+ @ComponentV2
32
+ struct Index {
33
+ @Local status: string = '';
34
+
35
+ build() {
36
+ Column() {
37
+ Button('调用系统能力')
38
+ .onClick(async () => {
39
+ // 这里放系统能力调用,如 picker.select() / call.makeCall(...) / startBackgroundRunning(...)
40
+ this.status = 'done';
41
+ })
42
+ Text(this.status)
43
+ }
44
+ }
45
+ }
46
+ ```
47
+
48
+ ---
49
+
50
+ ## 系统 API 分类索引
51
+
52
+ ```
53
+ 用户要做什么?
54
+
55
+ ├─ 访问相册/媒体库(图片、视频)
56
+ │ └─ photoAccessHelper(见 references/photo-access-helper.md)
57
+ │ · 查询媒体资源
58
+ │ · 获取文件 URI
59
+ │ · FetchResult 游标遍历
60
+
61
+ ├─ 申请/检查权限
62
+ │ └─ abilityAccessCtrl(见 references/permission-helper.md)
63
+ │ · 运行时权限请求
64
+ │ · 权限状态检查
65
+ │ · 权限拒绝处理
66
+
67
+ ├─ 文件读写
68
+ │ └─ fileIo from @kit.CoreFileKit(见 references/file-utils.md)
69
+ │ · 沙箱路径(context.filesDir / context.cacheDir)
70
+ │ · 文件读写操作
71
+ │ · 目录创建
72
+
73
+ ├─ 后台任务
74
+ │ └─ 见 references/background-tasks.md
75
+ │ · workScheduler(延迟任务)
76
+ │ · ContinuousTask(长时任务,如后台播放)
77
+ │ · AVSession(媒体会话,通知栏控制)
78
+
79
+ ├─ 媒体播放(AVPlayer/本地播放/后台播放)
80
+ │ └─ 参阅 references/avplayer-guide.md / video-playback.md
81
+ │ · AVPlayer 状态机
82
+ │ · fd:// 本地文件播放
83
+ │ · 后台播放三要素
84
+
85
+ ├─ 文件下载(大文件/进度/队列)
86
+ │ └─ 参阅 references/background-tasks.md(下载队列/长时任务)
87
+ │ · request.agent API
88
+ │ · 下载进度追踪
89
+ │ · 文件移动管线
90
+
91
+ └─ 拉起系统应用
92
+ ├─ 分享面板(隐式启动)→ references/share-panel.md
93
+ │ · @kit.ShareKit(ShareController / SharedData)
94
+ │ · UTD 类型转换、MIME 判断
95
+ │ · SharePreviewMode / SelectionMode 配置
96
+
97
+ ├─ 系统相机(隐式启动)→ references/camera-picker.md
98
+ │ · @kit.CameraKit(cameraPicker.pick)
99
+ │ · PickerMediaType(PHOTO / VIDEO)
100
+ │ · PickerResult 处理
101
+
102
+ ├─ 文件管理器(隐式启动)→ references/document-picker.md
103
+ │ · @kit.CoreFileKit(DocumentViewPicker)
104
+ │ · .select() 选择文件(对应 ACTION_OPEN_DOCUMENT)
105
+ │ · .save() 保存文件(对应 ACTION_CREATE_DOCUMENT)
106
+ │ · DocumentSelectOptions / DocumentSaveOptions 配置
107
+
108
+ ├─ 系统打印管理 → references/print-management.md
109
+ │ · @kit.BasicServicesKit(print.print)
110
+ │ · WebPrintDocumentAdapter(网页打印)
111
+ │ · PrintDocumentAdapter(自定义内容打印)
112
+
113
+ ├─ 浏览器/URL 跳转(隐式启动)→ references/browser-intent.md
114
+ │ · Want + startAbility
115
+ │ · action.viewData、mailto: 协议
116
+
117
+ ├─ 电话拨号 → references/telephony-dial.md
118
+ │ · @kit.TelephonyKit(call.makeCall)
119
+ │ · 拉起系统拨号界面,不走 Want/tel:
120
+
121
+ └─ 系统设置跳转(显式启动)→ references/system-settings.md
122
+ · Want + startAbility(显式指定 bundleName/abilityName)
123
+ · 华为系统设置页面跳转(com.huawei.settings)
124
+ · 权限设置、应用信息页面
125
+ ```
126
+
127
+ ---
128
+
129
+ ## 核心踩坑警示
130
+
131
+ ### 1. photoAccessHelper URI 不能给 Image 组件渲染视频
132
+
133
+ 视频类型的 URI 传给 `Image` 组件会显示灰色空白。视频项需用占位图。
134
+
135
+ ### 2. FetchResult 不是数组
136
+
137
+ `FetchResult` 是游标式迭代器,必须用 `getFirstObject()` + `getNextObject()` 遍历,最后 `close()`。
138
+
139
+ ### 3. 文件只能写沙箱路径
140
+
141
+ HarmonyOS 应用只能访问沙箱目录(`context.filesDir`、`context.cacheDir`),写入其他路径会 Permission denied。
142
+
143
+ ### 4. 后台播放需要三个条件
144
+
145
+ module.json5 声明 `backgroundModes` + 代码申请 `ContinuousTask` + `AVSession` 注册媒体会话。缺一不可。
146
+
147
+ ### 5. 权限请求是异步的
148
+
149
+ `requestPermissionsFromUser` 返回 Promise,必须 await。
150
+
151
+ ### 6. 分享面板 ShareController.show() 是异步的
152
+
153
+ `show()` 不会阻塞 UI,通过 `.then()`/.catch() 处理结果,不能 await。
154
+
155
+ ### 7. 拉起其他应用需要 module.json5 配置
156
+
157
+ **需要配置的场景**:
158
+ - 相机跳转:必须配置 `entity.system.camera` + `ohos.want.action.camera`
159
+ - 响应外部查看请求:需要配置 `ohos.want.action.view`(如相册响应其他应用查看图片)
160
+
161
+ **通常不需要配置的场景**:
162
+ - 浏览器跳转(`ohos.want.action.viewData`):系统内置支持
163
+ - 图片/视频分享:通常系统已内置支持(某些设备可能需要)
164
+ - 系统设置跳转(显式 Want):直接指定目标应用,无需声明
165
+
166
+ > 详细配置规则见各 references 文件中的 module.json5 配置章节。
167
+ > 系统设置跳转参考 `system-settings.md`
168
+
169
+ ---
170
+
171
+ ## AVPlayer 速查
172
+
173
+ AVPlayer 是 HarmonyOS 的核心媒体播放 API。状态机必须严格按顺序:
174
+
175
+ ```
176
+ Idle →(url=)→ Initialized →(prepare)→ Prepared →(play)→ Playing ↔ Paused
177
+ ```
178
+
179
+ **关键导入**:`import { media } from '@kit.MediaKit'`
180
+
181
+ **本地文件必须用 fd:// 协议**:
182
+ ```typescript
183
+ const file = fileIo.openSync(path, fileIo.OpenMode.READ_ONLY);
184
+ avPlayer.url = 'fd://' + file.fd.toString();
185
+ ```
186
+
187
+ > 完整生命周期、后台播放、倍速控制等详见 `avplayer-guide.md` 与 `video-playback.md`。
188
+
189
+ ---
190
+
191
+ ## 后台播放三要素检查清单
192
+
193
+ 后台持续播放需要三个条件同时满足,缺一不可:
194
+
195
+ - [ ] **module.json5**:abilities 中声明 `"backgroundModes": ["audioPlayback"]`
196
+ - [ ] **module.json5**:requestPermissions 中声明 `"ohos.permission.KEEP_BACKGROUND_RUNNING"`
197
+ - [ ] **代码**:调用 `backgroundTaskManager.startBackgroundRunning(context, BackgroundMode.AUDIO_PLAYBACK, wantAgent)`
198
+ - [ ] **代码**:创建 `avSession.createAVSession()` 并 `activate()`
199
+ - [ ] **代码**:创建 `wantAgent` 用于通知栏点击返回应用
200
+
201
+ ---
202
+
203
+ ## 权限配置三件套
204
+
205
+ 音频/网络应用常用权限组合(均为 system_grant,无需弹窗):
206
+
207
+ ```json5
208
+ "requestPermissions": [
209
+ { "name": "ohos.permission.INTERNET" },
210
+ { "name": "ohos.permission.GET_NETWORK_INFO" },
211
+ { "name": "ohos.permission.KEEP_BACKGROUND_RUNNING" }
212
+ ]
213
+ ```
214
+
215
+ ---
216
+
217
+ ## workScheduler 配置
218
+
219
+ 后台定时任务需要在 module.json5 中声明 extensionAbilities:
220
+
221
+ ```json5
222
+ "extensionAbilities": [{
223
+ "name": "FeedUpdateWorkAbility",
224
+ "srcEntry": "./ets/workers/FeedUpdateWorkAbility.ets",
225
+ "type": "workScheduler"
226
+ }]
227
+ ```
228
+
229
+ ---
230
+
231
+ ## fd:// 本地文件协议
232
+
233
+ AVPlayer 播放本地文件不能用 `file://`,必须用 `fd://`:
234
+
235
+ ```typescript
236
+ import { fileIo } from '@kit.CoreFileKit';
237
+ const file = fileIo.openSync(localPath, fileIo.OpenMode.READ_ONLY);
238
+ avPlayer.url = 'fd://' + file.fd.toString();
239
+ // 播放结束后统一关闭:fileIo.closeSync(file.fd);
240
+ ```
241
+
242
+ ---
243
+
244
+ ## 常见错误 vs 正确写法
245
+
246
+ ### 错误 1:直接用 for 循环遍历 FetchResult
247
+
248
+ ```typescript
249
+ // 错误 — FetchResult 不支持 for...of
250
+ for (const asset of fetchResult) { ... }
251
+
252
+ // 正确 — 使用 getFirstObject + getNextObject
253
+ let asset = await fetchResult.getFirstObject()
254
+ let i = 0
255
+ while (i < count) {
256
+ // 处理 asset
257
+ i++
258
+ if (i < count) asset = await fetchResult.getNextObject()
259
+ }
260
+ fetchResult.close()
261
+ ```
262
+
263
+ ### 错误 2:写文件到绝对路径
264
+
265
+ ```typescript
266
+ // 错误 — Permission denied
267
+ const path = '/storage/emulated/0/Download/file.txt'
268
+
269
+ // 正确 — 使用沙箱路径
270
+ const path = `${context.filesDir}/downloads/file.txt`
271
+ ```
272
+
273
+ ### 错误 3:忘记关闭 FetchResult
274
+
275
+ ```typescript
276
+ // 错误 — 资源泄漏
277
+ const result = await phAccessHelper.getAssets(options)
278
+ // 使用后没有 close
279
+
280
+ // 正确
281
+ const result = await phAccessHelper.getAssets(options)
282
+ try {
283
+ // 遍历处理...
284
+ } finally {
285
+ result.close()
286
+ }
287
+ ```
288
+
289
+ ---
290
+
291
+ ## 生成检查清单
292
+
293
+ - [ ] 页面/产物页用 V2 装饰器(`@Entry @ComponentV2` + `@Local`/`@Param`/`@Event`),无 V1 `@Component`/`@State`/`@Prop`/`@Link`/`@Watch`
294
+ - [ ] photoAccessHelper 的 FetchResult 在使用后调用了 close()
295
+ - [ ] 文件路径使用沙箱路径(context.filesDir / context.cacheDir)
296
+ - [ ] 需要的权限在 module.json5 中声明
297
+ - [ ] 运行时权限用 abilityAccessCtrl 动态请求
298
+ - [ ] 后台任务同时满足 module.json5 声明 + 代码申请
299
+ - [ ] 异步 API 正确使用 async/await
300
+ - [ ] 隐式启动(相机/分享/浏览器)已在 module.json5 的 skills 中声明 entities/actions
301
+
302
+ ---
303
+
304
+ ## 关联材料(包内)
305
+
306
+ | 需要什么 | 读取哪里 |
307
+ |---------|---------|
308
+ | 三方库替代方案 | `../library-migration/`(按 _SKILL 索引取件) |
309
+ | Android UI 对齐 | `../ui-alignment/README.md` |
310
+ | API 是否存在/版本兼容 | grep 本机 SDK `.d.ts` 声明为准 |
311
+
312
+ ---
313
+
314
+ ## References
315
+
316
+ - references/video-playback.md — 视频播放(XComponent/AVPlayer 表面绑定)
317
+ - references/webview-patterns.md — WebView 迁移形态
318
+
319
+ - `share-panel.md` — @kit.ShareKit 分享面板完整模板
320
+ - `camera-picker.md` — @kit.CameraKit 系统相机调用模板
321
+ - `document-picker.md` — @kit.CoreFileKit 文件管理器调用模板(DocumentViewPicker.select / .save)
322
+ - `print-management.md` — @kit.BasicServicesKit 系统打印管理模板(print.print / WebPrintDocumentAdapter)
323
+ - `browser-intent.md` — Want + startAbility 浏览器/URL 跳转模板
324
+ - `telephony-dial.md` — @kit.TelephonyKit 电话拨号(call.makeCall 拉起系统拨号界面)
325
+ - `system-settings.md` — Want + startAbility 系统设置跳转模板(显式 Want)
326
+ - `photo-access-helper.md` — 媒体查询/URI 获取/FetchResult 遍历完整模板
327
+ - `permission-helper.md` — abilityAccessCtrl 权限请求与检查
328
+ - `file-utils.md` — @kit.CoreFileKit 文件读写/沙箱路径
329
+ - `background-tasks.md` — workScheduler/ContinuousTask/AVSession 后台任务
330
+ - `avplayer-guide.md` — AVPlayer 完整生命周期 + stateChange 回调 + fd:// + Speed 枚举
331
+ - 遇到版本兼容性或其他不确定的 ArkTS 知识点:grep 本机 SDK `.d.ts` 声明为准
@@ -0,0 +1,161 @@
1
+ # AVPlayer 完整指南
2
+
3
+ > AVPlayer 生命周期、stateChange 回调、fd:// 协议、Speed 枚举、后台播放三要素。
4
+
5
+ ---
6
+
7
+ ## AVPlayer 状态机
8
+
9
+ ```
10
+ Idle →(url=)→ Initialized →(prepare)→ Prepared →(play)→ Playing ↔(pause/play)↔ Paused
11
+ ↓ completed
12
+ Stopped →(release)→ Released
13
+ Error: 任何状态出错 → reset() → release()
14
+ ```
15
+
16
+ ### 状态转换规则
17
+
18
+ | 当前状态 | 可执行操作 | 目标状态 |
19
+ |---------|----------|---------|
20
+ | Idle | 设置 `url` | Initialized |
21
+ | Initialized | `prepare()` | Prepared |
22
+ | Prepared | `play()`, `seek()`, `setSpeed()` | Playing |
23
+ | Playing | `pause()`, `seek()`, `stop()` | Paused/Stopped |
24
+ | Paused | `play()`, `seek()`, `stop()` | Playing/Stopped |
25
+ | Stopped | `release()` | Released |
26
+
27
+ ---
28
+
29
+ ## stateChange 回调模板
30
+
31
+ ```typescript
32
+ import { media } from '@kit.MediaKit';
33
+
34
+ player.on('stateChange', (state: string) => {
35
+ if (state === 'initialized') {
36
+ // URL 设置后触发 → 必须调用 prepare
37
+ player.prepare();
38
+ } else if (state === 'prepared') {
39
+ // prepare 完成 → 设置倍速/seek/play
40
+ player.setSpeed(media.PlaybackSpeed.SPEED_FORWARD_1_00_X);
41
+ if (savedPosition > 0) {
42
+ player.seek(savedPosition);
43
+ }
44
+ player.play();
45
+ } else if (state === 'playing') {
46
+ // 播放中 → 更新 UI 状态
47
+ AppStorage.setOrCreate<boolean>('isPlaying', true);
48
+ } else if (state === 'paused') {
49
+ AppStorage.setOrCreate<boolean>('isPlaying', false);
50
+ } else if (state === 'completed') {
51
+ // 播放完成 → 自动切歌或停止
52
+ } else if (state === 'error') {
53
+ player.reset();
54
+ player.release();
55
+ }
56
+ });
57
+
58
+ player.on('timeUpdate', (time: number) => {
59
+ AppStorage.setOrCreate<number>('playbackPosition', time);
60
+ });
61
+
62
+ player.on('seekDone', (seekPos: number) => {
63
+ AppStorage.setOrCreate<number>('playbackPosition', seekPos);
64
+ });
65
+
66
+ player.on('error', () => {
67
+ // 错误处理
68
+ });
69
+ ```
70
+
71
+ ---
72
+
73
+ ## fd:// 本地文件播放
74
+
75
+ ```typescript
76
+ import { fileIo } from '@kit.CoreFileKit';
77
+
78
+ // 打开文件
79
+ const file = fileIo.openSync(localPath, fileIo.OpenMode.READ_ONLY);
80
+ const fd = file.fd;
81
+ avPlayer.url = 'fd://' + fd.toString();
82
+
83
+ // 停止时关闭
84
+ if (this.localFileFd >= 0) {
85
+ try { fileIo.closeSync(this.localFileFd); } catch (e) {}
86
+ this.localFileFd = -1;
87
+ }
88
+ ```
89
+
90
+ ---
91
+
92
+ ## Speed 枚举映射
93
+
94
+ ```typescript
95
+ private snapToValidSpeed(speed: number): number {
96
+ const validSpeeds: number[] = [0.75, 1.0, 1.25, 1.5, 1.75, 2.0];
97
+ let closest = validSpeeds[0];
98
+ let minDiff = Math.abs(speed - closest);
99
+ for (let i = 1; i < validSpeeds.length; i++) {
100
+ const diff = Math.abs(speed - validSpeeds[i]);
101
+ if (diff < minDiff) { minDiff = diff; closest = validSpeeds[i]; }
102
+ }
103
+ return closest;
104
+ }
105
+
106
+ private mapToPlaybackSpeed(speed: number): media.PlaybackSpeed {
107
+ if (speed <= 0.75) return media.PlaybackSpeed.SPEED_FORWARD_0_75_X;
108
+ else if (speed <= 1.0) return media.PlaybackSpeed.SPEED_FORWARD_1_00_X;
109
+ else if (speed <= 1.25) return media.PlaybackSpeed.SPEED_FORWARD_1_25_X;
110
+ else if (speed <= 1.5) return media.PlaybackSpeed.SPEED_FORWARD_1_50_X;
111
+ else if (speed <= 1.75) return media.PlaybackSpeed.SPEED_FORWARD_1_75_X;
112
+ return media.PlaybackSpeed.SPEED_FORWARD_2_00_X;
113
+ }
114
+ ```
115
+
116
+ ---
117
+
118
+ ## 后台播放三要素
119
+
120
+ ```typescript
121
+ import { backgroundTaskManager } from '@kit.BackgroundTasksKit';
122
+ import { wantAgent } from '@kit.AbilityKit';
123
+ import { avSession } from '@kit.AVSessionKit';
124
+
125
+ // 1. WantAgent
126
+ const info: wantAgent.WantAgentInfo = {
127
+ wants: [{ bundleName: 'com.example.app', abilityName: 'EntryAbility' }],
128
+ actionType: wantAgent.OperationType.START_ABILITY,
129
+ requestCode: 0,
130
+ actionFlags: [wantAgent.WantAgentFlags.UPDATE_PRESENT_FLAG]
131
+ };
132
+ const agent = await wantAgent.getWantAgent(info);
133
+
134
+ // 2. 长时任务
135
+ await backgroundTaskManager.startBackgroundRunning(
136
+ context, backgroundTaskManager.BackgroundMode.AUDIO_PLAYBACK, agent);
137
+
138
+ // 3. AVSession
139
+ const session = await avSession.createAVSession(context, 'AppName', 'audio');
140
+ await session.activate();
141
+ session.on('play', () => { /* play */ });
142
+ session.on('pause', () => { /* pause */ });
143
+ session.on('seek', (time: number) => { /* seek */ });
144
+ session.on('playNext', () => { /* next */ });
145
+ session.on('playPrevious', () => { /* prev */ });
146
+
147
+ // 更新元数据
148
+ await session.setAVMetadata({ assetId: '0', title: 'Title', artist: 'Artist', duration: 300000 });
149
+
150
+ // 更新播放状态
151
+ await session.setAVPlaybackState({
152
+ state: avSession.PlaybackState.PLAYBACK_STATE_PLAY,
153
+ position: { elapsedTime: posMs, updateTime: Date.now() }
154
+ });
155
+
156
+ // 停止
157
+ session.off('play'); session.off('pause');
158
+ await session.deactivate();
159
+ await session.destroy();
160
+ await backgroundTaskManager.stopBackgroundRunning(context);
161
+ ```