@ohos-cpf/3rdloop 0.0.8 → 0.0.9

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 (219) hide show
  1. package/README.md +25 -0
  2. package/lib/cli.js +22 -5
  3. package/lib/doctor.js +111 -10
  4. package/lib/mcp.js +498 -0
  5. package/package.json +6 -2
  6. package/vendor/Archive/data/.index/meta.json +7 -0
  7. package/vendor/Archive/data/.index/search.db +0 -0
  8. package/vendor/Archive/data/docs/experiences/arkts-check-tool-pitfalls-baseline-comparison.md +13 -0
  9. package/vendor/Archive/data/docs/experiences/arkts-deep-path-import-recognition.md +31 -0
  10. package/vendor/Archive/data/docs/experiences/arkts-demo-coverage-entry-file-case-mismatch.md +25 -0
  11. package/vendor/Archive/data/docs/experiences/arkts-demo-coverage-import-trailing-slash.md +20 -0
  12. package/vendor/Archive/data/docs/experiences/arkts-library-source-files-may-be-ts.md +18 -0
  13. package/vendor/Archive/data/docs/experiences/arkts-typedarray-buffer-interface-cast-compile-fixes.md +36 -0
  14. package/vendor/Archive/data/docs/experiences/arkts-xts-compile-error-clustering-fix.md +24 -0
  15. package/vendor/Archive/data/docs/experiences/arkts-xts-doc-expected-value-runtime-probe.md +35 -0
  16. package/vendor/Archive/data/docs/experiences/arkts-xts-fixture-rawfile-testability-injection.md +33 -0
  17. package/vendor/Archive/data/docs/experiences/code-linter-chinese-comment-false-positive.md +16 -0
  18. package/vendor/Archive/data/docs/experiences/esobject-new-expression-variable-tracking.md +33 -0
  19. package/vendor/Archive/data/docs/experiences/filesystem-case-sensitivity-module-resolution.md +31 -0
  20. package/vendor/Archive/data/docs/experiences/gitcode-clone-redirect-warning-normal.md +13 -0
  21. package/vendor/Archive/data/docs/experiences/kn_msgvq1w585ec8319.md +77 -0
  22. package/vendor/Archive/data/docs/experiences/kn_msovnm6rd46de72c.md +98 -0
  23. package/vendor/Archive/data/docs/experiences/kn_mspt8vntfe708576.md +87 -0
  24. package/vendor/Archive/data/docs/experiences/kn_mspu1ei77adbbb48.md +133 -0
  25. package/vendor/Archive/data/docs/experiences/kn_mspubgak8d30bfce.md +128 -0
  26. package/vendor/Archive/data/docs/experiences/kn_mspug2de3cb1f7c3.md +115 -0
  27. package/vendor/Archive/data/docs/experiences/kn_skill_opt_001.md +38 -0
  28. package/vendor/Archive/data/docs/experiences/loop-artifacts-verification-evidence-triangle.md +19 -0
  29. package/vendor/Archive/data/docs/experiences/macos-bash-replace-build-ps1.md +19 -0
  30. package/vendor/Archive/data/docs/experiences/macos-bsd-diff-q-illegal-option.md +15 -0
  31. package/vendor/Archive/data/docs/experiences/migrate-cjs-compatible-api-version-map-limit.md +17 -0
  32. package/vendor/Archive/data/docs/experiences/mp3agic-arkts-library-behavior-quirks.md +21 -0
  33. package/vendor/Archive/data/docs/experiences/ohos-face-detection-scan-api-mapping.md +15 -0
  34. package/vendor/Archive/data/docs/experiences/pr-metadata-and-diff-integrity-verification.md +12 -0
  35. package/vendor/Archive/data/docs/experiences/rn-coverage-index-signature-pseudo-member-false-negative.md +32 -0
  36. package/vendor/Archive/data/docs/experiences/rn-memory-check-severity-calibration.md +21 -0
  37. package/vendor/Archive/data/docs/experiences/rn-platform-specific-api-exclusion-evidence.md +24 -0
  38. package/vendor/Archive/data/docs/experiences/rn-upstream-version-diff-pitfalls.md +17 -0
  39. package/vendor/Archive/data/docs/experiences/rn-version-gap-risk-rating-rules.md +13 -0
  40. package/vendor/Archive/data/docs/experiences/rn-view-lib-native-contract-diff-fabric-spec.md +16 -0
  41. package/vendor/Archive/data/docs/experiences/rnoh-adapter-package-version-field-semantics.md +18 -0
  42. package/vendor/Archive/data/docs/experiences/rnoh-arkts-sqlite-rows-array-format.md +18 -0
  43. package/vendor/Archive/data/docs/experiences/rnoh-dependency-residue-scan-strategy.md +18 -0
  44. package/vendor/Archive/data/docs/experiences/rnoh-example-local-lib-dep-use-tgz.md +53 -0
  45. package/vendor/Archive/data/docs/experiences/rnoh-example-prereserve-rntesterlist.md +17 -0
  46. package/vendor/Archive/data/docs/experiences/rnoh-example-template-compatiblesdkversion-upgrade.md +29 -0
  47. package/vendor/Archive/data/docs/experiences/rnoh-example-turbomodule-shell-adaptation-checklist.md +41 -0
  48. package/vendor/Archive/data/docs/experiences/rnoh-mcp-build-project-tool-risk.md +18 -0
  49. package/vendor/Archive/data/docs/experiences/rnoh-npm-devdependencies-version-precheck.md +29 -0
  50. package/vendor/Archive/data/docs/experiences/rnoh-repo-baseline-version-verification.md +13 -0
  51. package/vendor/Archive/data/docs/experiences/rnoh-repo-upstream-directory-mapping.md +18 -0
  52. package/vendor/Archive/data/docs/experiences/rnoh-stateless-library-zero-leak-verification.md +31 -0
  53. package/vendor/Archive/data/docs/experiences/rnoh-template-npmrc-credential-removal.md +15 -0
  54. package/vendor/Archive/data/docs/experiences/rnoh-turbomodule-codegen-wiring-verification.md +19 -0
  55. package/vendor/Archive/data/docs/experiences/rnoh-turbomodule-cpp-methodmap-compatibility-check.md +20 -0
  56. package/vendor/Archive/data/docs/experiences/scenario-doc-vs-source-signature-diff-four-patterns.md +24 -0
  57. package/vendor/Archive/data/docs/experiences/static-analysis-grep-cross-validation.md +29 -0
  58. package/vendor/Archive/demo.js +489 -0
  59. package/vendor/Archive/index.js +43 -0
  60. package/vendor/Archive/package.json +16 -0
  61. package/vendor/Archive/src/constants.js +83 -0
  62. package/vendor/Archive/src/data/stopwords.txt +110 -0
  63. package/vendor/Archive/src/data/synonyms.json +25 -0
  64. package/vendor/Archive/src/data/terms.txt +59 -0
  65. package/vendor/Archive/src/db/sqlite-backend.js +312 -0
  66. package/vendor/Archive/src/db/sqlite-schema.js +64 -0
  67. package/vendor/Archive/src/engine.js +501 -0
  68. package/vendor/Archive/src/index/index-manager.js +203 -0
  69. package/vendor/Archive/src/index/index-state.js +94 -0
  70. package/vendor/Archive/src/index/search-text-builder.js +106 -0
  71. package/vendor/Archive/src/index.js +22 -0
  72. package/vendor/Archive/src/parser/api-identifiers.js +121 -0
  73. package/vendor/Archive/src/parser/api-suffixes.js +48 -0
  74. package/vendor/Archive/src/parser/heading-normalize.js +40 -0
  75. package/vendor/Archive/src/parser/markdown-splitter.js +215 -0
  76. package/vendor/Archive/src/search/catalog-routing.js +87 -0
  77. package/vendor/Archive/src/search/fts-search.js +289 -0
  78. package/vendor/Archive/src/search/query-normalizer.js +159 -0
  79. package/vendor/Archive/src/search/query-rewriter.js +72 -0
  80. package/vendor/Archive/src/search/search-engine.js +72 -0
  81. package/vendor/Archive/src/search/snippet.js +64 -0
  82. package/vendor/Archive/src/store/dir-store.js +103 -0
  83. package/vendor/Archive/src/store/doc-store.js +36 -0
  84. package/vendor/Archive/src/tokenizer/lexicon.js +151 -0
  85. package/vendor/Archive/src/tokenizer/tokenizer.js +167 -0
  86. package/vendor/Archive/src/types.js +86 -0
  87. package/vendor/Archive/src/utils/hash.js +16 -0
  88. package/vendor/Archive/src/utils/lock.js +73 -0
  89. package/vendor/Archive/src/utils/path-safety.js +96 -0
  90. package/vendor/Archive/src/utils/paths.js +39 -0
  91. package/vendor/BadCase/rn/INDEX.md +127 -0
  92. package/vendor/BadCase/rn/cases/KI-001-webview/350/247/206/351/242/221/346/227/240/346/263/225/346/250/252/345/261/217.md +52 -0
  93. package/vendor/BadCase/rn/cases/KI-002-fastImage/347/203/255/346/233/264/346/226/260/345/233/276/347/211/207/345/244/261/350/264/245.md +37 -0
  94. package/vendor/BadCase/rn/cases/KI-003-wechat/347/274/251/347/225/245/345/233/276/346/234/254/345/234/260/345/233/276/347/211/207.md +62 -0
  95. package/vendor/BadCase/rn/cases/KI-004-wechat/345/233/236/350/260/203/346/227/266/345/272/217.md +47 -0
  96. package/vendor/BadCase/rn/cases/KI-005-geolocation/345/257/274/345/205/245/350/267/257/345/276/204/345/220/216/347/274/200.md +31 -0
  97. package/vendor/BadCase/rn/cases/KI-006-SmartRefreshLayout/346/231/272/350/203/275/346/214/207/351/222/210/345/264/251/346/272/203.md +55 -0
  98. package/vendor/BadCase/rn/cases/KI-007-orientation-locker/344/274/240/346/204/237/345/231/250/345/210/235/345/247/213/345/214/226.md +58 -0
  99. package/vendor/BadCase/rn/cases/KI-008-orientation-locker/344/274/240/346/204/237/345/231/250/345/274/225/347/224/250/350/256/241/346/225/260.md +47 -0
  100. package/vendor/BadCase/rn/cases/KI-009-pager-view/345/265/214/345/245/227/346/273/221/345/212/250.md +38 -0
  101. package/vendor/BadCase/rn/cases/KI-010-screens/346/211/213/345/212/277/345/206/262/347/252/201.md +48 -0
  102. package/vendor/BadCase/rn/cases/KI-011-spring-scrollview/346/211/213/345/212/277/351/207/215/345/244/215/347/273/221/345/256/232.md +49 -0
  103. package/vendor/BadCase/rn/cases/KI-012-qr-camera/346/250/252/345/261/217/351/200/202/351/205/215.md +59 -0
  104. package/vendor/BadCase/rn/cases/KI-013-webview/346/267/261/350/211/262/346/250/241/345/274/217/350/203/214/346/231/257/350/211/262.md +37 -0
  105. package/vendor/BadCase/rn/cases/KI-014-amap-geolocation/345/233/236/350/260/203/347/274/272/345/244/261.md +42 -0
  106. package/vendor/BadCase/rn/cases/KI-015-reanimated/350/277/220/350/241/214/346/227/266/346/236/220/346/236/204/345/264/251/346/272/203.md +54 -0
  107. package/vendor/BadCase/rn/cases/KI-016-fs/346/226/207/344/273/266/350/257/273/345/217/226/347/274/226/347/240/201.md +58 -0
  108. package/vendor/BadCase/rn/cases/KI-017-blob-util/345/217/202/346/225/260/347/274/226/347/240/201/351/224/231/350/257/257.md +39 -0
  109. package/vendor/BadCase/rn/cases/KI-018-modal/345/274/271/347/252/227/351/227/252/347/203/201.md +53 -0
  110. package/vendor/BadCase/rn/cases/KI-019-code-push/351/207/215/345/220/257/351/200/273/350/276/221/345/244/261/346/225/210.md +79 -0
  111. package/vendor/BadCase/rn/cases/KI-020-netinfo/346/225/217/346/204/237/344/277/241/346/201/257/346/263/204/351/234/262.md +60 -0
  112. package/vendor/BadCase/rn/cases/KI-021-video/346/234/254/345/234/260/350/247/206/351/242/221/346/222/255/346/224/276/345/274/202/345/270/270.md +79 -0
  113. package/vendor/BadCase/rn/cases/KI-022-audio-recorder-player/346/236/232/344/270/276/347/274/272/345/244/261.md +38 -0
  114. package/vendor/BadCase/rn/cases/KI-023-svg/346/270/220/345/217/230/347/273/247/346/211/277/345/244/261/346/225/210.md +62 -0
  115. package/vendor/BadCase/rn/generalization-log.md +55 -0
  116. package/vendor/BadCase/rn/pr-info/rntpc_react-native-SmartRefreshLayout-32.json +328 -0
  117. package/vendor/BadCase/rn/pr-info/rntpc_react-native-SmartRefreshLayout-32.md +382 -0
  118. package/vendor/BadCase/rn/pr-info/rntpc_react-native-amap-geolocation-27.json +1351 -0
  119. package/vendor/BadCase/rn/pr-info/rntpc_react-native-amap-geolocation-27.md +1176 -0
  120. package/vendor/BadCase/rn/pr-info/rntpc_react-native-audio-recorder-player-22.json +538 -0
  121. package/vendor/BadCase/rn/pr-info/rntpc_react-native-audio-recorder-player-22.md +1488 -0
  122. package/vendor/BadCase/rn/pr-info/rntpc_react-native-blob-util-23.json +211 -0
  123. package/vendor/BadCase/rn/pr-info/rntpc_react-native-blob-util-23.md +35 -0
  124. package/vendor/BadCase/rn/pr-info/rntpc_react-native-code-push-17.json +2048 -0
  125. package/vendor/BadCase/rn/pr-info/rntpc_react-native-code-push-17.md +3866 -0
  126. package/vendor/BadCase/rn/pr-info/rntpc_react-native-fast-image-102.json +198 -0
  127. package/vendor/BadCase/rn/pr-info/rntpc_react-native-fast-image-102.md +40 -0
  128. package/vendor/BadCase/rn/pr-info/rntpc_react-native-fs-38.json +751 -0
  129. package/vendor/BadCase/rn/pr-info/rntpc_react-native-fs-38.md +883 -0
  130. package/vendor/BadCase/rn/pr-info/rntpc_react-native-geolocation-24.json +1544 -0
  131. package/vendor/BadCase/rn/pr-info/rntpc_react-native-geolocation-24.md +2598 -0
  132. package/vendor/BadCase/rn/pr-info/rntpc_react-native-modal-20.json +246 -0
  133. package/vendor/BadCase/rn/pr-info/rntpc_react-native-modal-20.md +554 -0
  134. package/vendor/BadCase/rn/pr-info/rntpc_react-native-netinfo-31.json +211 -0
  135. package/vendor/BadCase/rn/pr-info/rntpc_react-native-netinfo-31.md +54 -0
  136. package/vendor/BadCase/rn/pr-info/rntpc_react-native-orientation-locker-45.json +1626 -0
  137. package/vendor/BadCase/rn/pr-info/rntpc_react-native-orientation-locker-45.md +2213 -0
  138. package/vendor/BadCase/rn/pr-info/rntpc_react-native-orientation-locker-51.json +208 -0
  139. package/vendor/BadCase/rn/pr-info/rntpc_react-native-orientation-locker-51.md +77 -0
  140. package/vendor/BadCase/rn/pr-info/rntpc_react-native-pager-view-32.json +377 -0
  141. package/vendor/BadCase/rn/pr-info/rntpc_react-native-pager-view-32.md +174 -0
  142. package/vendor/BadCase/rn/pr-info/rntpc_react-native-qr-decode-image-camera-37.json +232 -0
  143. package/vendor/BadCase/rn/pr-info/rntpc_react-native-qr-decode-image-camera-37.md +194 -0
  144. package/vendor/BadCase/rn/pr-info/rntpc_react-native-reanimated-82.json +198 -0
  145. package/vendor/BadCase/rn/pr-info/rntpc_react-native-reanimated-82.md +67 -0
  146. package/vendor/BadCase/rn/pr-info/rntpc_react-native-screens-87.json +198 -0
  147. package/vendor/BadCase/rn/pr-info/rntpc_react-native-screens-87.md +38 -0
  148. package/vendor/BadCase/rn/pr-info/rntpc_react-native-screens-93.json +208 -0
  149. package/vendor/BadCase/rn/pr-info/rntpc_react-native-screens-93.md +34 -0
  150. package/vendor/BadCase/rn/pr-info/rntpc_react-native-spring-scrollview-38.json +222 -0
  151. package/vendor/BadCase/rn/pr-info/rntpc_react-native-spring-scrollview-38.md +56 -0
  152. package/vendor/BadCase/rn/pr-info/rntpc_react-native-svg-117.json +463 -0
  153. package/vendor/BadCase/rn/pr-info/rntpc_react-native-svg-117.md +383 -0
  154. package/vendor/BadCase/rn/pr-info/rntpc_react-native-video-66.json +464 -0
  155. package/vendor/BadCase/rn/pr-info/rntpc_react-native-video-66.md +565 -0
  156. package/vendor/BadCase/rn/pr-info/rntpc_react-native-webview-112.json +198 -0
  157. package/vendor/BadCase/rn/pr-info/rntpc_react-native-webview-112.md +47 -0
  158. package/vendor/BadCase/rn/pr-info/rntpc_react-native-webview-121.json +232 -0
  159. package/vendor/BadCase/rn/pr-info/rntpc_react-native-webview-121.md +422 -0
  160. package/vendor/BadCase/rn/pr-info/rntpc_react-native-wechat-lib-15.json +295 -0
  161. package/vendor/BadCase/rn/pr-info/rntpc_react-native-wechat-lib-15.md +1038 -0
  162. package/vendor/BadCase/rn/rules/R-01-/345/205/250/345/261/217/347/252/227/345/217/243/347/212/266/346/200/201/347/256/241/347/220/206/345/256/214/346/225/264/346/200/247.md +20 -0
  163. package/vendor/BadCase/rn/rules/R-02-/350/265/204/346/272/220URI/345/275/242/346/200/201/345/210/206/346/224/257/350/246/206/347/233/226.md +21 -0
  164. package/vendor/BadCase/rn/rules/R-03-/351/231/204/345/261/236/346/223/215/344/275/234/345/244/261/350/264/245/351/230/273/346/226/255/344/270/273/346/265/201/347/250/213.md +20 -0
  165. package/vendor/BadCase/rn/rules/R-04-/345/274/202/346/255/245/345/233/236/350/260/203/346/263/250/345/206/214/346/227/266/345/272/217.md +20 -0
  166. package/vendor/BadCase/rn/rules/R-05-/346/250/241/345/235/227/345/257/274/345/205/245/350/267/257/345/276/204/350/247/204/350/214/203.md +19 -0
  167. package/vendor/BadCase/rn/rules/R-06-/344/274/240/346/204/237/345/231/250/347/241/254/344/273/266/346/235/203/351/231/220/346/214/211/351/234/200/350/216/267/345/217/226.md +21 -0
  168. package/vendor/BadCase/rn/rules/R-07-/346/231/272/350/203/275/346/214/207/351/222/210/347/224/237/345/221/275/345/221/250/346/234/237/347/256/241/347/220/206.md +20 -0
  169. package/vendor/BadCase/rn/rules/R-08-/346/211/213/345/212/277/344/272/213/344/273/266/346/263/250/345/206/214/344/270/216/345/206/262/347/252/201/345/244/204/347/220/206.md +22 -0
  170. package/vendor/BadCase/rn/rules/R-09-/346/250/252/347/253/226/345/261/217/345/244/232/345/275/242/346/200/201/345/270/203/345/261/200/351/200/202/351/205/215.md +20 -0
  171. package/vendor/BadCase/rn/rules/R-10-/346/267/261/350/211/262/346/250/241/345/274/217/344/270/273/351/242/230/351/242/234/350/211/262/351/200/202/351/205/215.md +19 -0
  172. package/vendor/BadCase/rn/rules/R-11-/346/216/245/345/217/243/345/233/236/350/260/203/345/256/236/347/216/260/345/256/214/346/225/264/346/200/247.md +20 -0
  173. package/vendor/BadCase/rn/rules/R-12-/345/216/237/347/224/237/350/277/220/350/241/214/346/227/266/350/265/204/346/272/220/346/236/220/346/236/204/346/227/266/345/272/217.md +20 -0
  174. package/vendor/BadCase/rn/rules/R-13-/346/226/207/344/273/266/346/225/260/346/215/256/347/274/226/347/240/201/344/270/216/346/240/274/345/274/217/345/205/274/345/256/271.md +21 -0
  175. package/vendor/BadCase/rn/rules/R-14-/345/212/250/347/224/273/345/210/235/345/247/213/345/214/226/346/227/266/345/272/217/344/270/216/347/212/266/346/200/201/345/220/214/346/255/245.md +20 -0
  176. package/vendor/BadCase/rn/rules/R-15-/347/212/266/346/200/201/346/214/201/344/271/205/345/214/226/344/270/216/351/207/215/345/220/257/351/200/273/350/276/221/344/270/200/350/207/264/346/200/247.md +20 -0
  177. package/vendor/BadCase/rn/rules/R-16-/346/225/217/346/204/237/344/277/241/346/201/257/346/227/245/345/277/227/346/263/204/351/234/262.md +19 -0
  178. package/vendor/BadCase/rn/rules/R-17-/345/252/222/344/275/223/350/265/204/346/272/220/347/224/237/345/221/275/345/221/250/346/234/237/344/270/216/351/224/231/350/257/257/345/244/204/347/220/206.md +21 -0
  179. package/vendor/BadCase/rn/rules/R-18-/350/203/275/345/212/233/346/236/232/344/270/276/351/205/215/347/275/256/345/256/214/346/225/264/346/200/247.md +19 -0
  180. package/vendor/BadCase/rn/rules/R-19-/345/233/276/345/275/242/346/270/262/346/237/223/345/261/236/346/200/247/347/273/247/346/211/277/344/270/216/351/207/215/347/275/256.md +19 -0
  181. package/vendor/MCP/README.md +490 -0
  182. package/vendor/MCP/config.json +29 -0
  183. package/vendor/MCP/package.json +23 -0
  184. package/vendor/MCP/scripts/analyze-demo-coverage.cjs +1203 -0
  185. package/vendor/MCP/scripts/analyze-xts-coverage.cjs +1245 -0
  186. package/vendor/MCP/scripts/deveco_docs.js +247 -0
  187. package/vendor/MCP/scripts/extract-interfaces.cjs +1487 -0
  188. package/vendor/MCP/scripts/flutter-analyze-demo-coverage.cjs +666 -0
  189. package/vendor/MCP/scripts/flutter-analyze-xts-coverage.cjs +684 -0
  190. package/vendor/MCP/scripts/flutter-extract-interfaces.cjs +1251 -0
  191. package/vendor/MCP/scripts/flutter-render-spec-doc.cjs +351 -0
  192. package/vendor/MCP/scripts/render-spec-doc.cjs +347 -0
  193. package/vendor/MCP/scripts/rn-analyze-demo-coverage.cjs +645 -0
  194. package/vendor/MCP/scripts/rn-analyze-test-coverage.cjs +614 -0
  195. package/vendor/MCP/scripts/rn-extract-interfaces.cjs +1462 -0
  196. package/vendor/MCP/scripts/rn-render-spec-doc.cjs +327 -0
  197. package/vendor/MCP/scripts/rn-scan-exports.cjs +1336 -0
  198. package/vendor/MCP/src/client/MCPClientPool.js +220 -0
  199. package/vendor/MCP/src/config/ConfigLoader.js +189 -0
  200. package/vendor/MCP/src/executor/ScriptExecutor.js +110 -0
  201. package/vendor/MCP/src/gateway/Gateway.js +451 -0
  202. package/vendor/MCP/src/index.js +87 -0
  203. package/vendor/MCP/src/library/KBToolProvider.js +229 -0
  204. package/vendor/MCP/src/library/logger.js +60 -0
  205. package/vendor/MCP/src/registry/ScriptRegistry.js +238 -0
  206. package/vendor/MCP/src/registry/ToolRegistry.js +111 -0
  207. package/vendor/MCP/src/types.js +115 -0
  208. package/vendor/Server/Skills/arkts-library-test-coverage-check/references/MCP_TOOL_USAGE.md +4 -2
  209. package/vendor/Server/Skills/arkts-library-xts-coverage/SKILL.md +3 -3
  210. package/vendor/Server/Skills/knowledge-import/SKILL.md +1 -1
  211. package/vendor/Server/Skills/knowledge-import/references/MCP_TOOL_USAGE.md +12 -4
  212. package/vendor/Server/Skills/ohos-lib-pr-push/SKILL.md +5 -4
  213. package/vendor/Server/Skills/rn-library-issue-generalizer/SKILL.md +2 -2
  214. package/vendor/Server/Skills/rn-library-known-issue-check/SKILL.md +2 -2
  215. package/vendor/Server/Skills/rnoh-lib-demo-coverage/SKILL.md +1 -2
  216. package/vendor/Server/Skills/rnoh-lib-test-align/references/port-test-demo-guide.md +1 -1
  217. package/vendor/Server/Skills/rnoh-lib-xts-coverage/SKILL.md +1 -2
  218. package/vendor/Server/package.json +5 -1
  219. package/vendor/VERSION +3 -3
@@ -0,0 +1,565 @@
1
+ # PR #66: fix:修复播放本地视频异常问题
2
+
3
+ - **状态**: merged
4
+ - **作者**: qq_434633291111
5
+ - **创建时间**: 2026-06-22T16:27:55+08:00
6
+ - **分支**: br_rnoh0.72 → br_rnoh0.72
7
+ - **变更文件数**: 12
8
+
9
+ ## PR 描述
10
+
11
+ fix:修复播放本地视频异常问题
12
+
13
+ ## 变更文件
14
+
15
+ | 文件 | 变更 | +行 | -行 |
16
+ |------|------|-----|-----|
17
+ | `examples/harmony/build-profile.json5` | ? | +2 | -22 |
18
+ | `examples/harmony/entry/oh-package-lock.json5` | deleted | +0 | -29 |
19
+ | `examples/harmony/entry/oh-package.json5` | ? | +1 | -1 |
20
+ | `examples/harmony/entry/src/main/cpp/CMakeLists.txt` | ? | +1 | -1 |
21
+ | `examples/harmony/entry/src/main/ets/RNPackagesFactory.ets` | ? | +1 | -1 |
22
+ | `examples/harmony/entry/src/main/ets/pages/Index.ets` | ? | +1 | -1 |
23
+ | `examples/harmony/hvigor/hvigor-config.json5` | ? | +1 | -1 |
24
+ | `examples/harmony/oh-package-lock.json5` | deleted | +0 | -28 |
25
+ | `examples/harmony/oh-package.json5` | ? | +1 | -1 |
26
+ | `examples/package.json` | ? | +3 | -2 |
27
+ | `harmony/rn_video/src/main/ets/controller/VideoController.ets` | ? | +28 | -13 |
28
+ | `harmony/rn_video/src/main/ets/view/PlayPlayer.ets` | ? | +127 | -25 |
29
+
30
+ ## Diff
31
+
32
+ ### `examples/harmony/build-profile.json5`
33
+
34
+ ```diff
35
+ @@ -1,33 +1,13 @@
36
+ {
37
+ "app": {
38
+ "signingConfigs": [
39
+ - {
40
+ - "name": "default",
41
+ - "type": "HarmonyOS",
42
+ - "material": {
43
+ - "certpath": "",
44
+ - "keyAlias": "debugKey",
45
+ - "keyPassword": "",
46
+ - "profile": "",
47
+ - "signAlg": "SHA256withECDSA",
48
+ - "storeFile": "",
49
+ - "storePassword": ""
50
+ - }
51
+ - }
52
+ ],
53
+ "products": [
54
+ {
55
+ "name": "default",
56
+ "signingConfig": "default",
57
+ - "targetSdkVersion": "5.1.1(19)",
58
+ - "compatibleSdkVersion": "5.0.1(13)",
59
+ - "runtimeOS": "HarmonyOS",
60
+ - "buildOption": {
61
+ - "strictMode": {
62
+ - "caseSensitiveCheck": true,
63
+ - "useNormalizedOHMUrl": true
64
+ - }
65
+ - }
66
+ + "compatibleSdkVersion": "5.0.0(12)",
67
+ + "runtimeOS": "HarmonyOS"
68
+ }
69
+ ],
70
+ "buildModeSet": [
71
+
72
+ ```
73
+
74
+ ### `examples/harmony/entry/oh-package-lock.json5`
75
+
76
+ ```diff
77
+ @@ -1,29 +0,0 @@
78
+ -{
79
+ - "meta": {
80
+ - "stableOrder": true,
81
+ - "enableUnifiedLockfile": false
82
+ - },
83
+ - "lockfileVersion": 3,
84
+ - "ATTENTION": "THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.",
85
+ - "specifiers": {
86
+ - "@react-native-oh-tpl/react-native-video@../../../harmony/rn_video": "@react-native-oh-tpl/react-native-video@../../../harmony/rn_video",
87
+ - "@rnoh/react-native-openharmony@../../node_modules/@react-native-oh/react-native-harmony/react_native_openharmony.har": "@rnoh/react-native-openharmony@../../node_modules/@react-native-oh/react-native-harmony/react_native_openharmony.har"
88
+ - },
89
+ - "packages": {
90
+ - "@react-native-oh-tpl/react-native-video@../../../harmony/rn_video": {
91
+ - "name": "@react-native-oh-tpl/react-native-video",
92
+ - "version": "5.2.3-rc.4",
93
+ - "resolved": "../../../harmony/rn_video",
94
+ - "registryType": "local",
95
+ - "dependencies": {
96
+ - "@rnoh/react-native-openharmony": "file:../react_native_openharmony.har"
97
+ - }
98
+ - },
99
+ - "@rnoh/react-native-openharmony@../../node_modules/@react-native-oh/react-native-harmony/react_native_openharmony.har": {
100
+ - "name": "@rnoh/react-native-openharmony",
101
+ - "version": "0.72.80",
102
+ - "resolved": "../../node_modules/@react-native-oh/react-native-harmony/react_native_openharmony.har",
103
+ - "registryType": "local"
104
+ - }
105
+ - }
106
+ -}
107
+
108
+
109
+ ```
110
+
111
+ ### `examples/harmony/entry/oh-package.json5`
112
+
113
+ ```diff
114
+ @@ -7,7 +7,7 @@
115
+ "license": "",
116
+ "dependencies": {
117
+ '@rnoh/react-native-openharmony': 'file:../../node_modules/@react-native-oh/react-native-harmony/react_native_openharmony.har',
118
+ - '@react-native-oh-tpl/react-native-video': '../../../harmony/rn_video'
119
+ + '@react-native-ohos/react-native-video': '../../../harmony/rn_video'
120
+ }
121
+ }
122
+
123
+
124
+ ```
125
+
126
+ ### `examples/harmony/entry/src/main/cpp/CMakeLists.txt`
127
+
128
+ ```diff
129
+ @@ -12,7 +12,7 @@ add_compile_definitions(WITH_HITRACE_SYSTRACE)
130
+ set(WITH_HITRACE_SYSTRACE 1) # for other CMakeLists.txt files to use
131
+
132
+ add_subdirectory("${RNOH_CPP_DIR}" ./rn)
133
+ -add_subdirectory("${OH_MODULE_DIR}/@react-native-oh-tpl/react-native-video/src/main/cpp" ./video)
134
+ +add_subdirectory("${OH_MODULE_DIR}/@react-native-ohos/react-native-video/src/main/cpp" ./video)
135
+
136
+ add_library(rnoh_app SHARED
137
+ "./PackageProvider.cpp"
138
+
139
+ ```
140
+
141
+ ### `examples/harmony/entry/src/main/ets/RNPackagesFactory.ets`
142
+
143
+ ```diff
144
+ @@ -1,5 +1,5 @@
145
+ import { RNPackageContext, RNPackage } from '@rnoh/react-native-openharmony/ts';
146
+ -import { RNCVideoPackage } from '@react-native-oh-tpl/react-native-video/ts';
147
+ +import { RNCVideoPackage } from '@react-native-ohos/react-native-video/ts';
148
+
149
+ export function createRNPackages(ctx: RNPackageContext): RNPackage[] {
150
+ return [
151
+
152
+ ```
153
+
154
+ ### `examples/harmony/entry/src/main/ets/pages/Index.ets`
155
+
156
+ ```diff
157
+ @@ -11,7 +11,7 @@ import {
158
+ RNOHCoreContext
159
+ } from '@rnoh/react-native-openharmony';
160
+ import { createRNPackages } from '../RNPackagesFactory';
161
+ -import { RNCVideo, RNC_VIDEO_TYPE } from "@react-native-oh-tpl/react-native-video"
162
+ +import { RNCVideo, RNC_VIDEO_TYPE } from "@react-native-ohos/react-native-video"
163
+
164
+ const arkTsComponentNames: Array<string> = [RNC_VIDEO_TYPE];
165
+
166
+
167
+ ```
168
+
169
+ ### `examples/harmony/hvigor/hvigor-config.json5`
170
+
171
+ ```diff
172
+ @@ -1,5 +1,5 @@
173
+ {
174
+ - "modelVersion": "5.1.1",
175
+ + "modelVersion": "5.0.0",
176
+ "dependencies": {
177
+ },
178
+ "execution": {
179
+
180
+ ```
181
+
182
+ ### `examples/harmony/oh-package-lock.json5`
183
+
184
+ ```diff
185
+ @@ -1,28 +0,0 @@
186
+ -{
187
+ - "meta": {
188
+ - "stableOrder": true,
189
+ - "enableUnifiedLockfile": false
190
+ - },
191
+ - "lockfileVersion": 3,
192
+ - "ATTENTION": "THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.",
193
+ - "specifiers": {
194
+ - "@ohos/hamock@1.0.0": "@ohos/hamock@1.0.0",
195
+ - "@ohos/hypium@1.0.21": "@ohos/hypium@1.0.21"
196
+ - },
197
+ - "packages": {
198
+ - "@ohos/hamock@1.0.0": {
199
+ - "name": "@ohos/hamock",
200
+ - "version": "1.0.0",
201
+ - "integrity": "sha512-K6lDPYc6VkKe6ZBNQa9aoG+ZZMiwqfcR/7yAVFSUGIuOAhPvCJAo9+t1fZnpe0dBRBPxj2bxPPbKh69VuyAtDg==",
202
+ - "resolved": "https://ohpm.openharmony.cn/ohpm/@ohos/hamock/-/hamock-1.0.0.har",
203
+ - "registryType": "ohpm"
204
+ - },
205
+ - "@ohos/hypium@1.0.21": {
206
+ - "name": "@ohos/hypium",
207
+ - "version": "1.0.21",
208
+ - "integrity": "sha512-iyKGMXxE+9PpCkqEwu0VykN/7hNpb+QOeIuHwkmZnxOpI+dFZt6yhPB7k89EgV1MiSK/ieV/hMjr5Z2mWwRfMQ==",
209
+ - "resolved": "https://ohpm.openharmony.cn/ohpm/@ohos/hypium/-/hypium-1.0.21.har",
210
+ - "registryType": "ohpm"
211
+ - }
212
+ - }
213
+ -}
214
+
215
+
216
+ ```
217
+
218
+ ### `examples/harmony/oh-package.json5`
219
+
220
+ ```diff
221
+ @@ -1,5 +1,5 @@
222
+ {
223
+ - "modelVersion": "5.1.1",
224
+ + "modelVersion": "5.0.0",
225
+ "description": "Please describe the basic information.",
226
+ "dependencies": {
227
+ },
228
+
229
+ ```
230
+
231
+ ### `examples/package.json`
232
+
233
+ ```diff
234
+ @@ -8,10 +8,11 @@
235
+ "start": "react-native start",
236
+ "test": "jest",
237
+ "dev": "react-native bundle-harmony --dev",
238
+ - "install:video": "cd ../ && npm pack && cd ./examples && npm i file:../react-native-ohos-react-native-video-6.13.2-rc.3.tgz"
239
+ + "install:video": "cd ../ && npm i --legacy-peer-deps && npm i typescript --legacy-peer-deps && npm pack && cd ./examples && npm i --legacy-peer-deps",
240
+ + "fast:pkg": "npm run install:video && npm run dev"
241
+ },
242
+ "dependencies": {
243
+ - "@react-native-ohos/react-native-video": "file:../react-native-ohos-react-native-video-6.13.2-rc.3.tgz",
244
+ + "@react-native-ohos/react-native-video": "file:../react-native-ohos-react-native-video-6.13.4.tgz",
245
+ "@react-native-oh/react-native-harmony": "^0.72.80",
246
+ "react": "18.2.0",
247
+ "react-native": "0.72.5"
248
+
249
+ ```
250
+
251
+ ### `harmony/rn_video/src/main/ets/controller/VideoController.ets`
252
+
253
+ ```diff
254
+ @@ -111,9 +111,9 @@ export class VideoController {
255
+ Logger.info(TAG, `createAVPlayer after bind`);
256
+ if (this.flagtd) {
257
+ this.flagtd = false;
258
+ - if (typeof this.url === "string") {
259
+ + if (typeof this.url === "string" && this.url.length > 0) {
260
+ this.avPlayer.url = this.url;
261
+ - } else {
262
+ + } else if (typeof this.url === "object") {
263
+ this.avPlayer.fdSrc = this.url;
264
+ }
265
+ Logger.error(TAG, `createAVPlayer need toplay url,after bind:` + this.url);
266
+ @@ -274,14 +274,19 @@ export class VideoController {
267
+ this.avPlayer.on(Events.STATE_CHANGE, async (state) => {
268
+ switch (state) {
269
+ case AvplayerStatus.IDLE:
270
+ - if (typeof this.url === "string") {
271
+ + // 只有在 url 有效时才设置源,避免在 reset 后立即设置无效源
272
+ + if (typeof this.url === "string" && this.url.length > 0) {
273
+ this.avPlayer.url = this.url;
274
+ - } else {
275
+ + } else if (typeof this.url === "object") {
276
+ this.avPlayer.fdSrc = this.url;
277
+ }
278
+ this.playPageThis.onVideoIdle();
279
+ break;
280
+ case AvplayerStatus.INITIALIZED:
281
+ + // AVPlayer 已成功加载新源,旧 fd 不再被使用,可以安全关闭
282
+ + if (this.playerThis && typeof this.playerThis.closeOldFd === 'function') {
283
+ + this.playerThis.closeOldFd();
284
+ + }
285
+ if (this.playerThis.disableFocus) {
286
+ await this.setAudioRendererInfo(audio.AudioConcurrencyMode.CONCURRENCY_MIX_WITH_OTHERS);
287
+ } else {
288
+ @@ -384,15 +389,17 @@ export class VideoController {
289
+ * @param surfaceId Indicates the surface ID of the surfaceId.
290
+ */
291
+ firstPlay(index: number, url: string | media.AVFileDescriptor, surfaceId: number): void {
292
+ - Logger.info(TAG, `firstPlay, url ${url}`);
293
+ + Logger.info(TAG, `firstPlay, url type: ${typeof url}, state: ${this.avPlayer?.state}`);
294
+ this.index = index;
295
+ this.url = url;
296
+ this._surfaceId = surfaceId;
297
+ if (this.avPlayer && this.avPlayer.state == AvplayerStatus.IDLE) {
298
+ - if (typeof this.url === "string") {
299
+ + if (typeof this.url === "string" && this.url.length > 0) {
300
+ this.avPlayer.url = this.url;
301
+ - } else {
302
+ + } else if (typeof this.url === "object") {
303
+ this.avPlayer.fdSrc = this.url;
304
+ + } else {
305
+ + Logger.error(TAG, `firstPlay, invalid url: ${this.url}`);
306
+ }
307
+ } else {
308
+ this.flagtd = true;
309
+ @@ -456,27 +463,35 @@ export class VideoController {
310
+ * @return
311
+ */
312
+ switchVideo(newUrl: string | media.AVFileDescriptor): void {
313
+ - Logger.info(TAG, `switchVideo, newUrl ${newUrl}`);
314
+ - this.bindState();
315
+ + Logger.info(TAG, `switchVideo, newUrl type: ${typeof newUrl}, state: ${this.avPlayer?.state}`);
316
+ + // 注意:不要在这里调用 bindState(),否则会重复注册事件监听器
317
+ + // 导致 onStateChange 被多次触发,在非 IDLE 状态时重复设置 url/fdSrc 引发 5400102 错误
318
+ this.url = newUrl;
319
+ if (this._surfaceId == 0 || this._surfaceId == undefined) {
320
+ - // Logger.info(TAG, `switchVideo, return`);
321
+ + return;
322
+ + }
323
+ + if (!this.avPlayer) {
324
+ + Logger.info(TAG, `switchVideo, avPlayer not ready, setting flagtd`);
325
+ + this.flagtd = true;
326
+ return;
327
+ }
328
+ if (AvplayerStatus.IDLE == this.avPlayer.state) {
329
+ - // Logger.info(TAG, `switchVideo, IDLE `);
330
+ + Logger.info(TAG, `switchVideo, IDLE state, setting source`);
331
+ if (typeof this.url === "string") {
332
+ this.avPlayer.url = this.url;
333
+ } else {
334
+ this.avPlayer.fdSrc = this.url;
335
+ }
336
+ } else {
337
+ + Logger.info(TAG, `switchVideo, non-IDLE state: ${this.avPlayer.state}, stopping...`);
338
+ this.avPlayer.stop().then(
339
+ ()=>{
340
+ - Logger.info(TAG, `switchVideo, reset`);
341
+ + Logger.info(TAG, `switchVideo, stopped, resetting`);
342
+ this.avPlayer.reset();
343
+ }
344
+ - )
345
+ + ).catch((err: BusinessError) => {
346
+ + Logger.error(TAG, `switchVideo, stop error: ${err.code} ${err.message}`);
347
+ + })
348
+ }
349
+
350
+ Logger.info(TAG, `switchVideo, state ${JSON.stringify(this.avPlayer.state)}`);
351
+
352
+ ```
353
+
354
+ ### `harmony/rn_video/src/main/ets/view/PlayPlayer.ets`
355
+
356
+ ```diff
357
+ @@ -52,6 +52,7 @@ export interface IPlayPlayer {
358
+ videoJustifyContent: FlexAlign
359
+ videoAlignItems: HorizontalAlign
360
+ matrix: Matrix4.Matrix4Transit
361
+ + closeOldFd: () => void
362
+ }
363
+
364
+ const TAG: string = 'RNPlayPlayer'
365
+ @@ -109,6 +110,7 @@ export struct PlayPlayer {
366
+ xComponentController: XComponentController = new XComponentController();
367
+ private surfaceID: number = 0;
368
+ private previousSrc: fs.File | string | undefined = undefined
369
+ + private pendingCloseSrc: fs.File | string | undefined = undefined
370
+ private orientationChange: boolean = true;
371
+ private isProgressSliding: boolean = false
372
+ private sliderTimer: number = 0
373
+ @@ -191,31 +193,46 @@ export struct PlayPlayer {
374
+ }
375
+
376
+ closeFsRawFd() {
377
+ - if (typeof this.previousSrc === "string") {
378
+ - getContext(this).resourceManager.closeRawFd(this.previousSrc, (error: BusinessError) => {
379
+ - if (error != null) {
380
+ - Logger.debug(TAG, `aboutToDisappear, closeRawFd error is${error.message} error code:${error.code}`);
381
+ - } else {
382
+ - Logger.debug(TAG, `aboutToDisappear, closeRawFd file succeed`);
383
+ + // 关闭旧的文件资源
384
+ + try {
385
+ + if (typeof this.previousSrc === "string") {
386
+ + // rawfile 路径 - 关闭 rawfile fd
387
+ + getContext(this).resourceManager.closeRawFdSync(this.previousSrc);
388
+ + Logger.debug(TAG, `closeFsRawFd, closeRawFd succeed for: ${this.previousSrc}`);
389
+ + } else if (typeof this.previousSrc === "object") {
390
+ + // fs.File 对象 - 关闭文件
391
+ + fs.closeSync(this.previousSrc);
392
+ + Logger.debug(TAG, `closeFsRawFd, close file succeed`);
393
+ + }
394
+ + // undefined = 使用临时文件方式,无需关闭 rawfile fd
395
+ + } catch (err) {
396
+ + Logger.error(TAG, `closeFsRawFd error: ${JSON.stringify(err)}`);
397
+ + }
398
+ + this.previousSrc = undefined;
399
+ + // 同时关闭待关闭的旧 fd
400
+ + if (this.pendingCloseSrc !== undefined) {
401
+ + try {
402
+ + if (typeof this.pendingCloseSrc === "string") {
403
+ + getContext(this).resourceManager.closeRawFdSync(this.pendingCloseSrc);
404
+ + } else if (typeof this.pendingCloseSrc === "object") {
405
+ + fs.closeSync(this.pendingCloseSrc);
406
+ }
407
+ - });
408
+ - } else if (typeof this.previousSrc === "object") {
409
+ - fs.close(this.previousSrc, (err: BusinessError) => {
410
+ - if (err) {
411
+ - Logger.debug(TAG,
412
+ - `aboutToDisappear, close file failed with error message:${err.message},error code:${err.code}`);
413
+ - } else {
414
+ - Logger.debug(TAG, `aboutToDisappear, close file succeed`);
415
+ - }
416
+ - });
417
+ + } catch (err) {
418
+ + Logger.error(TAG, `closeFsRawFd pendingCloseSrc error: ${JSON.stringify(err)}`);
419
+ + }
420
+ + this.pendingCloseSrc = undefined;
421
+ }
422
+ }
423
+
424
+ aboutToDisappear(): void {
425
+ if (this.playVideoModel) {
426
+ - this.playVideoModel.release()
427
+ - this.closeFsRawFd()
428
+ + try {
429
+ + this.playVideoModel.release()
430
+ + } catch (err) {
431
+ + Logger.error(TAG, `aboutToDisappear release error: ${JSON.stringify(err)}`);
432
+ + }
433
+ }
434
+ + this.closeFsRawFd()
435
+ }
436
+
437
+ // @Watch cb
438
+ @@ -226,33 +243,118 @@ export struct PlayPlayer {
439
+ }
440
+
441
+ async preparePlayer(): Promise<string | media.AVFileDescriptor> {
442
+ - this.closeFsRawFd()
443
+ return new Promise(async (resolve, reject) => {
444
+ try {
445
+ let src: string | media.AVFileDescriptor = '';
446
+ if (this.srcParam.startsWith('http')) {
447
+ this.type = CommonConstants.TYPE_INTERNET
448
+ src = this.srcParam
449
+ + this.pendingCloseSrc = this.previousSrc
450
+ this.previousSrc = undefined
451
+ } else if (this.srcParam.startsWith('asset')) {
452
+ const fileUrl = this.srcParam.split('//')[1];
453
+ - let fileDescriptor = await getContext(this).resourceManager.getRawFd(`assets/${fileUrl}`);
454
+ - this.previousSrc = `assets/${fileUrl}`
455
+ - src = fileDescriptor;
456
+ + const rawFilePath = `assets/${fileUrl}`;
457
+ + Logger.debug(TAG, `asset source, rawFilePath: ${rawFilePath}`);
458
+ + // fix:修复播放本地视频异常问题
459
+ + // 方案:将 rawfile 复制到应用沙箱临时目录,再用 file:// URI 播放
460
+ + // 原因:getRawFd 返回的 AVFileDescriptor 中 offset != 0(rawfile 在 HAP 包内有偏移),
461
+ + // AVPlayer 的 fdSrc 对 offset!=0 的支持在某些 HarmonyOS 版本上有 bug,
462
+ + // 会报 5400106 (Unsupported Format: CONTAINER_ERR-null-unsupport container format type)
463
+ + const context = getContext(this);
464
+ + const cacheDir = context.cacheDir;
465
+ + // 使用 rawfile 完整路径生成唯一缓存文件名,避免不同路径的同名文件冲突
466
+ + const cacheFileName = rawFilePath.replace(/\//g, '_');
467
+ + const destPath = `${cacheDir}/${cacheFileName}`;
468
+ + let needCopy = true;
469
+ + try {
470
+ + const stat = fs.statSync(destPath);
471
+ + const rawFdInfo = await context.resourceManager.getRawFd(rawFilePath);
472
+ + if (stat.size === rawFdInfo.length) {
473
+ + needCopy = false;
474
+ + Logger.debug(TAG, `cache hit: ${destPath}, size=${stat.size}`);
475
+ + context.resourceManager.closeRawFdSync(rawFilePath);
476
+ + } else {
477
+ + Logger.debug(TAG, `cache size mismatch: local=${stat.size}, rawfile=${rawFdInfo.length}`);
478
+ + context.resourceManager.closeRawFdSync(rawFilePath);
479
+ + }
480
+ + } catch (e) {
481
+ + Logger.error(TAG, `Error cache miss: ${destPath}`);
482
+ + }
483
+ + if (needCopy) {
484
+ + // 将 rawfile 内容读取后写入临时文件
485
+ + try {
486
+ + const content: Uint8Array = await context.resourceManager.getRawFile(rawFilePath);
487
+ + const destFile = fs.openSync(destPath, fs.OpenMode.CREATE | fs.OpenMode.READ_WRITE | fs.OpenMode.TRUNC);
488
+ + fs.writeSync(destFile.fd, content.buffer);
489
+ + fs.closeSync(destFile);
490
+ + Logger.debug(TAG, `copied rawfile to: ${destPath}, size=${content.length}`);
491
+ + } catch (copyErr) {
492
+ + Logger.error(TAG, `getRawFile copy failed: ${JSON.stringify(copyErr)}, trying fdSrc fallback`);
493
+ + try {
494
+ + let fileDescriptor = await context.resourceManager.getRawFd(rawFilePath);
495
+ + this.pendingCloseSrc = this.previousSrc
496
+ + this.previousSrc = rawFilePath;
497
+ + src = fileDescriptor;
498
+ + Logger.debug(TAG, `fallback to fdSrc: fd=${fileDescriptor.fd}, offset=${fileDescriptor.offset}, length=${fileDescriptor.length}`);
499
+ + } catch (fdErr) {
500
+ + Logger.error(TAG, `getRawFd also failed: ${JSON.stringify(fdErr)}`);
501
+ + reject(fdErr);
502
+ + return;
503
+ + }
504
+ + resolve(src);
505
+ + return;
506
+ + }
507
+ + }
508
+ + this.pendingCloseSrc = this.previousSrc
509
+ + // 打开复制后的临时文件,获取 fd(offset=0 的独立文件,不存在 fdSrc 兼容性问题)
510
+ + const tempFile = fs.openSync(destPath, fs.OpenMode.READ_ONLY);
511
+ + this.previousSrc = tempFile; // 记录以便后续关闭
512
+ + src = `fd://${tempFile.fd}`;
513
+ + Logger.debug(TAG, `local video source: ${src}`);
514
+ } else if (this.srcParam.startsWith('file:')) {
515
+ - this.previousSrc = fs.openSync(this.srcParam, fs.OpenMode.READ_ONLY)
516
+ - src = `fd://${this.previousSrc.fd}`;
517
+ + let file = fs.openSync(this.srcParam, fs.OpenMode.READ_ONLY)
518
+ + this.pendingCloseSrc = this.previousSrc
519
+ + this.previousSrc = file;
520
+ + src = `fd://${file.fd}`;
521
+ + } else if (this.srcParam.length > 0) {
522
+ + Logger.debug(TAG, `unknown scheme, trying as file path: ${this.srcParam}`);
523
+ + this.pendingCloseSrc = this.previousSrc
524
+ + src = this.srcParam;
525
+ + this.previousSrc = undefined;
526
+ } else {
527
+ + this.pendingCloseSrc = this.previousSrc
528
+ this.previousSrc = undefined
529
+ - Logger.debug(TAG, `local, finalsrc: ${(src)}`);
530
+ + Logger.debug(TAG, `empty source, finalsrc: ${src}`);
531
+ }
532
+ resolve(src)
533
+ } catch (error) {
534
+ + Logger.error(TAG, `preparePlayer error: ${JSON.stringify(error)}`);
535
+ reject(error)
536
+ }
537
+ })
538
+ }
539
+
540
+ + /**
541
+ + * 关闭旧的文件描述符(在 AVPlayer 完成切换后调用)
542
+ + * 此时 AVPlayer 已经不再使用旧 fd,可以安全关闭
543
+ + */
544
+ + closeOldFd(): void {
545
+ + if (this.pendingCloseSrc !== undefined) {
546
+ + try {
547
+ + if (typeof this.pendingCloseSrc === "string") {
548
+ + getContext(this).resourceManager.closeRawFdSync(this.pendingCloseSrc);
549
+ + Logger.debug(TAG, `closeOldFd, closeRawFd succeed for: ${this.pendingCloseSrc}`);
550
+ + } else if (typeof this.pendingCloseSrc === "object") {
551
+ + fs.closeSync(this.pendingCloseSrc);
552
+ + Logger.debug(TAG, `closeOldFd, close file succeed`);
553
+ + }
554
+ + } catch (err) {
555
+ + Logger.error(TAG, `closeOldFd error: ${JSON.stringify(err)}`);
556
+ + }
557
+ + this.pendingCloseSrc = undefined;
558
+ + }
559
+ + }
560
+ +
561
+ onSrcChanged(propName: string): void {
562
+ Logger.debug(TAG, `onSrcChanged,propName: ${JSON.stringify(propName)}`);
563
+ this.preparePlayer().then((src) => {
564
+
565
+ ```