@ohos-cpf/3rdloop 0.0.7 → 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 (230) hide show
  1. package/README.md +44 -25
  2. package/lib/cli.js +54 -29
  3. package/lib/config-cmd.js +1 -1
  4. package/lib/config.js +32 -0
  5. package/lib/doctor.js +266 -48
  6. package/lib/mcp.js +498 -0
  7. package/lib/opencode.js +75 -29
  8. package/lib/orch.js +32 -10
  9. package/lib/runner.js +8 -5
  10. package/lib/serve.js +162 -149
  11. package/lib/step.js +15 -4
  12. package/lib/web.js +107 -265
  13. package/lib/workflow.js +18 -8
  14. package/package.json +6 -2
  15. package/vendor/Archive/data/.index/meta.json +7 -0
  16. package/vendor/Archive/data/.index/search.db +0 -0
  17. package/vendor/Archive/data/docs/experiences/arkts-check-tool-pitfalls-baseline-comparison.md +13 -0
  18. package/vendor/Archive/data/docs/experiences/arkts-deep-path-import-recognition.md +31 -0
  19. package/vendor/Archive/data/docs/experiences/arkts-demo-coverage-entry-file-case-mismatch.md +25 -0
  20. package/vendor/Archive/data/docs/experiences/arkts-demo-coverage-import-trailing-slash.md +20 -0
  21. package/vendor/Archive/data/docs/experiences/arkts-library-source-files-may-be-ts.md +18 -0
  22. package/vendor/Archive/data/docs/experiences/arkts-typedarray-buffer-interface-cast-compile-fixes.md +36 -0
  23. package/vendor/Archive/data/docs/experiences/arkts-xts-compile-error-clustering-fix.md +24 -0
  24. package/vendor/Archive/data/docs/experiences/arkts-xts-doc-expected-value-runtime-probe.md +35 -0
  25. package/vendor/Archive/data/docs/experiences/arkts-xts-fixture-rawfile-testability-injection.md +33 -0
  26. package/vendor/Archive/data/docs/experiences/code-linter-chinese-comment-false-positive.md +16 -0
  27. package/vendor/Archive/data/docs/experiences/esobject-new-expression-variable-tracking.md +33 -0
  28. package/vendor/Archive/data/docs/experiences/filesystem-case-sensitivity-module-resolution.md +31 -0
  29. package/vendor/Archive/data/docs/experiences/gitcode-clone-redirect-warning-normal.md +13 -0
  30. package/vendor/Archive/data/docs/experiences/kn_msgvq1w585ec8319.md +77 -0
  31. package/vendor/Archive/data/docs/experiences/kn_msovnm6rd46de72c.md +98 -0
  32. package/vendor/Archive/data/docs/experiences/kn_mspt8vntfe708576.md +87 -0
  33. package/vendor/Archive/data/docs/experiences/kn_mspu1ei77adbbb48.md +133 -0
  34. package/vendor/Archive/data/docs/experiences/kn_mspubgak8d30bfce.md +128 -0
  35. package/vendor/Archive/data/docs/experiences/kn_mspug2de3cb1f7c3.md +115 -0
  36. package/vendor/Archive/data/docs/experiences/kn_skill_opt_001.md +38 -0
  37. package/vendor/Archive/data/docs/experiences/loop-artifacts-verification-evidence-triangle.md +19 -0
  38. package/vendor/Archive/data/docs/experiences/macos-bash-replace-build-ps1.md +19 -0
  39. package/vendor/Archive/data/docs/experiences/macos-bsd-diff-q-illegal-option.md +15 -0
  40. package/vendor/Archive/data/docs/experiences/migrate-cjs-compatible-api-version-map-limit.md +17 -0
  41. package/vendor/Archive/data/docs/experiences/mp3agic-arkts-library-behavior-quirks.md +21 -0
  42. package/vendor/Archive/data/docs/experiences/ohos-face-detection-scan-api-mapping.md +15 -0
  43. package/vendor/Archive/data/docs/experiences/pr-metadata-and-diff-integrity-verification.md +12 -0
  44. package/vendor/Archive/data/docs/experiences/rn-coverage-index-signature-pseudo-member-false-negative.md +32 -0
  45. package/vendor/Archive/data/docs/experiences/rn-memory-check-severity-calibration.md +21 -0
  46. package/vendor/Archive/data/docs/experiences/rn-platform-specific-api-exclusion-evidence.md +24 -0
  47. package/vendor/Archive/data/docs/experiences/rn-upstream-version-diff-pitfalls.md +17 -0
  48. package/vendor/Archive/data/docs/experiences/rn-version-gap-risk-rating-rules.md +13 -0
  49. package/vendor/Archive/data/docs/experiences/rn-view-lib-native-contract-diff-fabric-spec.md +16 -0
  50. package/vendor/Archive/data/docs/experiences/rnoh-adapter-package-version-field-semantics.md +18 -0
  51. package/vendor/Archive/data/docs/experiences/rnoh-arkts-sqlite-rows-array-format.md +18 -0
  52. package/vendor/Archive/data/docs/experiences/rnoh-dependency-residue-scan-strategy.md +18 -0
  53. package/vendor/Archive/data/docs/experiences/rnoh-example-local-lib-dep-use-tgz.md +53 -0
  54. package/vendor/Archive/data/docs/experiences/rnoh-example-prereserve-rntesterlist.md +17 -0
  55. package/vendor/Archive/data/docs/experiences/rnoh-example-template-compatiblesdkversion-upgrade.md +29 -0
  56. package/vendor/Archive/data/docs/experiences/rnoh-example-turbomodule-shell-adaptation-checklist.md +41 -0
  57. package/vendor/Archive/data/docs/experiences/rnoh-mcp-build-project-tool-risk.md +18 -0
  58. package/vendor/Archive/data/docs/experiences/rnoh-npm-devdependencies-version-precheck.md +29 -0
  59. package/vendor/Archive/data/docs/experiences/rnoh-repo-baseline-version-verification.md +13 -0
  60. package/vendor/Archive/data/docs/experiences/rnoh-repo-upstream-directory-mapping.md +18 -0
  61. package/vendor/Archive/data/docs/experiences/rnoh-stateless-library-zero-leak-verification.md +31 -0
  62. package/vendor/Archive/data/docs/experiences/rnoh-template-npmrc-credential-removal.md +15 -0
  63. package/vendor/Archive/data/docs/experiences/rnoh-turbomodule-codegen-wiring-verification.md +19 -0
  64. package/vendor/Archive/data/docs/experiences/rnoh-turbomodule-cpp-methodmap-compatibility-check.md +20 -0
  65. package/vendor/Archive/data/docs/experiences/scenario-doc-vs-source-signature-diff-four-patterns.md +24 -0
  66. package/vendor/Archive/data/docs/experiences/static-analysis-grep-cross-validation.md +29 -0
  67. package/vendor/Archive/demo.js +489 -0
  68. package/vendor/Archive/index.js +43 -0
  69. package/vendor/Archive/package.json +16 -0
  70. package/vendor/Archive/src/constants.js +83 -0
  71. package/vendor/Archive/src/data/stopwords.txt +110 -0
  72. package/vendor/Archive/src/data/synonyms.json +25 -0
  73. package/vendor/Archive/src/data/terms.txt +59 -0
  74. package/vendor/Archive/src/db/sqlite-backend.js +312 -0
  75. package/vendor/Archive/src/db/sqlite-schema.js +64 -0
  76. package/vendor/Archive/src/engine.js +501 -0
  77. package/vendor/Archive/src/index/index-manager.js +203 -0
  78. package/vendor/Archive/src/index/index-state.js +94 -0
  79. package/vendor/Archive/src/index/search-text-builder.js +106 -0
  80. package/vendor/Archive/src/index.js +22 -0
  81. package/vendor/Archive/src/parser/api-identifiers.js +121 -0
  82. package/vendor/Archive/src/parser/api-suffixes.js +48 -0
  83. package/vendor/Archive/src/parser/heading-normalize.js +40 -0
  84. package/vendor/Archive/src/parser/markdown-splitter.js +215 -0
  85. package/vendor/Archive/src/search/catalog-routing.js +87 -0
  86. package/vendor/Archive/src/search/fts-search.js +289 -0
  87. package/vendor/Archive/src/search/query-normalizer.js +159 -0
  88. package/vendor/Archive/src/search/query-rewriter.js +72 -0
  89. package/vendor/Archive/src/search/search-engine.js +72 -0
  90. package/vendor/Archive/src/search/snippet.js +64 -0
  91. package/vendor/Archive/src/store/dir-store.js +103 -0
  92. package/vendor/Archive/src/store/doc-store.js +36 -0
  93. package/vendor/Archive/src/tokenizer/lexicon.js +151 -0
  94. package/vendor/Archive/src/tokenizer/tokenizer.js +167 -0
  95. package/vendor/Archive/src/types.js +86 -0
  96. package/vendor/Archive/src/utils/hash.js +16 -0
  97. package/vendor/Archive/src/utils/lock.js +73 -0
  98. package/vendor/Archive/src/utils/path-safety.js +96 -0
  99. package/vendor/Archive/src/utils/paths.js +39 -0
  100. package/vendor/BadCase/rn/INDEX.md +127 -0
  101. 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
  102. 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
  103. 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
  104. package/vendor/BadCase/rn/cases/KI-004-wechat/345/233/236/350/260/203/346/227/266/345/272/217.md +47 -0
  105. 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
  106. 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
  107. 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
  108. 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
  109. package/vendor/BadCase/rn/cases/KI-009-pager-view/345/265/214/345/245/227/346/273/221/345/212/250.md +38 -0
  110. package/vendor/BadCase/rn/cases/KI-010-screens/346/211/213/345/212/277/345/206/262/347/252/201.md +48 -0
  111. 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
  112. package/vendor/BadCase/rn/cases/KI-012-qr-camera/346/250/252/345/261/217/351/200/202/351/205/215.md +59 -0
  113. 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
  114. package/vendor/BadCase/rn/cases/KI-014-amap-geolocation/345/233/236/350/260/203/347/274/272/345/244/261.md +42 -0
  115. 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
  116. 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
  117. 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
  118. package/vendor/BadCase/rn/cases/KI-018-modal/345/274/271/347/252/227/351/227/252/347/203/201.md +53 -0
  119. 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
  120. 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
  121. 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
  122. 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
  123. 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
  124. package/vendor/BadCase/rn/generalization-log.md +55 -0
  125. package/vendor/BadCase/rn/pr-info/rntpc_react-native-SmartRefreshLayout-32.json +328 -0
  126. package/vendor/BadCase/rn/pr-info/rntpc_react-native-SmartRefreshLayout-32.md +382 -0
  127. package/vendor/BadCase/rn/pr-info/rntpc_react-native-amap-geolocation-27.json +1351 -0
  128. package/vendor/BadCase/rn/pr-info/rntpc_react-native-amap-geolocation-27.md +1176 -0
  129. package/vendor/BadCase/rn/pr-info/rntpc_react-native-audio-recorder-player-22.json +538 -0
  130. package/vendor/BadCase/rn/pr-info/rntpc_react-native-audio-recorder-player-22.md +1488 -0
  131. package/vendor/BadCase/rn/pr-info/rntpc_react-native-blob-util-23.json +211 -0
  132. package/vendor/BadCase/rn/pr-info/rntpc_react-native-blob-util-23.md +35 -0
  133. package/vendor/BadCase/rn/pr-info/rntpc_react-native-code-push-17.json +2048 -0
  134. package/vendor/BadCase/rn/pr-info/rntpc_react-native-code-push-17.md +3866 -0
  135. package/vendor/BadCase/rn/pr-info/rntpc_react-native-fast-image-102.json +198 -0
  136. package/vendor/BadCase/rn/pr-info/rntpc_react-native-fast-image-102.md +40 -0
  137. package/vendor/BadCase/rn/pr-info/rntpc_react-native-fs-38.json +751 -0
  138. package/vendor/BadCase/rn/pr-info/rntpc_react-native-fs-38.md +883 -0
  139. package/vendor/BadCase/rn/pr-info/rntpc_react-native-geolocation-24.json +1544 -0
  140. package/vendor/BadCase/rn/pr-info/rntpc_react-native-geolocation-24.md +2598 -0
  141. package/vendor/BadCase/rn/pr-info/rntpc_react-native-modal-20.json +246 -0
  142. package/vendor/BadCase/rn/pr-info/rntpc_react-native-modal-20.md +554 -0
  143. package/vendor/BadCase/rn/pr-info/rntpc_react-native-netinfo-31.json +211 -0
  144. package/vendor/BadCase/rn/pr-info/rntpc_react-native-netinfo-31.md +54 -0
  145. package/vendor/BadCase/rn/pr-info/rntpc_react-native-orientation-locker-45.json +1626 -0
  146. package/vendor/BadCase/rn/pr-info/rntpc_react-native-orientation-locker-45.md +2213 -0
  147. package/vendor/BadCase/rn/pr-info/rntpc_react-native-orientation-locker-51.json +208 -0
  148. package/vendor/BadCase/rn/pr-info/rntpc_react-native-orientation-locker-51.md +77 -0
  149. package/vendor/BadCase/rn/pr-info/rntpc_react-native-pager-view-32.json +377 -0
  150. package/vendor/BadCase/rn/pr-info/rntpc_react-native-pager-view-32.md +174 -0
  151. package/vendor/BadCase/rn/pr-info/rntpc_react-native-qr-decode-image-camera-37.json +232 -0
  152. package/vendor/BadCase/rn/pr-info/rntpc_react-native-qr-decode-image-camera-37.md +194 -0
  153. package/vendor/BadCase/rn/pr-info/rntpc_react-native-reanimated-82.json +198 -0
  154. package/vendor/BadCase/rn/pr-info/rntpc_react-native-reanimated-82.md +67 -0
  155. package/vendor/BadCase/rn/pr-info/rntpc_react-native-screens-87.json +198 -0
  156. package/vendor/BadCase/rn/pr-info/rntpc_react-native-screens-87.md +38 -0
  157. package/vendor/BadCase/rn/pr-info/rntpc_react-native-screens-93.json +208 -0
  158. package/vendor/BadCase/rn/pr-info/rntpc_react-native-screens-93.md +34 -0
  159. package/vendor/BadCase/rn/pr-info/rntpc_react-native-spring-scrollview-38.json +222 -0
  160. package/vendor/BadCase/rn/pr-info/rntpc_react-native-spring-scrollview-38.md +56 -0
  161. package/vendor/BadCase/rn/pr-info/rntpc_react-native-svg-117.json +463 -0
  162. package/vendor/BadCase/rn/pr-info/rntpc_react-native-svg-117.md +383 -0
  163. package/vendor/BadCase/rn/pr-info/rntpc_react-native-video-66.json +464 -0
  164. package/vendor/BadCase/rn/pr-info/rntpc_react-native-video-66.md +565 -0
  165. package/vendor/BadCase/rn/pr-info/rntpc_react-native-webview-112.json +198 -0
  166. package/vendor/BadCase/rn/pr-info/rntpc_react-native-webview-112.md +47 -0
  167. package/vendor/BadCase/rn/pr-info/rntpc_react-native-webview-121.json +232 -0
  168. package/vendor/BadCase/rn/pr-info/rntpc_react-native-webview-121.md +422 -0
  169. package/vendor/BadCase/rn/pr-info/rntpc_react-native-wechat-lib-15.json +295 -0
  170. package/vendor/BadCase/rn/pr-info/rntpc_react-native-wechat-lib-15.md +1038 -0
  171. 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
  172. 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
  173. 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
  174. 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
  175. 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
  176. 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
  177. 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
  178. 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
  179. 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
  180. 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
  181. 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
  182. 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
  183. 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
  184. 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
  185. 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
  186. 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
  187. 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
  188. 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
  189. 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
  190. package/vendor/MCP/README.md +490 -0
  191. package/vendor/MCP/config.json +29 -0
  192. package/vendor/MCP/package.json +23 -0
  193. package/vendor/MCP/scripts/analyze-demo-coverage.cjs +1203 -0
  194. package/vendor/MCP/scripts/analyze-xts-coverage.cjs +1245 -0
  195. package/vendor/MCP/scripts/deveco_docs.js +247 -0
  196. package/vendor/MCP/scripts/extract-interfaces.cjs +1487 -0
  197. package/vendor/MCP/scripts/flutter-analyze-demo-coverage.cjs +666 -0
  198. package/vendor/MCP/scripts/flutter-analyze-xts-coverage.cjs +684 -0
  199. package/vendor/MCP/scripts/flutter-extract-interfaces.cjs +1251 -0
  200. package/vendor/MCP/scripts/flutter-render-spec-doc.cjs +351 -0
  201. package/vendor/MCP/scripts/render-spec-doc.cjs +347 -0
  202. package/vendor/MCP/scripts/rn-analyze-demo-coverage.cjs +645 -0
  203. package/vendor/MCP/scripts/rn-analyze-test-coverage.cjs +614 -0
  204. package/vendor/MCP/scripts/rn-extract-interfaces.cjs +1462 -0
  205. package/vendor/MCP/scripts/rn-render-spec-doc.cjs +327 -0
  206. package/vendor/MCP/scripts/rn-scan-exports.cjs +1336 -0
  207. package/vendor/MCP/src/client/MCPClientPool.js +220 -0
  208. package/vendor/MCP/src/config/ConfigLoader.js +189 -0
  209. package/vendor/MCP/src/executor/ScriptExecutor.js +110 -0
  210. package/vendor/MCP/src/gateway/Gateway.js +451 -0
  211. package/vendor/MCP/src/index.js +87 -0
  212. package/vendor/MCP/src/library/KBToolProvider.js +229 -0
  213. package/vendor/MCP/src/library/logger.js +60 -0
  214. package/vendor/MCP/src/registry/ScriptRegistry.js +238 -0
  215. package/vendor/MCP/src/registry/ToolRegistry.js +111 -0
  216. package/vendor/MCP/src/types.js +115 -0
  217. package/vendor/Server/CLI/cli.js +3 -3
  218. package/vendor/Server/Routes/server.js +3 -3
  219. package/vendor/Server/Skills/arkts-library-test-coverage-check/references/MCP_TOOL_USAGE.md +4 -2
  220. package/vendor/Server/Skills/arkts-library-xts-coverage/SKILL.md +3 -3
  221. package/vendor/Server/Skills/knowledge-import/SKILL.md +1 -1
  222. package/vendor/Server/Skills/knowledge-import/references/MCP_TOOL_USAGE.md +12 -4
  223. package/vendor/Server/Skills/ohos-lib-pr-push/SKILL.md +5 -4
  224. package/vendor/Server/Skills/rn-library-issue-generalizer/SKILL.md +2 -2
  225. package/vendor/Server/Skills/rn-library-known-issue-check/SKILL.md +2 -2
  226. package/vendor/Server/Skills/rnoh-lib-demo-coverage/SKILL.md +1 -2
  227. package/vendor/Server/Skills/rnoh-lib-test-align/references/port-test-demo-guide.md +1 -1
  228. package/vendor/Server/Skills/rnoh-lib-xts-coverage/SKILL.md +1 -2
  229. package/vendor/Server/package.json +5 -1
  230. package/vendor/VERSION +3 -3
@@ -0,0 +1,1488 @@
1
+ # PR #22: fix:把遗漏的封装格式AAC补齐
2
+
3
+ - **状态**: merged
4
+ - **作者**: chenbaodi123
5
+ - **创建时间**: 2026-06-25T10:36:47+08:00
6
+ - **分支**: 77_bugfix → br_rnoh0.77
7
+ - **变更文件数**: 15
8
+ - **⚠️ 注意**: diff 过大已截断,变更文件列表完整保留
9
+
10
+ ## PR 描述
11
+
12
+ 问题原因:在index.ts的AudioFormatHarmonyType格式中没有aac的枚举,导致用户无法录制aac格式的音频
13
+ 解决方案:ts的AudioFormatHarmonyType格式中补充aac格式的枚举类型
14
+
15
+ ## 变更文件
16
+
17
+ | 文件 | 变更 | +行 | -行 |
18
+ |------|------|-----|-----|
19
+ | `.gitignore` | ? | +0 | -1 |
20
+ | `OAT.xml` | ? | +2 | -0 |
21
+ | `README.md` | ? | +746 | -7 |
22
+ | `README_en.md` | added | +754 | -0 |
23
+ | `buildEnv.sh` | added | +8 | -0 |
24
+ | `example/harmony/build-profile.template.json5` | ? | +10 | -2 |
25
+ | `example/harmony/entry/oh-package.json5` | ? | +1 | -1 |
26
+ | `example/harmony/oh-package.json5` | ? | +1 | -1 |
27
+ | `example/index.js` | added | +11 | -0 |
28
+ | `example/package.json` | ? | +6 | -5 |
29
+ | `harmony/audio_recorder_player.har` | ? | +0 | -0 |
30
+ | `harmony/audio_recorder_player/src/main/ets/RNAudioRecorderPlayerTurboModule.ts` | ? | +1 | -1 |
31
+ | `harmony/audio_recorder_player/src/main/ets/index.ts` | renamed | +0 | -0 |
32
+ | `index.ts` | ? | +2 | -1 |
33
+ | `package.json` | ? | +2 | -1 |
34
+
35
+ ## Diff
36
+
37
+ ### `.gitignore`
38
+
39
+ ```diff
40
+ @@ -54,7 +54,6 @@ package-lock.json
41
+ # Built files
42
+ tsconfig.tsbuildinfo
43
+ index.js.flow
44
+ -index.js
45
+ harmony/audio_recorder_player/oh_modules/
46
+
47
+ harmony/audio_recorder_player/build/
48
+
49
+ ```
50
+
51
+ ### `OAT.xml`
52
+
53
+ ```diff
54
+ @@ -48,6 +48,7 @@
55
+ <filteritem type="filepath" name="index.*" desc="第三方开源软件源码,不修改版权头,以防有修改版权风险" />
56
+ <filteritem type="filepath" name="hvigor/hvigor-wrapper.js" desc="工程模板,不修改版权头,以防有修改版权风险" />
57
+ <filteritem type="filepath" name="hvigor/hvigor-config.json5" desc="工程模板,不修改版权头,以防有修改版权风险" />
58
+ + <filteritem type="filepath" name="buildEnv.sh" desc="工程模板,不修改版权头,以防有修改版权风险" />
59
+ </filefilter>
60
+ <filefilter name="defaultPolicyFilter" desc="Filters for compatibility,license header policies">
61
+ <filteritem type="filepath" name="harmony/audio_recorder_player/hvigorfile.ts" desc="hvigor构建脚本,DevEco Studio自动生成,不手动修改" />
62
+ @@ -79,6 +80,7 @@
63
+ <filteritem type="filepath" name="index.*" desc="第三方开源软件源码,不修改版权头,以防有修改版权风险"/>
64
+ <filteritem type="filepath" name="hvigor/hvigor-wrapper.js" desc="工程模板,不修改版权头,以防有修改版权风险"/>
65
+ <filteritem type="filepath" name="hvigor/hvigor-config.json5" desc="工程模板,不修改版权头,以防有修改版权风险"/>
66
+ + <filteritem type="filepath" name="buildEnv.sh" desc="工程模板,不修改版权头,以防有修改版权风险" />
67
+ </filefilter>
68
+
69
+ <filefilter name="binaryFileTypePolicyFilter" desc="Filters for copyright header policies">
70
+
71
+ ```
72
+
73
+ ### `README.md`
74
+
75
+ ```diff
76
+ @@ -1,14 +1,753 @@
77
+ -# @react-native-ohos/react-native-audio-recorder-player
78
+ +> 模板版本:v0.2.2
79
+
80
+ -This project is based on [react-native-audio-recorder-player@3.6.13](https://github.com/hyochan/react-native-audio-recorder-player/tree/3.6.13)
81
+ +<p align="center">
82
+ + <h1 align="center"> <code>react-native-audio-recorder-player</code> </h1>
83
+ +</p>
84
+ +<p align="center">
85
+ + <a href="https://github.com/hyochan/react-native-audio-recorder-player">
86
+ + <img src="https://img.shields.io/badge/platforms-android%20|%20ios%20|%20harmony%20-lightgrey.svg" alt="Supported platforms" />
87
+ + </a>
88
+ + <a href="https://github.com/hyochan/react-native-audio-recorder-player/blob/main/LICENSE">
89
+ + <img src="https://img.shields.io/badge/license-MIT-green.svg" alt="License" />
90
+ + </a>
91
+ +</p>
92
+
93
+ -## Documentation
94
+ +> [!TIP] [Github 地址](https://github.com/react-native-oh-library/react-native-audio-recorder-player)
95
+
96
+ -- [中文](https://gitee.com/react-native-oh-library/usage-docs/blob/master/zh-cn/react-native-audio-recorder-player.md)
97
+ +## 安装与使用
98
+
99
+ -- [English](https://gitee.com/react-native-oh-library/usage-docs/blob/master/en/react-native-audio-recorder-player.md)
100
+ +请到三方库的 Releases 发布地址查看配套的版本信息:
101
+
102
+ -## License
103
+ +| 三方库版本 | 发布信息 | 支持RN版本 |
104
+ +| ---------- | ------------------------------------------------------------ | ---------- |
105
+ +| <= 3.6.10-0.0.2@deprecated | [@react-native-oh-tpl/react-native-audio-recorder-player Releases(deprecated)](https://github.com/react-native-oh-library/react-native-audio-recorder-player/releases) | 0.72 |
106
+ +| 3.6.11 | [@react-native-ohos/react-native-audio-recorder-player Releases](https://gitcode.com/openharmony-sig/rntpc_react-native-audio-recorder-player/releases) | 0.72 |
107
+ +| 3.7.0 | [@react-native-ohos/react-native-audio-recorder-player Releases](https://gitcode.com/openharmony-sig/rntpc_react-native-audio-recorder-player/releases) | 0.77 |
108
+
109
+ -This library is licensed under [The MIT License (MIT)](https://github.com/hyochan/react-native-audio-recorder-player/blob/main/LICENSE)
110
+ +对于未发布到npm的旧版本,请参考[安装指南](/tgz-usage.md)安装tgz包。
111
+
112
+ +进入到工程目录并输入以下命令:
113
+ +
114
+ +#### **npm**
115
+ +
116
+ +```bash
117
+ +npm install @react-native-ohos/react-native-audio-recorder-player
118
+ +```
119
+ +
120
+ +#### **yarn**
121
+ +
122
+ +```bash
123
+ +yarn add @react-native-ohos/react-native-audio-recorder-player
124
+ +```
125
+ +
126
+ +下面的代码展示了这个库的基本使用场景:
127
+ +
128
+ +> [!WARNING] 使用时 import 的库名不变。
129
+ +
130
+ +```js
131
+ +import AudioRecorderPlayer, {
132
+ + AVEncoderAudioQualityIOSType,
133
+ + AVEncodingOption,
134
+ + AudioEncoderAndroidType,
135
+ + AudioSourceAndroidType,
136
+ + OutputFormatAndroidType,
137
+ + AudioMimeHarmonyType,
138
+ + AudioFormatHarmonyType,
139
+ + AudioSourceHarmonyType,
140
+ + AudioSet
141
+ +} from 'react-native-audio-recorder-player'; import type {
142
+ + PlayBackType,
143
+ + RecordBackType,
144
+ +} from 'react-native-audio-recorder-player';
145
+ +
146
+ +import {
147
+ + Dimensions,
148
+ + Platform,
149
+ + ActivityIndicator,
150
+ + Image,
151
+ + SafeAreaView,
152
+ + StyleSheet,
153
+ + Text,
154
+ + TouchableOpacity,
155
+ + View,
156
+ +} from 'react-native';
157
+ +import React, { Component } from 'react';
158
+ +
159
+ +import type { ReactElement, ReactNode } from 'react';
160
+ +
161
+ +const stylesButton: any = StyleSheet.create({
162
+ + btn: {
163
+ + backgroundColor: 'transparent',
164
+ + alignSelf: 'center',
165
+ + borderRadius: 4,
166
+ + borderWidth: 2,
167
+ + width: 320,
168
+ + height: 52,
169
+ + borderColor: 'white',
170
+ +
171
+ + alignItems: 'center',
172
+ + justifyContent: 'center',
173
+ + },
174
+ + btnDisabled: {
175
+ + backgroundColor: 'rgb(243,243,243)',
176
+ + alignSelf: 'center',
177
+ + borderRadius: 4,
178
+ + borderWidth: 2,
179
+ + width: 320,
180
+ + height: 52,
181
+ + borderColor: '#333',
182
+ +
183
+ + alignItems: 'center',
184
+ + justifyContent: 'center',
185
+ + },
186
+ + txt: {
187
+ + fontSize: 14,
188
+ + color: 'white',
189
+ + },
190
+ + imgLeft: {
191
+ + width: 24,
192
+ + height: 24,
193
+ + position: 'absolute',
194
+ + left: 16,
195
+ + },
196
+ +});
197
+ +
198
+ +interface ItemProps {
199
+ + children?: ReactNode;
200
+ + isLoading?: boolean;
201
+ + isDisabled?: boolean;
202
+ + onPress?: () => void;
203
+ + style?: any;
204
+ + disabledStyle?: any;
205
+ + textStyle?: any;
206
+ + imgLeftSrc?: any;
207
+ + imgLeftStyle?: any;
208
+ + indicatorColor?: string;
209
+ + activeOpacity?: number;
210
+ +}
211
+ +
212
+ +class Button extends Component<ItemProps, any> {
213
+ + private static defaultProps: Partial<ItemProps> = {
214
+ + isLoading: false,
215
+ + isDisabled: false,
216
+ + style: stylesButton.btn,
217
+ + textStyle: stylesButton.txt,
218
+ + imgLeftStyle: stylesButton.imgLeft,
219
+ + indicatorColor: 'white',
220
+ + activeOpacity: 0.5,
221
+ + };
222
+ +
223
+ + constructor(props: ItemProps) {
224
+ + super(props);
225
+ + this.state = {};
226
+ + }
227
+ +
228
+ + public render(): ReactElement {
229
+ + if (this.props.isDisabled) {
230
+ + return (
231
+ + <View style={this.props.disabledStyle}>
232
+ + <Text style={this.props.textStyle}>{this.props.children}</Text>
233
+ + </View>
234
+ + );
235
+ + }
236
+ +
237
+ + if (this.props.isLoading) {
238
+ + return (
239
+ + <View style={this.props.style}>
240
+ + <ActivityIndicator size="small" color={this.props.indicatorColor} />
241
+ + </View>
242
+ + );
243
+ + }
244
+ +
245
+ + return (
246
+ + <TouchableOpacity
247
+ + activeOpacity={this.props.activeOpacity}
248
+ + onPress={this.props.onPress}>
249
+ + <View style={this.props.style}>
250
+ + {this.props.imgLeftSrc ? (
251
+ + <Image
252
+ + style={this.props.imgLeftStyle}
253
+ + source={this.props.imgLeftSrc}
254
+ + />
255
+ + ) : null}
256
+ + <Text style={this.props.textStyle}>{this.props.children}</Text>
257
+ + </View>
258
+ + </TouchableOpacity>
259
+ + );
260
+ + }
261
+ +}
262
+ +
263
+ +const styles: any = StyleSheet.create({
264
+ + container: {
265
+ + flex: 1,
266
+ + backgroundColor: '#455A64',
267
+ + flexDirection: 'column',
268
+ + alignItems: 'center',
269
+ + height: Dimensions.get('screen').height
270
+ + },
271
+ + titleTxt: {
272
+ + marginTop: 100,
273
+ + color: 'white',
274
+ + fontSize: 28,
275
+ + },
276
+ + viewRecorder: {
277
+ + marginTop: 40,
278
+ + width: '100%',
279
+ + alignItems: 'center',
280
+ + },
281
+ + recordBtnWrapper: {
282
+ + flexDirection: 'row',
283
+ + },
284
+ + viewPlayer: {
285
+ + marginTop: 60,
286
+ + alignSelf: 'stretch',
287
+ + alignItems: 'center',
288
+ + },
289
+ + viewBarWrapper: {
290
+ + marginTop: 28,
291
+ + marginHorizontal: 28,
292
+ + alignSelf: 'stretch',
293
+ + },
294
+ + viewBar: {
295
+ + backgroundColor: '#ccc',
296
+ + height: 4,
297
+ + alignSelf: 'stretch',
298
+ + },
299
+ + viewBarPlay: {
300
+ + backgroundColor: 'white',
301
+ + height: 4,
302
+ + width: 0,
303
+ + },
304
+ + playStatusTxt: {
305
+ + marginTop: 8,
306
+ + color: '#ccc',
307
+ + },
308
+ + playBtnWrapper: {
309
+ + flexDirection: 'row',
310
+ + marginTop: 40,
311
+ + },
312
+ + btn: {
313
+ + borderColor: 'white',
314
+ + borderWidth: 1,
315
+ + },
316
+ + txt: {
317
+ + color: 'white',
318
+ + fontSize: 14,
319
+ + marginHorizontal: 8,
320
+ + marginVertical: 4,
321
+ + },
322
+ + txtRecordCounter: {
323
+ + marginTop: 32,
324
+ + color: 'white',
325
+ + fontSize: 20,
326
+ + textAlignVertical: 'center',
327
+ + fontWeight: '200',
328
+ + fontFamily: 'Helvetica Neue',
329
+ + letterSpacing: 3,
330
+ + width: 300
331
+ + },
332
+ + txtCounter: {
333
+ + marginTop: 12,
334
+ + color: 'white',
335
+ + fontSize: 20,
336
+ + textAlignVertical: 'center',
337
+ + fontWeight: '200',
338
+ + fontFamily: 'Helvetica Neue',
339
+ + letterSpacing: 3,
340
+ + width: 300
341
+ + },
342
+ +});
343
+ +
344
+ +interface State {
345
+ + isLoggingIn: boolean;
346
+ + recordSecs: number;
347
+ + recordTime: string;
348
+ + currentPositionSec: number;
349
+ + currentDurationSec: number;
350
+ + playTime: string;
351
+ + duration: string;
352
+ +}
353
+ +
354
+ +const screenWidth = Dimensions.get('screen').width;
355
+ +
356
+ +class Page extends Component<any, State> {
357
+ + private audioRecorderPlayer
358
+ +
359
+ + constructor(props: any) {
360
+ + super(props);
361
+ + this.state = {
362
+ + isLoggingIn: false,
363
+ + recordSecs: 0,
364
+ + recordTime: '00:00:00',
365
+ + currentPositionSec: 0,
366
+ + currentDurationSec: 0,
367
+ + playTime: '00:00:00',
368
+ + duration: '00:00:00',
369
+ + };
370
+ +
371
+ + this.audioRecorderPlayer = new AudioRecorderPlayer()
372
+ + this.audioRecorderPlayer.setSubscriptionDuration(0.5); // optional. Default is 0.5
373
+ + }
374
+ +
375
+ + public render(): ReactElement {
376
+ + let playWidth =
377
+ + (this.state.currentPositionSec / this.state.currentDurationSec) *
378
+ + (screenWidth - 56);
379
+ +
380
+ + if (!playWidth) {
381
+ + playWidth = 0;
382
+ + }
383
+ +
384
+ + return (
385
+ + <SafeAreaView style={styles.container}>
386
+ + <Text style={styles.titleTxt}>Audio Recorder Player</Text>
387
+ + <Text style={styles.txtRecordCounter}>{this.state.recordTime}</Text>
388
+ + <View style={styles.viewRecorder}>
389
+ + <View style={styles.recordBtnWrapper}>
390
+ + <Button
391
+ + style={styles.btn}
392
+ + onPress={this.onStartRecord}
393
+ + textStyle={styles.txt}>
394
+ + startRecord
395
+ + </Button>
396
+ + <Button
397
+ + style={[
398
+ + styles.btn,
399
+ + {
400
+ + marginLeft: 12,
401
+ + },
402
+ + ]}
403
+ + onPress={this.onPauseRecord}
404
+ + textStyle={styles.txt}>
405
+ + Pause
406
+ + </Button>
407
+ + <Button
408
+ + style={[
409
+ + styles.btn,
410
+ + {
411
+ + marginLeft: 12,
412
+ + },
413
+ + ]}
414
+ + onPress={this.onResumeRecord}
415
+ + textStyle={styles.txt}>
416
+ + Resume
417
+ + </Button>
418
+ + <Button
419
+ + style={[styles.btn, { marginLeft: 12 }]}
420
+ + onPress={this.onStopRecord}
421
+ + textStyle={styles.txt}>
422
+ + Stop
423
+ + </Button>
424
+ + </View>
425
+ + </View>
426
+ + <View style={styles.viewPlayer}>
427
+ + <TouchableOpacity
428
+ + style={styles.viewBarWrapper}
429
+ + onPress={this.onStatusPress}>
430
+ + <View style={styles.viewBar}>
431
+ + <View style={[styles.viewBarPlay, { width: playWidth }]} />
432
+ + </View>
433
+ + </TouchableOpacity>
434
+ + <Text style={styles.txtCounter}>
435
+ + {this.state.playTime} / {this.state.duration}
436
+ + </Text>
437
+ + <View style={styles.playBtnWrapper}>
438
+ + <Button
439
+ + style={styles.btn}
440
+ + onPress={this.onStartPlay}
441
+ + textStyle={styles.txt}>
442
+ + Play
443
+ + </Button>
444
+ + <Button
445
+ + style={[
446
+ + styles.btn,
447
+ + {
448
+ + marginLeft: 12,
449
+ + },
450
+ + ]}
451
+ + onPress={this.onPausePlay}
452
+ + textStyle={styles.txt}>
453
+ + Pause
454
+ + </Button>
455
+ + <Button
456
+ + style={[
457
+ + styles.btn,
458
+ + {
459
+ + marginLeft: 12,
460
+ + },
461
+ + ]}
462
+ + onPress={this.onResumePlay}
463
+ + textStyle={styles.txt}>
464
+ + Resume
465
+ + </Button>
466
+ + <Button
467
+ + style={[
468
+ + styles.btn,
469
+ + {
470
+ + marginLeft: 12,
471
+ + },
472
+ + ]}
473
+ + onPress={this.onStopPlay}
474
+ + textStyle={styles.txt}>
475
+ + Stop
476
+ + </Button>
477
+ + </View>
478
+ + </View>
479
+ + </SafeAreaView>
480
+ + );
481
+ + }
482
+ +
483
+ + private onStatusPress = (e: any): void => {
484
+ + const touchX = e.nativeEvent.locationX;
485
+ + console.log(`touchX: ${touchX}`);
486
+ +
487
+ + const playWidth =
488
+ + (this.state.currentPositionSec / this.state.currentDurationSec) *
489
+ + (screenWidth - 56);
490
+ + console.log(`currentPlayWidth: ${playWidth}`);
491
+ +
492
+ + const currentPosition = Math.round(this.state.currentPositionSec);
493
+ +
494
+ + if (playWidth && playWidth < touchX) {
495
+ + const addSecs = Math.round(currentPosition + 1000);
496
+ + this.audioRecorderPlayer.seekToPlayer(addSecs);
497
+ + console.log(`addSecs: ${addSecs}`);
498
+ + } else {
499
+ + const subSecs = Math.round(currentPosition - 1000);
500
+ + this.audioRecorderPlayer.seekToPlayer(subSecs);
501
+ + console.log(`subSecs: ${subSecs}`);
502
+ + }
503
+ + };
504
+ +
505
+ + private onStartRecord = async (): Promise<void> => {
506
+ +
507
+ + const audioSet: AudioSet = {
508
+ + AudioEncoderAndroid: AudioEncoderAndroidType.AAC,
509
+ + AudioSourceAndroid: AudioSourceAndroidType.MIC,
510
+ + AVEncoderAudioQualityKeyIOS: AVEncoderAudioQualityIOSType.high,
511
+ + AVNumberOfChannelsKeyIOS: 2,
512
+ + AVFormatIDKeyIOS: AVEncodingOption.aac,
513
+ + OutputFormatAndroid: OutputFormatAndroidType.AAC_ADTS,
514
+ + AudioSourceHarmony: AudioSourceHarmonyType.MIC,
515
+ + AudioMimeHarmony: AudioMimeHarmonyType.AUDIO_AAC,
516
+ + AudioFileFormatHarmony: AudioFormatHarmonyType.MPEG_4A,
517
+ + AudioEncodingBitRateHarmony: 3200,
518
+ + AudioSamplingRateHarmony: 44100,
519
+ + AudioChannelsHarmony: 2,
520
+ + };
521
+ +
522
+ + console.log('audioSet', audioSet);
523
+ +
524
+ + const uri = await this.audioRecorderPlayer.startRecorder(
525
+ + 'audio.m4a',
526
+ + audioSet,
527
+ + );
528
+ +
529
+ + this.audioRecorderPlayer.addRecordBackListener((e: RecordBackType) => {
530
+ + console.log('record-back', e);
531
+ + this.setState({
532
+ + recordSecs: e.currentPosition,
533
+ + recordTime: this.audioRecorderPlayer.mmssss(
534
+ + Math.floor(e.currentPosition),
535
+ + ),
536
+ + });
537
+ + });
538
+ +
539
+ + console.log(`uri: ${uri}`);
540
+ + };
541
+ +
542
+ + private onPauseRecord = async (): Promise<void> => {
543
+ + try {
544
+ + const r = await this.audioRecorderPlayer.pauseRecorder();
545
+ + console.log(r);
546
+ + } catch (err) {
547
+ + console.log('pauseRecord', err);
548
+ + }
549
+ + };
550
+ +
551
+ + private onResumeRecord = async (): Promise<void> => {
552
+ + await this.audioRecorderPlayer.resumeRecorder();
553
+ + };
554
+ +
555
+ + private onStopRecord = async (): Promise<void> => {
556
+ + const result = await this.audioRecorderPlayer.stopRecorder();
557
+ + this.audioRecorderPlayer.removeRecordBackListener();
558
+ + this.setState({
559
+ + recordSecs: 0,
560
+ + });
561
+ + console.log(result, '>>>>>>>stopRecorder');
562
+ + };
563
+ +
564
+ + private onStartPlay = async (): Promise<void> => {
565
+ + console.log('onStartPlay');
566
+ +
567
+ + try {
568
+ + const msg = await this.audioRecorderPlayer.startPlayer('https://sis-sample-audio.obs.cn-north-1.myhuaweicloud.com/16k16bit.mp3', { 'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:12.0) Gecko/20100101 Firefox/21.0' });
569
+ + const volume = await this.audioRecorderPlayer.setVolume(1);
570
+ + this.audioRecorderPlayer.addPlayBackListener((e: PlayBackType) => {
571
+ + console.log('playBackListener', e);
572
+ + this.setState({
573
+ + currentPositionSec: e.currentPosition,
574
+ + currentDurationSec: e.duration,
575
+ + playTime: this.audioRecorderPlayer.mmssss(e.currentPosition),
576
+ + duration: this.audioRecorderPlayer.mmssss(Math.floor(e.duration)),
577
+ + });
578
+ + });
579
+ +
580
+ + } catch (err) {
581
+ + console.log('startPlayer error', err);
582
+ + }
583
+ + };
584
+ +
585
+ + private onPausePlay = async (): Promise<void> => {
586
+ + await this.audioRecorderPlayer.pausePlayer();
587
+ + };
588
+ +
589
+ + private onResumePlay = async (): Promise<void> => {
590
+ + await this.audioRecorderPlayer.resumePlayer();
591
+ + };
592
+ +
593
+ + private onStopPlay = async (): Promise<void> => {
594
+ + console.log('onStopPlay');
595
+ + this.audioRecorderPlayer.stopPlayer();
596
+ + this.audioRecorderPlayer.removePlayBackListener();
597
+ + };
598
+ +}
599
+ +
600
+ +export default Page;
601
+ +
602
+ +```
603
+ +
604
+ +## Link
605
+ +
606
+ +| | 是否支持autolink | RN框架版本 |
607
+ +|--------------------------------------|-----------------|------------|
608
+ +| ~3.7.0 | No | 0.77 |
609
+ +| ~3.6.11 | Yes | 0.72 |
610
+ +| <= 3.6.10-0.0.2@deprecated | No | 0.72 |
611
+ +
612
+ +使用AutoLink的工程需要根据该文档配置,Autolink框架指导文档:https://gitcode.com/openharmony-sig/ohos_react_native/blob/master/docs/zh-cn/Autolinking.md
613
+ +
614
+ +如您使用的版本支持 Autolink,并且工程已接入 Autolink,可跳过ManualLink配置。
615
+ +<details>
616
+ + <summary>ManualLink: 此步骤为手动配置原生依赖项的指导</summary>
617
+ +
618
+ +首先需要使用 DevEco Studio 打开项目里的 HarmonyOS 工程 `harmony`。
619
+ +
620
+ +### 在工程根目录的 `oh-package.json5` 添加 overrides 字段
621
+ +
622
+ +```json
623
+ +{
624
+ + ...
625
+ + "overrides": {
626
+ + "@rnoh/react-native-openharmony" : "./react_native_openharmony"
627
+ + }
628
+ +}
629
+ +```
630
+ +
631
+ +### 引入原生端代码
632
+ +
633
+ +目前有两种方法:
634
+ +
635
+ +1. 通过 har 包引入(在 IDE 完善相关功能后该方法会被遗弃,目前首选此方法);
636
+ +2. 直接链接源码。
637
+ +
638
+ +方法一:通过 har 包引入(推荐)
639
+ +
640
+ +> [!TIP] har 包位于三方库安装路径的 `harmony` 文件夹下。
641
+ +
642
+ +打开 `entry/oh-package.json5`,添加以下依赖
643
+ +
644
+ +```json
645
+ +"dependencies": {
646
+ + "@rnoh/react-native-openharmony": "file:../react_native_openharmony",
647
+ +
648
+ + "@react-native-ohos/react-native-audio-recorder-player": "file:../../node_modules/@react-native-ohos/react-native-audio-recorder-player/harmony/audio_recorder_player.har"
649
+ + }
650
+ +```
651
+ +点击右上角的 `sync` 按钮
652
+ +
653
+ +或者在终端执行:
654
+ +
655
+ +```bash
656
+ +cd entry
657
+ +ohpm install
658
+ +```
659
+ +方法二:直接链接源码
660
+ +
661
+ +> [!TIP] 如需使用直接链接源码,请参考[直接链接源码说明](/link-source-code.md)
662
+ +
663
+ +### 配置 CMakeLists 和引入 RNAudioRecorderPlayerPackage
664
+ +
665
+ +> 若使用的是 <= 3.6.10-0.0.2 版本,请跳过本章。
666
+ +
667
+ +打开 `entry/src/main/cpp/CMakeLists.txt`,添加:
668
+ +
669
+ +```diff
670
+ +project(rnapp)
671
+ +cmake_minimum_required(VERSION 3.4.1)
672
+ +set(CMAKE_SKIP_BUILD_RPATH TRUE)
673
+ +set(RNOH_APP_DIR "${CMAKE_CURRENT_SOURCE_DIR}")
674
+ +set(NODE_MODULES "${CMAKE_CURRENT_SOURCE_DIR}/../../../../../node_modules")
675
+ ++ set(OH_MODULES "${CMAKE_CURRENT_SOURCE_DIR}/../../../oh_modules")
676
+ +set(RNOH_CPP_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../../../../../../react-native-harmony/harmony/cpp")
677
+ +set(LOG_VERBOSITY_LEVEL 1)
678
+ +set(CMAKE_ASM_FLAGS "-Wno-error=unused-command-line-argument -Qunused-arguments")
679
+ +set(CMAKE_CXX_FLAGS "-fstack-protector-strong -Wl,-z,relro,-z,now,-z,noexecstack -s -fPIE -pie")
680
+ +set(WITH_HITRACE_SYSTRACE 1) # for other CMakeLists.txt files to use
681
+ +add_compile_definitions(WITH_HITRACE_SYSTRACE)
682
+ +
683
+ +add_subdirectory("${RNOH_CPP_DIR}" ./rn)
684
+ +
685
+ +# RNOH_BEGIN: manual_package_linking_1
686
+ +add_subdirectory("../../../../sample_package/src/main/cpp" ./sample-package)
687
+ ++ add_subdirectory("${OH_MODULES}/@react-native
688
+ ... [diff 已截断]
689
+ ```
690
+
691
+ ### `README_en.md`
692
+
693
+ ```diff
694
+ @@ -0,0 +1,754 @@
695
+ +> Template version: v0.2.2
696
+ +
697
+ +<p align="center">
698
+ + <h1 align="center"> <code>react-native-audio-recorder-player</code> </h1>
699
+ +</p>
700
+ +<p align="center">
701
+ + <a href="https://github.com/hyochan/react-native-audio-recorder-player">
702
+ + <img src="https://img.shields.io/badge/platforms-android%20|%20ios%20|%20harmony%20-lightgrey.svg" alt="Supported platforms" />
703
+ + </a>
704
+ + <a href="https://github.com/hyochan/react-native-audio-recorder-player/blob/main/LICENSE">
705
+ + <img src="https://img.shields.io/badge/license-MIT-green.svg" alt="License" />
706
+ + </a>
707
+ +</p>
708
+ +
709
+ +> [!TIP] [ GitHub address](https://github.com/react-native-oh-library/react-native-audio-recorder-player)
710
+ +
711
+ +## Installation and Usage
712
+ +
713
+ +Please refer to the Releases page of the third-party library for the corresponding version information
714
+ +
715
+ +| Third-party Library Version | Release Information | Supported RN Version |
716
+ +| ---------- | ------------------------------------------------------------ | ---------- |
717
+ +| <= 3.6.10-0.0.2@deprecated | [@react-native-oh-tpl/react-native-audio-recorder-player Releases(deprecated)](https://github.com/react-native-oh-library/react-native-audio-recorder-player/releases) | 0.72 |
718
+ +| 3.6.11 | [@react-native-ohos/react-native-audio-recorder-player Releases](https://gitcode.com/openharmony-sig/rntpc_react-native-audio-recorder-player/releases) | 0.72 |
719
+ +| 3.7.0 | [@react-native-ohos/react-native-audio-recorder-player Releases](https://gitcode.com/openharmony-sig/rntpc_react-native-audio-recorder-player/releases) | 0.77 |
720
+ +
721
+ +For older versions that are not published to npm, please refer to the [installation guide](/tgz-usage-en.md) to install the tgz package.
722
+ +
723
+ +Go to the project directory and execute the following instruction:
724
+ +
725
+ +
726
+ +
727
+ +#### **npm**
728
+ +
729
+ +```bash
730
+ +npm install @react-native-ohos/react-native-audio-recorder-player
731
+ +```
732
+ +
733
+ +#### **yarn**
734
+ +
735
+ +```bash
736
+ +yarn add @react-native-ohos/react-native-audio-recorder-player
737
+ +```
738
+ +
739
+ +The following code shows the basic use scenario of the repository:
740
+ +
741
+ +> [!WARNING] The name of the imported repository remains unchanged.
742
+ +
743
+ +```js
744
+ +import AudioRecorderPlayer, {
745
+ + AVEncoderAudioQualityIOSType,
746
+ + AVEncodingOption,
747
+ + AudioEncoderAndroidType,
748
+ + AudioSourceAndroidType,
749
+ + OutputFormatAndroidType,
750
+ +} from 'react-native-audio-recorder-player'; import type {
751
+ + PlayBackType,
752
+ + RecordBackType,
753
+ +} from 'react-native-audio-recorder-player';
754
+ +import { AudioMimeHarmonyType, AudioFormatHarmonyType, AudioSourceHarmonyType, AudioSet } from "react-native-audio-recorder-player";
755
+ +
756
+ +import {
757
+ + Dimensions,
758
+ + Platform,
759
+ + ActivityIndicator,
760
+ + Image,
761
+ + SafeAreaView,
762
+ + StyleSheet,
763
+ + Text,
764
+ + TouchableOpacity,
765
+ + View,
766
+ +} from 'react-native';
767
+ +import React, { Component } from 'react';
768
+ +
769
+ +import type { ReactElement, ReactNode } from 'react';
770
+ +
771
+ +const stylesButton: any = StyleSheet.create({
772
+ + btn: {
773
+ + backgroundColor: 'transparent',
774
+ + alignSelf: 'center',
775
+ + borderRadius: 4,
776
+ + borderWidth: 2,
777
+ + width: 320,
778
+ + height: 52,
779
+ + borderColor: 'white',
780
+ +
781
+ + alignItems: 'center',
782
+ + justifyContent: 'center',
783
+ + },
784
+ + btnDisabled: {
785
+ + backgroundColor: 'rgb(243,243,243)',
786
+ + alignSelf: 'center',
787
+ + borderRadius: 4,
788
+ + borderWidth: 2,
789
+ + width: 320,
790
+ + height: 52,
791
+ + borderColor: '#333',
792
+ +
793
+ + alignItems: 'center',
794
+ + justifyContent: 'center',
795
+ + },
796
+ + txt: {
797
+ + fontSize: 14,
798
+ + color: 'white',
799
+ + },
800
+ + imgLeft: {
801
+ + width: 24,
802
+ + height: 24,
803
+ + position: 'absolute',
804
+ + left: 16,
805
+ + },
806
+ +});
807
+ +
808
+ +interface ItemProps {
809
+ + children?: ReactNode;
810
+ + isLoading?: boolean;
811
+ + isDisabled?: boolean;
812
+ + onPress?: () => void;
813
+ + style?: any;
814
+ + disabledStyle?: any;
815
+ + textStyle?: any;
816
+ + imgLeftSrc?: any;
817
+ + imgLeftStyle?: any;
818
+ + indicatorColor?: string;
819
+ + activeOpacity?: number;
820
+ +}
821
+ +
822
+ +class Button extends Component<ItemProps, any> {
823
+ + private static defaultProps: Partial<ItemProps> = {
824
+ + isLoading: false,
825
+ + isDisabled: false,
826
+ + style: stylesButton.btn,
827
+ + textStyle: stylesButton.txt,
828
+ + imgLeftStyle: stylesButton.imgLeft,
829
+ + indicatorColor: 'white',
830
+ + activeOpacity: 0.5,
831
+ + };
832
+ +
833
+ + constructor(props: ItemProps) {
834
+ + super(props);
835
+ + this.state = {};
836
+ + }
837
+ +
838
+ + public render(): ReactElement {
839
+ + if (this.props.isDisabled) {
840
+ + return (
841
+ + <View style={this.props.disabledStyle}>
842
+ + <Text style={this.props.textStyle}>{this.props.children}</Text>
843
+ + </View>
844
+ + );
845
+ + }
846
+ +
847
+ + if (this.props.isLoading) {
848
+ + return (
849
+ + <View style={this.props.style}>
850
+ + <ActivityIndicator size="small" color={this.props.indicatorColor} />
851
+ + </View>
852
+ + );
853
+ + }
854
+ +
855
+ + return (
856
+ + <TouchableOpacity
857
+ + activeOpacity={this.props.activeOpacity}
858
+ + onPress={this.props.onPress}>
859
+ + <View style={this.props.style}>
860
+ + {this.props.imgLeftSrc ? (
861
+ + <Image
862
+ + style={this.props.imgLeftStyle}
863
+ + source={this.props.imgLeftSrc}
864
+ + />
865
+ + ) : null}
866
+ + <Text style={this.props.textStyle}>{this.props.children}</Text>
867
+ + </View>
868
+ + </TouchableOpacity>
869
+ + );
870
+ + }
871
+ +}
872
+ +
873
+ +const styles: any = StyleSheet.create({
874
+ + container: {
875
+ + flex: 1,
876
+ + backgroundColor: '#455A64',
877
+ + flexDirection: 'column',
878
+ + alignItems: 'center',
879
+ + height: Dimensions.get('screen').height
880
+ + },
881
+ + titleTxt: {
882
+ + marginTop: 100,
883
+ + color: 'white',
884
+ + fontSize: 28,
885
+ + },
886
+ + viewRecorder: {
887
+ + marginTop: 40,
888
+ + width: '100%',
889
+ + alignItems: 'center',
890
+ + },
891
+ + recordBtnWrapper: {
892
+ + flexDirection: 'row',
893
+ + },
894
+ + viewPlayer: {
895
+ + marginTop: 60,
896
+ + alignSelf: 'stretch',
897
+ + alignItems: 'center',
898
+ + },
899
+ + viewBarWrapper: {
900
+ + marginTop: 28,
901
+ + marginHorizontal: 28,
902
+ + alignSelf: 'stretch',
903
+ + },
904
+ + viewBar: {
905
+ + backgroundColor: '#ccc',
906
+ + height: 4,
907
+ + alignSelf: 'stretch',
908
+ + },
909
+ + viewBarPlay: {
910
+ + backgroundColor: 'white',
911
+ + height: 4,
912
+ + width: 0,
913
+ + },
914
+ + playStatusTxt: {
915
+ + marginTop: 8,
916
+ + color: '#ccc',
917
+ + },
918
+ + playBtnWrapper: {
919
+ + flexDirection: 'row',
920
+ + marginTop: 40,
921
+ + },
922
+ + btn: {
923
+ + borderColor: 'white',
924
+ + borderWidth: 1,
925
+ + },
926
+ + txt: {
927
+ + color: 'white',
928
+ + fontSize: 14,
929
+ + marginHorizontal: 8,
930
+ + marginVertical: 4,
931
+ + },
932
+ + txtRecordCounter: {
933
+ + marginTop: 32,
934
+ + color: 'white',
935
+ + fontSize: 20,
936
+ + textAlignVertical: 'center',
937
+ + fontWeight: '200',
938
+ + fontFamily: 'Helvetica Neue',
939
+ + letterSpacing: 3,
940
+ + width: 300
941
+ + },
942
+ + txtCounter: {
943
+ + marginTop: 12,
944
+ + color: 'white',
945
+ + fontSize: 20,
946
+ + textAlignVertical: 'center',
947
+ + fontWeight: '200',
948
+ + fontFamily: 'Helvetica Neue',
949
+ + letterSpacing: 3,
950
+ + width: 300
951
+ + },
952
+ +});
953
+ +
954
+ +interface State {
955
+ + isLoggingIn: boolean;
956
+ + recordSecs: number;
957
+ + recordTime: string;
958
+ + currentPositionSec: number;
959
+ + currentDurationSec: number;
960
+ + playTime: string;
961
+ + duration: string;
962
+ +}
963
+ +
964
+ +const screenWidth = Dimensions.get('screen').width;
965
+ +
966
+ +class Page extends Component<any, State> {
967
+ + private audioRecorderPlayer
968
+ +
969
+ + constructor(props: any) {
970
+ + super(props);
971
+ + this.state = {
972
+ + isLoggingIn: false,
973
+ + recordSecs: 0,
974
+ + recordTime: '00:00:00',
975
+ + currentPositionSec: 0,
976
+ + currentDurationSec: 0,
977
+ + playTime: '00:00:00',
978
+ + duration: '00:00:00',
979
+ + };
980
+ +
981
+ + this.audioRecorderPlayer = new AudioRecorderPlayer()
982
+ + this.audioRecorderPlayer.setSubscriptionDuration(0.5); // optional. Default is 0.5
983
+ + }
984
+ +
985
+ + public render(): ReactElement {
986
+ + let playWidth =
987
+ + (this.state.currentPositionSec / this.state.currentDurationSec) *
988
+ + (screenWidth - 56);
989
+ +
990
+ + if (!playWidth) {
991
+ + playWidth = 0;
992
+ + }
993
+ +
994
+ + return (
995
+ + <SafeAreaView style={styles.container}>
996
+ + <Text style={styles.titleTxt}>Audio Recorder Player</Text>
997
+ + <Text style={styles.txtRecordCounter}>{this.state.recordTime}</Text>
998
+ + <View style={styles.viewRecorder}>
999
+ + <View style={styles.recordBtnWrapper}>
1000
+ + <Button
1001
+ + style={styles.btn}
1002
+ + onPress={this.onStartRecord}
1003
+ + textStyle={styles.txt}>
1004
+ + startRecord
1005
+ + </Button>
1006
+ + <Button
1007
+ + style={[
1008
+ + styles.btn,
1009
+ + {
1010
+ + marginLeft: 12,
1011
+ + },
1012
+ + ]}
1013
+ + onPress={this.onPauseRecord}
1014
+ + textStyle={styles.txt}>
1015
+ + Pause
1016
+ + </Button>
1017
+ + <Button
1018
+ + style={[
1019
+ + styles.btn,
1020
+ + {
1021
+ + marginLeft: 12,
1022
+ + },
1023
+ + ]}
1024
+ + onPress={this.onResumeRecord}
1025
+ + textStyle={styles.txt}>
1026
+ + Resume
1027
+ + </Button>
1028
+ + <Button
1029
+ + style={[styles.btn, { marginLeft: 12 }]}
1030
+ + onPress={this.onStopRecord}
1031
+ + textStyle={styles.txt}>
1032
+ + Stop
1033
+ + </Button>
1034
+ + </View>
1035
+ + </View>
1036
+ + <View style={styles.viewPlayer}>
1037
+ + <TouchableOpacity
1038
+ + style={styles.viewBarWrapper}
1039
+ + onPress={this.onStatusPress}>
1040
+ + <View style={styles.viewBar}>
1041
+ + <View style={[styles.viewBarPlay, { width: playWidth }]} />
1042
+ + </View>
1043
+ + </TouchableOpacity>
1044
+ + <Text style={styles.txtCounter}>
1045
+ + {this.state.playTime} / {this.state.duration}
1046
+ + </Text>
1047
+ + <View style={styles.playBtnWrapper}>
1048
+ + <Button
1049
+ + style={styles.btn}
1050
+ + onPress={this.onStartPlay}
1051
+ + textStyle={styles.txt}>
1052
+ + Play
1053
+ + </Button>
1054
+ + <Button
1055
+ + style={[
1056
+ + styles.btn,
1057
+ + {
1058
+ + marginLeft: 12,
1059
+ + },
1060
+ + ]}
1061
+ + onPress={this.onPausePlay}
1062
+ + textStyle={styles.txt}>
1063
+ + Pause
1064
+ + </Button>
1065
+ + <Button
1066
+ + style={[
1067
+ + styles.btn,
1068
+ + {
1069
+ + marginLeft: 12,
1070
+ + },
1071
+ + ]}
1072
+ + onPress={this.onResumePlay}
1073
+ + textStyle={styles.txt}>
1074
+ + Resume
1075
+ + </Button>
1076
+ + <Button
1077
+ + style={[
1078
+ + styles.btn,
1079
+ + {
1080
+ + marginLeft: 12,
1081
+ + },
1082
+ + ]}
1083
+ + onPress={this.onStopPlay}
1084
+ + textStyle={styles.txt}>
1085
+ + Stop
1086
+ + </Button>
1087
+ + </View>
1088
+ + </View>
1089
+ + </SafeAreaView>
1090
+ + );
1091
+ + }
1092
+ +
1093
+ + private onStatusPress = (e: any): void => {
1094
+ + const touchX = e.nativeEvent.locationX;
1095
+ + console.log(`touchX: ${touchX}`);
1096
+ +
1097
+ + const playWidth =
1098
+ + (this.state.currentPositionSec / this.state.currentDurationSec) *
1099
+ + (screenWidth - 56);
1100
+ + console.log(`currentPlayWidth: ${playWidth}`);
1101
+ +
1102
+ + const currentPosition = Math.round(this.state.currentPositionSec);
1103
+ +
1104
+ + if (playWidth && playWidth < touchX) {
1105
+ + const addSecs = Math.round(currentPosition + 1000);
1106
+ + this.audioRecorderPlayer.seekToPlayer(addSecs);
1107
+ + console.log(`addSecs: ${addSecs}`);
1108
+ + } else {
1109
+ + const subSecs = Math.round(currentPosition - 1000);
1110
+ + this.audioRecorderPlayer.seekToPlayer(subSecs);
1111
+ + console.log(`subSecs: ${subSecs}`);
1112
+ + }
1113
+ + };
1114
+ +
1115
+ + private onStartRecord = async (): Promise<void> => {
1116
+ +
1117
+ + const audioSet: AudioSet = {
1118
+ + AudioEncoderAndroid: AudioEncoderAndroidType.AAC,
1119
+ + AudioSourceAndroid: AudioSourceAndroidType.MIC,
1120
+ + AVEncoderAudioQualityKeyIOS: AVEncoderAudioQualityIOSType.high,
1121
+ + AVNumberOfChannelsKeyIOS: 2,
1122
+ + AVFormatIDKeyIOS: AVEncodingOption.aac,
1123
+ + OutputFormatAndroid: OutputFormatAndroidType.AAC_ADTS,
1124
+ + AudioSourceHarmony: AudioSourceHarmonyType.MIC,
1125
+ + AudioMimeHarmony: AudioMimeHarmonyType.AUDIO_AAC,
1126
+ + AudioFileFormatHarmony: AudioFormatHarmonyType.MPEG_4A,
1127
+ + AudioEncodingBitRateHarmony: 3200,
1128
+ + AudioSamplingRateHarmony: 44100,
1129
+ + AudioChannelsHarmony: 2,
1130
+ + };
1131
+ +
1132
+ + console.log('audioSet', audioSet);
1133
+ +
1134
+ + const uri = await this.audioRecorderPlayer.startRecorder(
1135
+ + 'audio.m4a',
1136
+ + audioSet,
1137
+ + );
1138
+ +
1139
+ + this.audioRecorderPlayer.addRecordBackListener((e: RecordBackType) => {
1140
+ + console.log('record-back', e);
1141
+ + this.setState({
1142
+ + recordSecs: e.currentPosition,
1143
+ + recordTime: this.audioRecorderPlayer.mmssss(
1144
+ + Math.floor(e.currentPosition),
1145
+ + ),
1146
+ + });
1147
+ + });
1148
+ +
1149
+ + console.log(`uri: ${uri}`);
1150
+ + };
1151
+ +
1152
+ + private onPauseRecord = async (): Promise<void> => {
1153
+ + try {
1154
+ + const r = await this.audioRecorderPlayer.pauseRecorder();
1155
+ + console.log(r);
1156
+ + } catch (err) {
1157
+ + console.log('pauseRecord', err);
1158
+ + }
1159
+ + };
1160
+ +
1161
+ + private onResumeRecord = async (): Promise<void> => {
1162
+ + await this.audioRecorderPlayer.resumeRecorder();
1163
+ + };
1164
+ +
1165
+ + private onStopRecord = async (): Promise<void> => {
1166
+ + const result = await this.audioRecorderPlayer.stopRecorder();
1167
+ + this.audioRecorderPlayer.removeRecordBackListener();
1168
+ + this.setState({
1169
+ + recordSecs: 0,
1170
+ + });
1171
+ + console.log(result, '>>>>>>>stopRecorder');
1172
+ + };
1173
+ +
1174
+ + private onStartPlay = async (): Promise<void> => {
1175
+ + console.log('onStartPlay');
1176
+ +
1177
+ + try {
1178
+ +
1179
+ +
1180
+ + const msg = await this.audioRecorderPlayer.startPlayer('https://sis-sample-audio.obs.cn-north-1.myhuaweicloud.com/16k16bit.mp3', { 'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:12.0) Gecko/20100101 Firefox/21.0' });
1181
+ + const volume = await this.audioRecorderPlayer.setVolume(1);
1182
+ + this.audioRecorderPlayer.addPlayBackListener((e: PlayBackType) => {
1183
+ + console.log('playBackListener', e);
1184
+ + this.setState({
1185
+ + currentPositionSec: e.currentPosition,
1186
+ + currentDurationSec: e.duration,
1187
+ + playTime: this.audioRecorderPlayer.mmssss(e.currentPosition),
1188
+ + duration: this.audioRecorderPlayer.mmssss(Math.floor(e.duration)),
1189
+ + });
1190
+ + });
1191
+ +
1192
+ + } catch (err) {
1193
+ + console.log('startPlayer error', err);
1194
+ + }
1195
+ + };
1196
+ +
1197
+ + private onPausePlay = async (): Promise<void> => {
1198
+ + await this.audioRecorderPlayer.pausePlayer();
1199
+ + };
1200
+ +
1201
+ + private onResumePlay = async (): Promise<void> => {
1202
+ + await this.audioRecorderPlayer.resumePlayer();
1203
+ + };
1204
+ +
1205
+ + private onStopPlay = async (): Promise<void> => {
1206
+ + console.log('onStopPlay');
1207
+ + this.audioRecorderPlayer.stopPlayer();
1208
+ + this.audioRecorderPlayer.removePlayBackListener();
1209
+ + };
1210
+ +}
1211
+ +
1212
+ +export default Page;
1213
+ +
1214
+ +```
1215
+ +
1216
+ +## Link
1217
+ +
1218
+ +| | Is supported autolink | Supported RN Version |
1219
+ +|--------------------------------------|-----------------------|----------------------|
1220
+ +| ~3.7.0 | No | 0.77 |
1221
+ +| ~3.6.11 | Yes | 0.72 |
1222
+ +| <= 3.6.10-0.0.2@deprecated | No | 0.72 |
1223
+ +
1224
+ +Using AutoLink need to be configured according to this document, Autolink Framework Guide Documentation: https://gitcode.com/openharmony-sig/ohos_react_native/blob/master/docs/zh-cn/Autolinking.md
1225
+ +
1226
+ +If the version you use supports Autolink and the project has been connected to Autolink, skip the ManualLink configuration.
1227
+ +<details>
1228
+ + <summary>ManualLink: this step is a guide to manually configure native dependencies.</summary>
1229
+ +
1230
+ +First, use DevEco Studio to open the HarmonyOS project `harmony` in the project directory.
1231
+ +
1232
+ +### Adding the overrides Field to `oh-package.json5 File` in the Root Directory of the Project
1233
+ +
1234
+ +```json
1235
+ +{
1236
+ + ...
1237
+ + "overrides": {
1238
+ + "@rnoh/react-native-openharmony" : "./react_native_openharmony"
1239
+ + }
1240
+ +}
1241
+ +```
1242
+ +
1243
+ +### Introducing Native Code
1244
+ +
1245
+ +Currently, two methods are available:
1246
+ +
1247
+ +Method 1 (recommended): Use the HAR file.
1248
+ +
1249
+ +> [!TIP] The HAR file is stored in the `harmony` directory in the installation path of the third-party library.
1250
+ +
1251
+ +Open `entry/oh-package.json5` file and add the following dependencies:
1252
+ +
1253
+ +```json
1254
+ +"dependencies": {
1255
+ + "@rnoh/react-native-openharmony": "file:../react_native_openharmony",
1256
+ +
1257
+ + "@react-native-ohos/react-native-audio-recorder-player": "file:../../node_modules/@react-native-ohos/react-native-audio-recorder-player/harmony/audio_recorder_player.har"
1258
+ + }
1259
+ +```
1260
+ +
1261
+ +Click the `sync` button in the upper right corner.
1262
+ +
1263
+ +Alternatively, run the following instruction on the terminal:
1264
+ +
1265
+ +```bash
1266
+ +cd entry
1267
+ +ohpm install
1268
+ +```
1269
+ +
1270
+ +Method 2: Directly link to the source code.
1271
+ +
1272
+ +> [!TIP] or details, see [Directly Linking Source Code](/link-source-code.md).
1273
+ +
1274
+ +### Configuring CMakeLists and Introducing RNAudioRecorderPlayerPackage
1275
+ +
1276
+ +> If you are using version <= 3.6.10-0.0.2, please skip this chapter.
1277
+ +
1278
+ +Open `entry/src/main/cpp/CMakeLists.txt` and add the following code:
1279
+ +
1280
+ +```diff
1281
+ +project(rnapp)
1282
+ +cmake_minimum_required(VERSION 3.4.1)
1283
+ +set(CMAKE_SKIP_BUILD_RPATH TRUE)
1284
+ +set(RNOH_APP_DIR "${CMAKE_CURRENT_SOURCE_DIR}")
1285
+ +set(NODE_MODULES "${CMAKE_CURRENT_SOURCE_DIR}/../../../../../node_modules")
1286
+ ++ set(OH_MODULES "${CMAKE_CURRENT_SOURCE_DIR}/../../../oh_modules")
1287
+ +set(RNOH_CPP_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../../../../../../react-native-harmony/harmony/cpp")
1288
+ +set(LOG_VERBOS
1289
+ ... [diff 已截断]
1290
+ ```
1291
+
1292
+ ### `buildEnv.sh`
1293
+
1294
+ ```diff
1295
+ @@ -0,0 +1,8 @@
1296
+ +#!/bin/bash
1297
+ +BUILD_PKG_DIR=example
1298
+ +BUILD_SAMPLE_DIR=example/harmony
1299
+ +BUILD_THIRD_PARTY_DIR=harmony/
1300
+ +
1301
+ +# BUILD_PKG_DIR: 用来打 tgz 包的工程目录
1302
+ +# BUILD_SAMPLE_DIR:用来打 har 包的目录
1303
+ +# BUILD_THIRD_PARTY_DIR:库模块源码目录
1304
+
1305
+ ```
1306
+
1307
+ ### `example/harmony/build-profile.template.json5`
1308
+
1309
+ ```diff
1310
+ @@ -4,9 +4,13 @@
1311
+ {
1312
+ "name": 'default',
1313
+ "signingConfig": 'default',
1314
+ - "compileSdkVersion": '5.0.1(13)',
1315
+ "compatibleSdkVersion": '5.0.0(12)',
1316
+ - "runtimeOS": 'HarmonyOS'
1317
+ + "runtimeOS": 'HarmonyOS',
1318
+ + "buildOption": {
1319
+ + "strictMode": {
1320
+ + "useNormalizedOHMUrl": true
1321
+ + }
1322
+ + }
1323
+ },
1324
+ ],
1325
+ "buildModeSet": [
1326
+ @@ -31,6 +35,10 @@
1327
+ ],
1328
+ },
1329
+ ],
1330
+ + },
1331
+ + {
1332
+ + "name": 'audio_recorder_player',
1333
+ + "srcPath": '../../harmony/audio_recorder_player'
1334
+ }
1335
+ ],
1336
+ }
1337
+
1338
+
1339
+ ```
1340
+
1341
+ ### `example/harmony/entry/oh-package.json5`
1342
+
1343
+ ```diff
1344
+ @@ -5,7 +5,7 @@
1345
+ "description": "example description",
1346
+ "version": "1.0.0",
1347
+ "dependencies": {
1348
+ - "@rnoh/react-native-openharmony": "file:../../node_modules/react-native-harmony/harmony/react_native_openharmony.har",
1349
+ + "@rnoh/react-native-openharmony": "file:../../node_modules/react-native-harmony/react_native_openharmony.har",
1350
+ "@react-native-ohos/react-native-audio-recorder-player": "file:../../node_modules/@react-native-ohos/react-native-audio-recorder-player/harmony/audio_recorder_player.har"
1351
+ }
1352
+ }
1353
+
1354
+
1355
+ ```
1356
+
1357
+ ### `example/harmony/oh-package.json5`
1358
+
1359
+ ```diff
1360
+ @@ -6,7 +6,7 @@
1361
+ "repository": {},
1362
+ "version": "1.0.0",
1363
+ "overrides": {
1364
+ - "@rnoh/react-native-openharmony": "file:./../node_modules/react-native-harmony/harmony/react_native_openharmony.har"
1365
+ + "@rnoh/react-native-openharmony": "file:./../node_modules/react-native-harmony/react_native_openharmony.har"
1366
+ },
1367
+ "dynamicDependencies": {}
1368
+ }
1369
+
1370
+
1371
+ ```
1372
+
1373
+ ### `example/index.js`
1374
+
1375
+ ```diff
1376
+ @@ -0,0 +1,11 @@
1377
+ +/*
1378
+ + * Copyright (c) 2024 Huawei Device Co., Ltd. All rights reserved
1379
+ + * Use of this source code is governed by a MIT license that can be
1380
+ + * found in the LICENSE file.
1381
+ + */
1382
+ +
1383
+ +import {AppRegistry, View, Text} from 'react-native';
1384
+ +import {name as appName} from './app.json';
1385
+ +import App from './src/index';
1386
+ +
1387
+ +AppRegistry.registerComponent(appName, () => App);
1388
+
1389
+
1390
+ ```
1391
+
1392
+ ### `example/package.json`
1393
+
1394
+ ```diff
1395
+ @@ -8,18 +8,19 @@
1396
+ "start": "hdc rport tcp:8081 tcp:8081 && react-native start",
1397
+ "codegen": "react-native codegen-harmony --rnoh-module-path ./harmony/entry/oh_modules/@rnoh/react-native-openharmony",
1398
+ "pack:pkg": "cd ../ && npm pack && cd ./example",
1399
+ - "install:pkg": "npm uninstall @react-native-ohos/react-native-audio-recorder-player && npm run pack:pkg && npm i @react-native-ohos/react-native-audio-recorder-player@file:../react-native-ohos-react-native-audio-recorder-player-3.6.14-rc.1.tgz",
1400
+ + "install:pkg": "npm uninstall @react-native-ohos/react-native-audio-recorder-player && npm run pack:pkg && npm i @react-native-ohos/react-native-audio-recorder-player@file:../react-native-ohos-react-native-audio-recorder-player-3.7.0.tgz",
1401
+ "dev": "npm run codegen && react-native bundle-harmony --dev --minify=false",
1402
+ "prod": "npm run codegen && react-native bundle-harmony --dev=false --minify=true",
1403
+ "postinstall": "node ./scripts/create-build-profile",
1404
+ - "fast:pkg": "cd ../ && npm i --legacy-peer-deps && npm pack && cd ./example && npm i && npm run dev"
1405
+ + "fast-install-project": "cd ../ && npm i --force && npm run pack && rm -r node_modules && cd ./example && npm i --force",
1406
+ + "fast:pkg": "npm run fast-install-project && npm run dev"
1407
+ },
1408
+ "dependencies": {
1409
+ "@gorhom/portal": "^1.0.14",
1410
+ - "@react-native-ohos/react-native-audio-recorder-player": "file:../react-native-ohos-react-native-audio-recorder-player-3.6.14-rc.1.tgz",
1411
+ + "@react-native-ohos/react-native-audio-recorder-player": "file:../react-native-ohos-react-native-audio-recorder-player-3.7.0.tgz",
1412
+ "react": "18.3.1",
1413
+ "react-native": "0.77.1",
1414
+ - "react-native-harmony": "file:../packages/rnoh-react-native-harmony-0.77.10.tgz",
1415
+ + "react-native-harmony": "npm:@react-native-oh/react-native-harmony@0.77.18-1",
1416
+ "react-native-reanimated": "^3.6.0"
1417
+ },
1418
+ "devDependencies": {
1419
+ @@ -34,7 +35,7 @@
1420
+ "@react-native/eslint-config": "0.77.1",
1421
+ "@react-native/metro-config": "^0.77.1",
1422
+ "@react-native/typescript-config": "0.77.1",
1423
+ - "@rnoh/react-native-harmony-cli": "file:../packages/rnoh-react-native-harmony-cli-0.77.10.tgz",
1424
+ + "@rnoh/react-native-harmony-cli": "npm:@react-native-oh/react-native-harmony-cli@0.77.18-1",
1425
+ "@tsconfig/react-native": "^3.0.0",
1426
+ "@types/d3-scale-chromatic": "^3.0.0",
1427
+ "@types/jest": "^29.5.13",
1428
+
1429
+ ```
1430
+
1431
+ ### `harmony/audio_recorder_player.har`
1432
+
1433
+ ```diff
1434
+ Binary files no preview for this file type
1435
+ ```
1436
+
1437
+ ### `harmony/audio_recorder_player/src/main/ets/RNAudioRecorderPlayerTurboModule.ts`
1438
+
1439
+ ```diff
1440
+ @@ -23,7 +23,7 @@
1441
+ */
1442
+ import { TurboModule, TurboModuleContext, } from '@rnoh/react-native-openharmony/ts';
1443
+ import { media } from '@kit.MediaKit';
1444
+ -import { AudioSet } from '.';
1445
+ +import type { AudioSet } from '.';
1446
+ import Recorder from './recorder/Recorder';
1447
+ import { AVRecorderState, defaultBitrate, defaultChannels, defaultSampleRate, RecordBackName, } from './recorder/types';
1448
+ import AudioPlayer from './audioPlayer/AudioPlayer';
1449
+
1450
+ ```
1451
+
1452
+ ### `harmony/audio_recorder_player/src/main/ets/index.ts`
1453
+
1454
+ ```diff
1455
+ The file is empty
1456
+ ```
1457
+
1458
+ ### `index.ts`
1459
+
1460
+ ```diff
1461
+ @@ -29,7 +29,8 @@ export enum AudioFormatHarmonyType {
1462
+ MPEG_4 = 'mp4',
1463
+ MPEG_4A = 'm4a',
1464
+ MP3 = 'mp3',
1465
+ - WAV = 'wav'
1466
+ + WAV = 'wav',
1467
+ + AAC = 'aac'
1468
+ }
1469
+
1470
+ export enum AudioMimeHarmonyType {
1471
+
1472
+ ```
1473
+
1474
+ ### `package.json`
1475
+
1476
+ ```diff
1477
+ @@ -9,7 +9,8 @@
1478
+ "scripts": {
1479
+ "test": "echo \"Error: no test specified\" && exit 1",
1480
+ "build": "tsc && flowgen index.d.ts -o index.js.flow",
1481
+ - "lint": "eslint -c .eslintrc.js 'index.ts'"
1482
+ + "lint": "eslint -c .eslintrc.js 'index.ts'",
1483
+ + "pack": "npm pack --ignore-scripts"
1484
+ },
1485
+ "harmony": {
1486
+ "alias": "react-native-audio-recorder-player"
1487
+
1488
+ ```