@ohos-cpf/3rdloop 0.0.2 → 0.0.3
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.
- package/README.md +244 -244
- package/bin/3rdloop.mjs +46 -46
- package/lib/cli.js +781 -781
- package/lib/config-cmd.js +451 -451
- package/lib/config.js +318 -318
- package/lib/doctor.js +113 -113
- package/lib/exit-codes.js +30 -30
- package/lib/opencode.js +155 -155
- package/lib/orch.js +426 -426
- package/lib/queries.js +263 -263
- package/lib/step.js +325 -325
- package/lib/ui.js +222 -222
- package/lib/update.js +279 -279
- package/lib/workflow.js +308 -308
- package/lib/workflows.js +131 -131
- package/package.json +50 -50
- package/vendor/Server/Agent/SkillSelector/README.md +343 -343
- package/vendor/Server/Agent/SkillSelector/core/Agent.js +207 -207
- package/vendor/Server/Agent/SkillSelector/index.js +14 -14
- package/vendor/Server/Agent/SkillSelector/llm/llmClient.js +313 -313
- package/vendor/Server/Agent/SkillSelector/llm/prompts.js +161 -161
- package/vendor/Server/Agent/SkillSelector/llm/reactSteps.js +144 -144
- package/vendor/Server/Agent/SkillSelector/matcher/fuzzyMatcher.js +433 -433
- package/vendor/Server/Agent/SkillSelector/scanner/skillScanner.js +382 -382
- package/vendor/Server/Agent/SkillSelector/utils/actionWords.js +59 -59
- package/vendor/Server/Brain/AnalysisStrategies.js +422 -422
- package/vendor/Server/Brain/Brain.js +686 -686
- package/vendor/Server/Brain/DecompositionStrategies.js +621 -621
- package/vendor/Server/Brain/PlanPersistence.js +196 -196
- package/vendor/Server/Brain/SkillExecutor.js +251 -251
- package/vendor/Server/Brain/index.js +11 -11
- package/vendor/Server/CLI/cli.js +275 -275
- package/vendor/Server/CLI/deveco-code/index.js +71 -71
- package/vendor/Server/CLI/deveco-code.js +5 -5
- package/vendor/Server/CLI/opencode/index.js +817 -818
- package/vendor/Server/CLI/opencode.js +5 -5
- package/vendor/Server/DbUse/MessageArchive.js +61 -61
- package/vendor/Server/DbUse/StorageManager.js +107 -107
- package/vendor/Server/DbUse/adapters/BaseAdapter.js +94 -94
- package/vendor/Server/DbUse/adapters/FileAdapter.js +138 -138
- package/vendor/Server/DbUse/adapters/JsonAdapter.js +138 -138
- package/vendor/Server/DbUse/adapters/JsonlAdapter.js +114 -114
- package/vendor/Server/DbUse/adapters/SqliteAdapter.js +157 -157
- package/vendor/Server/DbUse/index.js +160 -160
- package/vendor/Server/DbUse/stores/SessionStore.js +279 -279
- package/vendor/Server/DbUse/stores/TaskExecutionStore.js +133 -133
- package/vendor/Server/DbUse/stores/TaskRegistryStore.js +262 -262
- package/vendor/Server/DbUse/stores/TaskStepStore.js +279 -279
- package/vendor/Server/FlexRunner/FlexRunner.js +1759 -1759
- package/vendor/Server/FlexRunner/index.js +12 -12
- package/vendor/Server/Knowledge/KnowledgeImporter.js +523 -523
- package/vendor/Server/Knowledge/KnowledgeManager.js +341 -341
- package/vendor/Server/Knowledge/index.js +33 -33
- package/vendor/Server/LoopEngine/LoopEngine.js +1133 -1133
- package/vendor/Server/LoopEngine/index.js +11 -11
- package/vendor/Server/Orchestrator/Orchestrator.js +0 -3
- package/vendor/Server/Orchestrator/StepNode.js +312 -312
- package/vendor/Server/Orchestrator/index.js +13 -13
- package/vendor/Server/Routes/controllers/BrainController.js +241 -241
- package/vendor/Server/Routes/controllers/FlexRunnerController.js +1125 -1125
- package/vendor/Server/Routes/controllers/HealthController.js +44 -44
- package/vendor/Server/Routes/controllers/KnowledgeImportController.js +355 -355
- package/vendor/Server/Routes/controllers/LoopEngineController.js +788 -788
- package/vendor/Server/Routes/controllers/StatsController.js +57 -57
- package/vendor/Server/Routes/controllers/StreamController.js +67 -67
- package/vendor/Server/Routes/library/logger.js +179 -179
- package/vendor/Server/Routes/library/zipArchive.js +172 -172
- package/vendor/Server/Routes/router/Router.js +204 -204
- package/vendor/Server/Routes/routes/brain.js +47 -47
- package/vendor/Server/Routes/routes/flexrunner.js +72 -72
- package/vendor/Server/Routes/routes/health.js +28 -28
- package/vendor/Server/Routes/routes/index.js +57 -57
- package/vendor/Server/Routes/routes/knowledge.js +55 -55
- package/vendor/Server/Routes/routes/loopengine.js +58 -58
- package/vendor/Server/Routes/routes/orchestrator.js +61 -61
- package/vendor/Server/Routes/routes/registry.js +97 -97
- package/vendor/Server/Routes/routes/stats.js +23 -23
- package/vendor/Server/Routes/routes/stream.js +30 -30
- package/vendor/Server/Routes/server.js +203 -203
- package/vendor/Server/Routes/sse/SseHub.js +308 -308
- package/vendor/Server/Skills/acceptance-check/SKILL.md +191 -191
- package/vendor/Server/Skills/acceptance-check/references/PHASE1_ARTIFACT_COLLECTION.md +52 -52
- package/vendor/Server/Skills/acceptance-check/references/PHASE2_CRITERIA_EVALUATION.md +77 -77
- package/vendor/Server/Skills/acceptance-check/references/PHASE2_EVIDENCE_VERIFICATION.md +70 -70
- package/vendor/Server/Skills/arkts-code-check/SKILL.md +320 -320
- package/vendor/Server/Skills/arkts-code-check/references/CODE_CHECK_GUIDE.md +210 -210
- package/vendor/Server/Skills/arkts-code-check/references/FILE_TYPE_GUIDE.md +28 -28
- package/vendor/Server/Skills/arkts-code-check/references/PHASE1_INFO_COLLECTION.md +233 -233
- package/vendor/Server/Skills/arkts-code-check/references/REPORT_TEMPLATE.md +219 -219
- package/vendor/Server/Skills/arkts-library-compile-validate/SKILL.md +328 -328
- package/vendor/Server/Skills/arkts-library-compile-validate/scripts/build.ps1 +93 -93
- package/vendor/Server/Skills/arkts-library-compile-validate/scripts/code-linter.cjs +432 -432
- package/vendor/Server/Skills/arkts-library-compile-validate/scripts/migrate.cjs +851 -851
- package/vendor/Server/Skills/arkts-library-compile-validate/scripts/ohpm-switch.cjs +788 -788
- package/vendor/Server/Skills/arkts-library-demo-code/SKILL.md +291 -291
- package/vendor/Server/Skills/arkts-library-demo-code/references/API_SIGNATURE_CHECKS.md +68 -68
- package/vendor/Server/Skills/arkts-library-demo-code/references/BUILD_VALIDATION.md +184 -184
- package/vendor/Server/Skills/arkts-library-demo-code/references/CODE_STANDARDS.md +337 -337
- package/vendor/Server/Skills/arkts-library-demo-code/references/EXAMPLES.md +400 -400
- package/vendor/Server/Skills/arkts-library-demo-code/references/SYSTEM_API_LOOKUP.md +98 -98
- package/vendor/Server/Skills/arkts-library-demo-code/references/TEMPLATE.md +544 -544
- package/vendor/Server/Skills/arkts-library-demo-code/scripts/build.ps1 +93 -93
- package/vendor/Server/Skills/arkts-library-demo-code/scripts/code-linter.cjs +432 -432
- package/vendor/Server/Skills/arkts-library-demo-code/scripts/migrate.cjs +851 -851
- package/vendor/Server/Skills/arkts-library-demo-code/scripts/ohpm-switch.cjs +788 -788
- package/vendor/Server/Skills/arkts-library-demo-coverage/SKILL.md +174 -174
- package/vendor/Server/Skills/arkts-library-demo-scenario/SKILL.md +321 -321
- package/vendor/Server/Skills/arkts-library-demo-scenario/references/EXAMPLES.md +100 -100
- package/vendor/Server/Skills/arkts-library-demo-scenario/references/TEMPLATE.md +185 -185
- package/vendor/Server/Skills/arkts-library-documentation-quality-check/SKILL.md +233 -233
- package/vendor/Server/Skills/arkts-library-documentation-quality-check/assets/REPORT_TEMPLATE.md +102 -102
- package/vendor/Server/Skills/arkts-library-documentation-quality-check/references/CHECK_DIMENSIONS.md +89 -89
- package/vendor/Server/Skills/arkts-library-documentation-quality-check/references/COMPLIANCE_CHECKLIST.md +62 -62
- package/vendor/Server/Skills/arkts-library-documentation-quality-check/references/KB_QUERY_GUIDE.md +107 -107
- package/vendor/Server/Skills/arkts-library-documentation-quality-check/references/MCP_TOOL_DISCOVERY.md +124 -124
- package/vendor/Server/Skills/arkts-library-documentation-quality-check/references/REPORT_TEMPLATE.md +90 -90
- package/vendor/Server/Skills/arkts-library-documentation-quality-check/references/SCORING_FORMULA.md +57 -57
- package/vendor/Server/Skills/arkts-library-documentation-quality-check/scripts/validate-skill.cjs +259 -259
- package/vendor/Server/Skills/arkts-library-interface-spec/SKILL.md +97 -97
- package/vendor/Server/Skills/arkts-library-memory-leak-check/SKILL.md +391 -391
- package/vendor/Server/Skills/arkts-library-source-clone/SKILL.md +113 -113
- package/vendor/Server/Skills/arkts-library-stability-check/SKILL.md +312 -312
- package/vendor/Server/Skills/arkts-library-stability-check/assets/REPORT_TEMPLATE.md +154 -154
- package/vendor/Server/Skills/arkts-library-stability-check/references/CHECKLIST.md +165 -165
- package/vendor/Server/Skills/arkts-library-stability-check/references/CODE_EXAMPLES.md +308 -308
- package/vendor/Server/Skills/arkts-library-stability-check/references/SCORING_RULES.md +90 -90
- package/vendor/Server/Skills/arkts-library-stability-check/scripts/validate-skill.cjs +282 -282
- package/vendor/Server/Skills/arkts-library-test-coverage-check/SKILL.md +360 -360
- package/vendor/Server/Skills/arkts-library-test-coverage-check/assets/REPORT_TEMPLATE.md +145 -145
- package/vendor/Server/Skills/arkts-library-test-coverage-check/references/CHECKLIST.md +252 -252
- package/vendor/Server/Skills/arkts-library-test-coverage-check/references/MCP_TOOL_USAGE.md +114 -114
- package/vendor/Server/Skills/arkts-library-test-coverage-check/scripts/validate-skill.cjs +262 -262
- package/vendor/Server/Skills/arkts-library-xts-code/SKILL.md +455 -455
- package/vendor/Server/Skills/arkts-library-xts-code/assets/report-template.md +60 -60
- package/vendor/Server/Skills/arkts-library-xts-code/references/ACCESS_MODIFIER_PRECHECK.md +76 -76
- package/vendor/Server/Skills/arkts-library-xts-code/references/BUILD_VERIFICATION.md +200 -200
- package/vendor/Server/Skills/arkts-library-xts-code/references/CODE_STANDARDS.md +518 -518
- package/vendor/Server/Skills/arkts-library-xts-code/references/SUBAGENT_PROMPT_TEMPLATE.md +276 -276
- package/vendor/Server/Skills/arkts-library-xts-code/references/SYSTEM_API_LOOKUP.md +92 -92
- package/vendor/Server/Skills/arkts-library-xts-code/references/XTS_TEMPLATE.md +767 -767
- package/vendor/Server/Skills/arkts-library-xts-code/scripts/build.ps1 +93 -93
- package/vendor/Server/Skills/arkts-library-xts-code/scripts/code-linter.cjs +432 -432
- package/vendor/Server/Skills/arkts-library-xts-code/scripts/migrate.cjs +851 -851
- package/vendor/Server/Skills/arkts-library-xts-code/scripts/ohpm-switch.cjs +788 -788
- package/vendor/Server/Skills/arkts-library-xts-code/scripts/precheck-access-modifiers.cjs +221 -221
- package/vendor/Server/Skills/arkts-library-xts-code-fix/SKILL.md +228 -228
- package/vendor/Server/Skills/arkts-library-xts-coverage/SKILL.md +97 -97
- package/vendor/Server/Skills/arkts-library-xts-doc/SKILL.md +194 -194
- package/vendor/Server/Skills/arkts-library-xts-doc/references/EXAMPLES.md +575 -575
- package/vendor/Server/Skills/arkts-library-xts-doc/references/TEMPLATE.md +574 -574
- package/vendor/Server/Skills/arkts-library-xts-doc/references/TESTABILITY_GUIDE.md +182 -182
- package/vendor/Server/Skills/arkts-library-xts-execution/SKILL.md +490 -490
- package/vendor/Server/Skills/arkts-library-xts-execution/references/error-fixing-examples.md +217 -217
- package/vendor/Server/Skills/arkts-library-xts-execution/scripts/build.ps1 +93 -93
- package/vendor/Server/Skills/arkts-library-xts-execution/scripts/code-linter.cjs +432 -432
- package/vendor/Server/Skills/arkts-library-xts-execution/scripts/migrate.cjs +851 -851
- package/vendor/Server/Skills/arkts-library-xts-execution/scripts/ohpm-switch.cjs +788 -788
- package/vendor/Server/Skills/flutter-code-check/SKILL.md +299 -299
- package/vendor/Server/Skills/flutter-code-check/assets/OUTPUT_TEMPLATE.md +311 -311
- package/vendor/Server/Skills/flutter-code-check/references/CHECKLIST.md +190 -190
- package/vendor/Server/Skills/flutter-code-check/references/PLATFORMS.md +133 -133
- package/vendor/Server/Skills/flutter-code-check/scripts/validate-skill.cjs +259 -259
- package/vendor/Server/Skills/flutter-interface/README.md +75 -75
- package/vendor/Server/Skills/flutter-interface/SKILL.md +291 -291
- package/vendor/Server/Skills/flutter-interface/references/EXAMPLES.md +336 -336
- package/vendor/Server/Skills/flutter-interface/references/GIT_CLONE_GUIDE.md +190 -190
- package/vendor/Server/Skills/flutter-interface/references/SCRIPT_REFERENCE.md +258 -258
- package/vendor/Server/Skills/flutter-interface/references/TEMPLATE.md +254 -254
- package/vendor/Server/Skills/flutter-library-consistency-check/SKILL.md +517 -517
- package/vendor/Server/Skills/flutter-library-consistency-check/references/CHECKLIST.md +381 -381
- package/vendor/Server/Skills/flutter-library-consistency-check/references/FUNCTION_COMPARISON_GUIDE.md +341 -341
- package/vendor/Server/Skills/flutter-library-consistency-check/references/PLATFORM_LIMITATION_GUIDE.md +71 -71
- package/vendor/Server/Skills/flutter-library-documentation-quality-check/SKILL.md +518 -518
- package/vendor/Server/Skills/flutter-library-documentation-quality-check/references/CHECKLIST.md +406 -406
- package/vendor/Server/Skills/flutter-library-memory-leak-check/SKILL.md +652 -652
- package/vendor/Server/Skills/flutter-library-memory-leak-check/references/CHECKLIST.md +396 -396
- package/vendor/Server/Skills/flutter-library-stability-check/SKILL.md +744 -744
- package/vendor/Server/Skills/flutter-library-stability-check/references/CHECKLIST.md +720 -720
- package/vendor/Server/Skills/flutter-library-test-coverage-check/SKILL.md +414 -414
- package/vendor/Server/Skills/flutter-library-test-coverage-check/assets/REPORT_TEMPLATE.md +150 -150
- package/vendor/Server/Skills/flutter-library-test-coverage-check/references/CHECKLIST.md +304 -304
- package/vendor/Server/Skills/flutter-library-test-coverage-check/references/SCORING_RULES.md +265 -265
- package/vendor/Server/Skills/flutter-library-test-coverage-check/references/SCRIPT_USAGE.md +286 -286
- package/vendor/Server/Skills/knowledge-import/SKILL.md +383 -383
- package/vendor/Server/Skills/knowledge-import/references/MCP_TOOL_USAGE.md +165 -165
- package/vendor/Server/Skills/knowledge-import/references/SKILL_LOCATOR_GUIDE.md +91 -91
- package/vendor/Server/Skills/knowledge-import/references/SKILL_OPTIMIZATION_GUIDE.md +127 -127
- package/vendor/Server/Skills/ohos-lib-pr-push/SKILL.md +453 -301
- package/vendor/Server/Skills/ohos-lib-pr-push/assets/PR_CHECKLIST.md +151 -0
- package/vendor/Server/Skills/ohos-lib-pr-push/assets/PR_ISSUE_TEMPLATE.md +257 -105
- package/vendor/Server/Skills/ohos-lib-pr-push/references/GITCODE_API.md +191 -127
- package/vendor/Server/Skills/ohos-lib-pr-push/scripts/gitcode-api.cjs +317 -208
- package/vendor/Server/Skills/rn-code-check/SKILL.md +320 -320
- package/vendor/Server/Skills/rn-code-check/references/API-GUIDE.md +234 -234
- package/vendor/Server/Skills/rn-code-check/references/CHECKLIST.md +188 -188
- package/vendor/Server/Skills/rn-code-check/references/REPORT-TEMPLATE.md +246 -246
- package/vendor/Server/Skills/rn-lib-add-example/SKILL.md +198 -198
- package/vendor/Server/Skills/rn-lib-add-example/references/APP_RENAME_GUIDE.md +40 -40
- package/vendor/Server/Skills/rn-lib-add-example/references/SHELL_ADAPTATION_CHECKLIST.md +78 -78
- package/vendor/Server/Skills/rn-lib-add-example/references/TEMPLATE_REPO_GUIDE.md +70 -70
- package/vendor/Server/Skills/rn-lib-add-example/references/VERIFICATION_GUIDE.md +47 -47
- package/vendor/Server/Skills/rn-lib-add-example/scripts/create-example.cjs +252 -252
- package/vendor/Server/Skills/rn-lib-update-doc/SKILL.md +176 -176
- package/vendor/Server/Skills/rn-lib-update-doc/config.json +5 -5
- package/vendor/Server/Skills/rn-lib-update-doc/references/changelog-template.md +35 -35
- package/vendor/Server/Skills/rn-lib-update-doc/references/format-diff.md +137 -137
- package/vendor/Server/Skills/rn-lib-update-doc/references/link-registry.json +33 -33
- package/vendor/Server/Skills/rn-lib-update-doc/references/model-0.4.2-overview.md +40 -40
- package/vendor/Server/Skills/rn-lib-update-doc/references/model-0.4.2.md +429 -429
- package/vendor/Server/Skills/rn-lib-update-doc/scripts/detect-readme-format.cjs +105 -105
- package/vendor/Server/Skills/rn-lib-update-doc/scripts/find-usage-doc.cjs +90 -90
- package/vendor/Server/Skills/rn-lib-update-doc/scripts/link-verify.cjs +213 -213
- package/vendor/Server/Skills/rn-lib-update-doc/scripts/normalize-changelog.cjs +73 -73
- package/vendor/Server/Skills/rn-lib-update-doc/scripts/normalize-package-meta.cjs +258 -258
- package/vendor/Server/Skills/rn-lib-update-doc/scripts/normalize-readme-links.cjs +341 -341
- package/vendor/Server/Skills/rn-lib-update-doc/scripts/resolve-usage-docs.cjs +67 -67
- package/vendor/Server/Skills/rn-library-consistency-check/SKILL.md +299 -299
- package/vendor/Server/Skills/rn-library-consistency-check/assets/REPORT_TEMPLATE.md +293 -293
- package/vendor/Server/Skills/rn-library-consistency-check/references/ARKTS_COMPONENT_CHECK_GUIDE.md +857 -857
- package/vendor/Server/Skills/rn-library-consistency-check/references/ARKTS_TURBOMODULE_CHECK_GUIDE.md +856 -856
- package/vendor/Server/Skills/rn-library-consistency-check/references/CHECKLIST.md +157 -157
- package/vendor/Server/Skills/rn-library-consistency-check/references/CPP_COMPONENT_CHECK_GUIDE.md +801 -801
- package/vendor/Server/Skills/rn-library-consistency-check/references/CPP_TURBOMODULE_CHECK_GUIDE.md +683 -683
- package/vendor/Server/Skills/rn-library-consistency-check/references/FUNCTION_COMPARISON_GUIDE.md +233 -233
- package/vendor/Server/Skills/rn-library-consistency-check/references/NATIVE_COMPONENT_IDENTIFICATION.md +1373 -1373
- package/vendor/Server/Skills/rn-library-consistency-check/references/SCORING_STANDARD.md +220 -220
- package/vendor/Server/Skills/rn-library-consistency-check/scripts/validate-skill.py +245 -245
- package/vendor/Server/Skills/rn-library-documentation-quality-check/SKILL.md +263 -263
- package/vendor/Server/Skills/rn-library-documentation-quality-check/assets/MODEL.md +414 -414
- package/vendor/Server/Skills/rn-library-documentation-quality-check/assets/MODEL_en.md +413 -413
- package/vendor/Server/Skills/rn-library-documentation-quality-check/assets/REPORT_TEMPLATE.md +311 -311
- package/vendor/Server/Skills/rn-library-documentation-quality-check/references/CHECK_CHECKLIST.md +355 -355
- package/vendor/Server/Skills/rn-library-documentation-quality-check/references/CROSS_VALIDATION_GUIDE.md +115 -115
- package/vendor/Server/Skills/rn-library-documentation-quality-check/references/DOC_COLLECTION_GUIDE.md +139 -139
- package/vendor/Server/Skills/rn-library-documentation-quality-check/references/EXAMPLES.md +586 -586
- package/vendor/Server/Skills/rn-library-documentation-quality-check/references/GOTCHAS.md +57 -57
- package/vendor/Server/Skills/rn-library-documentation-quality-check/scripts/validate-skill.py +259 -259
- package/vendor/Server/Skills/rn-library-interface-analyzer/SKILL.md +301 -301
- package/vendor/Server/Skills/rn-library-interface-analyzer/assets/REPORT_TEMPLATE.md +148 -148
- package/vendor/Server/Skills/rn-library-interface-analyzer/references/DOC_ANNOTATION_GUIDE.md +118 -118
- package/vendor/Server/Skills/rn-library-interface-analyzer/references/SCRIPT_USAGE_GUIDE.md +168 -168
- package/vendor/Server/Skills/rn-library-interface-analyzer/references/URL_PARSING_RULES.md +176 -176
- package/vendor/Server/Skills/rn-library-issue-generalizer/SKILL.md +274 -274
- package/vendor/Server/Skills/rn-library-issue-generalizer/assets/case-template.md +45 -45
- package/vendor/Server/Skills/rn-library-issue-generalizer/assets/rule-template.md +25 -25
- package/vendor/Server/Skills/rn-library-issue-generalizer/references/PR_FETCH_GUIDE.md +61 -61
- package/vendor/Server/Skills/rn-library-issue-generalizer/references/RULE_TEMPLATE_GUIDE.md +165 -165
- package/vendor/Server/Skills/rn-library-issue-generalizer/scripts/fetch-pr-info.py +239 -239
- package/vendor/Server/Skills/rn-library-known-issue-check/SKILL.md +263 -263
- package/vendor/Server/Skills/rn-library-known-issue-check/assets/REPORT_TEMPLATE.md +96 -96
- package/vendor/Server/Skills/rn-library-known-issue-check/references/COMPLIANCE_CHECKLIST.md +57 -57
- package/vendor/Server/Skills/rn-library-known-issue-check/references/INSPECTION_GUIDE.md +99 -99
- package/vendor/Server/Skills/rn-library-known-issue-check/references/PRESCREEN_GUIDE.md +64 -64
- package/vendor/Server/Skills/rn-library-known-issue-check/references/SOURCE_PREP_GUIDE.md +74 -74
- package/vendor/Server/Skills/rn-library-known-issue-check/scripts/validate-known-issue-report.py +164 -164
- package/vendor/Server/Skills/rn-library-memory-leak-check/SKILL.md +356 -339
- package/vendor/Server/Skills/rn-library-memory-leak-check/assets/REPORT_TEMPLATE.md +85 -83
- package/vendor/Server/Skills/rn-library-memory-leak-check/references/CHECKLIST.md +905 -859
- package/vendor/Server/Skills/rn-library-memory-leak-check/references/HARMONY_CODE_PATTERNS.md +124 -122
- package/vendor/Server/Skills/rn-library-memory-leak-check/scripts/scan_harmony_code.py +287 -279
- package/vendor/Server/Skills/rn-library-stability-check/SKILL.md +273 -273
- package/vendor/Server/Skills/rn-library-stability-check/assets/REPORT_TEMPLATE.md +129 -129
- package/vendor/Server/Skills/rn-library-stability-check/references/CHECKLIST.md +581 -581
- package/vendor/Server/Skills/rn-library-stability-check/references/SCORING_RULES.md +138 -138
- package/vendor/Server/Skills/rn-library-stability-check/scripts/scan-harmony-code.py +168 -168
- package/vendor/Server/Skills/rn-library-test-coverage-check/SKILL.md +526 -506
- package/vendor/Server/Skills/rn-library-test-coverage-check/references/CHECKLIST.md +321 -280
- package/vendor/Server/Skills/rn-library-test-coverage-check/references/DEMO_LOCATION.md +221 -221
- package/vendor/Server/Skills/rn-library-test-coverage-check/references/REPORT_TEMPLATE.md +220 -209
- package/vendor/Server/Skills/rn-library-test-coverage-check/references/SCRIPT_USAGE.md +325 -325
- package/vendor/Server/Skills/rn-ohos-xts-generator/SKILL.md +279 -279
- package/vendor/Server/Skills/rn-ohos-xts-generator/assets/TEST_FILE_TEMPLATES.md +404 -404
- package/vendor/Server/Skills/rn-ohos-xts-generator/references/BUILD_TROUBLESHOOTING.md +185 -185
- package/vendor/Server/Skills/rn-ohos-xts-generator/references/BUILD_WORKFLOW.md +265 -265
- package/vendor/Server/Skills/rn-ohos-xts-generator/references/COMMON_CONFIG.md +189 -189
- package/vendor/Server/Skills/rn-ohos-xts-generator/references/CONFIG_GUIDE.md +203 -203
- package/vendor/Server/Skills/rn-ohos-xts-generator/references/COVERAGE_ANALYZER.md +147 -147
- package/vendor/Server/Skills/rn-ohos-xts-generator/references/DESIGN_DOC_GUIDE.md +148 -148
- package/vendor/Server/Skills/rn-ohos-xts-generator/references/GENERATION_FLOW.md +165 -165
- package/vendor/Server/Skills/rn-ohos-xts-generator/references/GENERATION_STRATEGY.md +195 -195
- package/vendor/Server/Skills/rn-ohos-xts-generator/references/HARMONY_SCANNER.md +249 -249
- package/vendor/Server/Skills/rn-ohos-xts-generator/references/JEST_FRAMEWORK.md +235 -235
- package/vendor/Server/Skills/rn-ohos-xts-generator/references/PLATFORM_COMPAT.md +161 -161
- package/vendor/Server/Skills/rn-ohos-xts-generator/references/RN_TEST_PATTERNS.md +413 -413
- package/vendor/Server/Skills/rn-ohos-xts-generator/references/SOURCE_PARSER.md +235 -235
- package/vendor/Server/Skills/rn-ohos-xts-generator/references/TEST_CONVENTIONS.md +245 -245
- package/vendor/Server/Skills/rn-ohos-xts-generator/references/TROUBLESHOOTING.md +282 -282
- package/vendor/Server/Skills/rn-ohos-xts-generator/references/USAGE_GUIDE.md +251 -251
- package/vendor/Server/Skills/rnoh-cptf-api-test/SKILL.md +469 -469
- package/vendor/Server/Skills/rnoh-cptf-api-test/assets/CPTF_TEST_TEMPLATE.md +310 -310
- package/vendor/Server/Skills/rnoh-cptf-api-test/assets/DEMO_PAGE_TEMPLATE.md +303 -303
- package/vendor/Server/Skills/rnoh-cptf-api-test/references/CPTF_TEST_GENERATION_GUIDE.md +421 -421
- package/vendor/Server/Skills/rnoh-cptf-api-test/references/DEMO_GENERATION_GUIDE.md +358 -358
- package/vendor/Server/Skills/rnoh-cptf-api-test/references/QUALITY_CHECKLIST.md +114 -114
- package/vendor/Server/Skills/rnoh-cptf-api-test/references/SPEC_PARSING_GUIDE.md +274 -274
- package/vendor/Server/Skills/rnoh-cptf-api-test/scripts/validate-rnoh-cptf-api-test.sh +185 -185
- package/vendor/Server/Skills/rnoh-cptf-demo-test/SKILL.md +191 -191
- package/vendor/Server/Skills/rnoh-cptf-demo-test/assets/TEST_TEMPLATE.md +216 -216
- package/vendor/Server/Skills/rnoh-cptf-demo-test/references/CPTF_SETUP.md +107 -107
- package/vendor/Server/Skills/rnoh-cptf-demo-test/references/DEMO_ANALYSIS.md +120 -120
- package/vendor/Server/Skills/rnoh-cptf-demo-test/scripts/validate-rnoh-cptf-test.sh +108 -108
- package/vendor/Server/Skills/rnoh-cptf-test-run/SKILL.md +237 -237
- package/vendor/Server/Skills/rnoh-cptf-test-run/references/DEBUG_PLAYBOOK.md +261 -261
- package/vendor/Server/Skills/rnoh-cptf-test-run/scripts/validate-run-env.sh +112 -112
- package/vendor/Server/Skills/rnoh-lib-code-adapt/SKILL.md +497 -497
- package/vendor/Server/Skills/rnoh-lib-code-adapt/references/adapt-checklist.md +270 -270
- package/vendor/Server/Skills/rnoh-lib-code-adapt/references/api-migration-checklist.md +164 -164
- package/vendor/Server/Skills/rnoh-lib-code-adapt/references/common-compile-errors.md +556 -556
- package/vendor/Server/Skills/rnoh-lib-code-adapt/references/deveco-cli-tools.md +459 -459
- package/vendor/Server/Skills/rnoh-lib-code-adapt/references/edge-cases.md +65 -65
- package/vendor/Server/Skills/rnoh-lib-code-adapt/references/har-tgz-build.md +512 -512
- package/vendor/Server/Skills/rnoh-lib-code-adapt/references/version-compat-matrix.md +132 -132
- package/vendor/Server/Skills/rnoh-lib-code-adapt/scripts/auto-integrate.sh +424 -424
- package/vendor/Server/Skills/rnoh-lib-demo-coverage/SKILL.md +137 -137
- package/vendor/Server/Skills/rnoh-lib-demo-create/SKILL.md +306 -306
- package/vendor/Server/Skills/rnoh-lib-demo-create/assets/DEMO_PAGE_TEMPLATE.md +485 -485
- package/vendor/Server/Skills/rnoh-lib-demo-create/assets/INDEX_TEMPLATE.md +172 -172
- package/vendor/Server/Skills/rnoh-lib-demo-create/references/DEMO_CODE_RULES.md +422 -422
- package/vendor/Server/Skills/rnoh-lib-demo-create/references/QUALITY_CHECKLIST.md +95 -95
- package/vendor/Server/Skills/rnoh-lib-demo-create/references/SOURCE_EXPLORATION.md +169 -169
- package/vendor/Server/Skills/rnoh-lib-demo-doc/SKILL.md +554 -554
- package/vendor/Server/Skills/rnoh-lib-demo-doc/assets/DEMO_DOC_TEMPLATE.md +106 -106
- package/vendor/Server/Skills/rnoh-lib-demo-doc/references/COVERAGE_INCREMENTAL.md +216 -216
- package/vendor/Server/Skills/rnoh-lib-demo-doc/references/DEMO_DESIGN_RULES.md +413 -413
- package/vendor/Server/Skills/rnoh-lib-demo-doc/references/OUTPUT_FORMAT.md +269 -269
- package/vendor/Server/Skills/rnoh-lib-demo-doc/references/QUALITY_CHECKLIST.md +98 -98
- package/vendor/Server/Skills/rnoh-lib-func-test/SKILL.md +337 -337
- package/vendor/Server/Skills/rnoh-lib-rnt-search/SKILL.md +722 -722
- package/vendor/Server/Skills/rnoh-lib-rnt-search/assets/PORT_REPORT_TEMPLATE.md +219 -219
- package/vendor/Server/Skills/rnoh-lib-rnt-search/references/DEMO_PORTING_GUIDE.md +345 -345
- package/vendor/Server/Skills/rnoh-lib-rnt-search/references/PORT_VERIFICATION.md +269 -269
- package/vendor/Server/Skills/rnoh-lib-rnt-search/references/RNT_PROJECT_STRUCTURE.md +173 -173
- package/vendor/Server/Skills/rnoh-lib-rnt-search/scripts/analyze-demo-deps.cjs +267 -267
- package/vendor/Server/Skills/rnoh-lib-rnt-search/scripts/detect-rnoh-version.cjs +174 -174
- package/vendor/Server/Skills/rnoh-lib-rnt-search/scripts/find-rnt-demo.sh +111 -111
- package/vendor/Server/Skills/rnoh-lib-rnt-search/scripts/port-demo.sh +186 -186
- package/vendor/Server/Skills/rnoh-lib-rnt-search/scripts/read-lib-meta.cjs +150 -150
- package/vendor/Server/Skills/rnoh-lib-test-align/SKILL.md +296 -296
- package/vendor/Server/Skills/rnoh-lib-test-align/references/jest-troubleshooting.md +371 -371
- package/vendor/Server/Skills/rnoh-lib-test-align/references/port-test-demo-guide.md +212 -212
- package/vendor/Server/Skills/rnoh-lib-test-align/references/runtime-troubleshooting.md +345 -345
- package/vendor/Server/Skills/rnoh-lib-test-align/references/unit-test-template.md +223 -223
- package/vendor/Server/Skills/rnoh-lib-test-align/scripts/port-test-demo.sh +1053 -1053
- package/vendor/Server/Skills/rnoh-lib-version-diff/SKILL.md +295 -255
- package/vendor/Server/Skills/rnoh-lib-version-diff/references/OHOS_ADAPTATION.md +82 -77
- package/vendor/Server/Skills/rnoh-lib-version-diff/references/OHOS_API_LOOKUP.md +224 -224
- package/vendor/Server/Skills/rnoh-lib-version-diff/references/script-reference.md +175 -174
- package/vendor/Server/Skills/rnoh-lib-version-diff/scripts/detect-upstream-version.js +967 -967
- package/vendor/Server/Skills/rnoh-lib-version-diff/scripts/generate-diff.js +1798 -1798
- package/vendor/Server/Skills/rnoh-lib-version-diff/scripts/package.json +5 -5
- package/vendor/Server/Skills/rnoh-lib-version-diff/templates/report-template.md +180 -137
- package/vendor/Server/Skills/rnoh-lib-xts-coverage/SKILL.md +145 -145
- package/vendor/Server/Skills/skill-generator/SKILL.md +365 -365
- package/vendor/Server/Skills/skill-generator/assets/SKILL_TEMPLATE.md +183 -183
- package/vendor/Server/Skills/skill-generator/references/COMPLIANCE_CHECKLIST.md +82 -82
- package/vendor/Server/Skills/skill-generator/references/KB_QUERY_GUIDE.md +110 -110
- package/vendor/Server/Skills/skill-generator/references/MCP_TOOL_DISCOVERY.md +122 -122
- package/vendor/Server/Skills/skill-generator/references/SKILL_SPEC.md +121 -121
- package/vendor/Server/Skills/skill-generator/scripts/validate-skill.cjs +259 -259
- package/vendor/Server/Skills/task-analysis/SKILL.md +234 -234
- package/vendor/Server/Skills/task-analysis/assets/OUTPUT_EXAMPLES.md +160 -160
- package/vendor/Server/Skills/task-analysis/references/ACCEPTANCE_CRITERIA_GUIDE.md +190 -190
- package/vendor/Server/Skills/task-analysis/references/ANALYSIS_SCHEMA.md +224 -224
- package/vendor/Server/Skills/task-analysis/references/INTEGRATION_CONTEXT.md +162 -162
- package/vendor/Server/Skills/task-analysis/references/LESSONS_LEARNED.md +55 -55
- package/vendor/Server/Skills/task-analysis/references/REPLAN_CONTEXT_GUIDE.md +126 -126
- package/vendor/Server/Skills/task-analysis/scripts/validate-analysis-output.sh +256 -256
- package/vendor/Server/Skills/task-decomposition/SKILL.md +528 -528
- package/vendor/Server/Skills/task-decomposition/assets/OUTPUT_EXAMPLES.md +451 -451
- package/vendor/Server/Skills/task-decomposition/references/ACCEPTANCE_CRITERIA_GUIDE.md +179 -179
- package/vendor/Server/Skills/task-decomposition/references/DEPENDENCY_GRAPH_GUIDE.md +152 -152
- package/vendor/Server/Skills/task-decomposition/references/INTEGRATION_CONTEXT.md +175 -175
- package/vendor/Server/Skills/task-decomposition/references/REPLAN_CONTEXT_GUIDE.md +195 -195
- package/vendor/Server/Skills/task-decomposition/references/TASK_DECOMPOSITION_TEMPLATES.md +226 -226
- package/vendor/Server/Skills/task-decomposition/scripts/list-available-skills.cjs +263 -263
- package/vendor/Server/Skills/task-decomposition/scripts/skill-blacklist.json +29 -29
- package/vendor/Server/Skills/task-decomposition/scripts/validate-decomposition-output.cjs +376 -376
- package/vendor/Server/Skills/task-decomposition/scripts/validate-param-consistency.cjs +259 -259
- package/vendor/Server/Skills/task-decomposition/scripts/validate-specified-skills.cjs +216 -216
- package/vendor/Server/Skills/task-decomposition/scripts/validate-step-graph.cjs +424 -424
- package/vendor/Server/Skills/tpc-cpp-check/SKILL.md +427 -427
- package/vendor/Server/Skills/tpc-cpp-check/references/CHECKLIST.md +214 -214
- package/vendor/Server/Skills/tpc-cpp-check/references/HPKBUILD_GUIDE.md +235 -235
- package/vendor/Server/Skills/tpc-cpp-check/references/REPORT_TEMPLATE.md +250 -250
- package/vendor/Server/TestCheck/TestCheck.js +775 -775
- package/vendor/Server/TestCheck/index.js +11 -11
- package/vendor/Server/library/McpToolGuide.js +280 -280
- package/vendor/Server/library/StatsService.js +126 -126
- package/vendor/Server/library/cstTime.js +16 -16
- package/vendor/VERSION +3 -3
- package/workflows/pr-check.mjs +105 -105
- package/workflows/pr-push.mjs +192 -192
- package/vendor/Server/Agent/SkillSelector/types.js +0 -63
|
@@ -1,1373 +1,1373 @@
|
|
|
1
|
-
# RN 原生组件(ViewManager)识别与定位指南
|
|
2
|
-
|
|
3
|
-
本文档定义 RN 一致性检视中**原生组件(ViewManager)**的识别方法、注册链路定位流程和检视对比规范,确保检视人员能准确区分 TurboModule/NativeModule(方法级桥接)与原生组件(UI 组件桥接),并系统性地定位组件的完整注册链路。
|
|
4
|
-
|
|
5
|
-
> ⚠️ **核心定位**:RN 库可同时包含两类原生桥接——**TurboModule/NativeModule**(方法级桥接)和**原生组件(ViewManager)**(UI 组件桥接)。两者独立检视、独立扣分,不可混为一谈。
|
|
6
|
-
|
|
7
|
-
---
|
|
8
|
-
|
|
9
|
-
## 1. 原生组件 vs TurboModule/NativeModule 区分
|
|
10
|
-
|
|
11
|
-
### 1.1 两类桥接的本质区别
|
|
12
|
-
|
|
13
|
-
| 桥接类型 | 本质 | JS 层注册方式 | 代码特征 | 检视维度 |
|
|
14
|
-
|----------|------|---------------|----------|----------|
|
|
15
|
-
| TurboModule/NativeModule | 方法级桥接(JS 调用原生方法) | `TurboModuleRegistry.getEnforcing<Spec>('XXX')` 或 `NativeModules.XXX` | JS 层导出 `Spec extends TurboModule`,ArkTS 层继承 `TurboModule` | 方法签名、参数类型、返回值、事件 |
|
|
16
|
-
| 原生组件(ViewManager) | UI 组件桥接(JS 渲染原生视图) | `codegenNativeComponent<NativeProps>('ComponentName')` 或 `requireNativeComponent<Props>('ComponentName')` | JS 层定义 `NativeProps` + `NativeCommands`,ArkTS 层 `@Component export struct` 或 `@Component struct` | Props、Commands、事件发送、DescriptorWrapper |
|
|
17
|
-
|
|
18
|
-
### 1.2 判定流程
|
|
19
|
-
|
|
20
|
-
```
|
|
21
|
-
搜索 RN 库 JS 源码中的注册入口(搜索范围:src/ 目录及其所有子目录):
|
|
22
|
-
|
|
23
|
-
1. 找到 codegenNativeComponent → ✅ 含 Codegen 原生组件 → 执行本文档 2A 流程
|
|
24
|
-
2. 找到 requireNativeComponent → ✅ 含 Legacy 原生组件 → 执行本文档 2B 流程
|
|
25
|
-
3. 找到 TurboModuleRegistry → ✅ 含 TurboModule → 仅执行方法级对比(见 FUNCTION_COMPARISON_GUIDE.md)
|
|
26
|
-
4. 找到 NativeModules 但无 1/2 → ✅ 仅含 NativeModule(方法级) → 仅执行方法级对比
|
|
27
|
-
5. 1+2+3 均找到 → ✅ 同时含原生组件和 TurboModule → 分别执行两类检视
|
|
28
|
-
6. 1+3 找到但无 2 → ✅ Codegen 原生组件 + TurboModule → 分别执行两类检视
|
|
29
|
-
7. 2+3 找到但无 1 → ✅ Legacy 原生组件 + TurboModule → 分别执行两类检视
|
|
30
|
-
8. 均未找到 → ❌ 纯 JS 库 → 无原生桥接检视需求
|
|
31
|
-
```
|
|
32
|
-
|
|
33
|
-
> 💡 **共存示例**:react-native-webview 同时有 `RNCWebView` 原生组件(codegenNativeComponent)和 `RNCWebViewModule` TurboModule(TurboModuleRegistry)。react-native-maps 同时有多个 Legacy 原生组件(requireNativeComponent)和 TurboModule(NativeModules)。
|
|
34
|
-
|
|
35
|
-
> ⚠️ **重要**:`requireNativeComponent` 是 RN 旧架构的原生组件注册方式,与 `codegenNativeComponent` 功能等价(都是注册 UI 组件),但注册链路追踪方式不同。不可因未找到 `codegenNativeComponent` 就判定库不含原生组件。
|
|
36
|
-
|
|
37
|
-
---
|
|
38
|
-
|
|
39
|
-
## 2. 原生组件注册链路定位流程
|
|
40
|
-
|
|
41
|
-
原生组件存在两种注册架构模式,必须先判定模式再执行对应流程:
|
|
42
|
-
|
|
43
|
-
| 模式 | JS 层特征 | OHOS Package 特征 | 识别方法 |
|
|
44
|
-
|------|-----------|-------------------|----------|
|
|
45
|
-
| **模式 A:Codegen 架构** | `codegenNativeComponent` | Package 有 `createDescriptorWrapperFactoryByDescriptorType` 返回组件名 → DescriptorWrapper 映射;存在 `generated/` 目录 | 找到 `codegenNativeComponent` |
|
|
46
|
-
| **模式 B:Legacy/Descriptor 架构** | `requireNativeComponent` 或无 JS 层组件注册宏 | Package 仅注册 TurboModule(无 `createDescriptorWrapperFactoryByDescriptorType`);手动定义 Descriptor 类型;可能有 `ComponentFactory` 脚本路由 | 未找到 `codegenNativeComponent` 但找到 `requireNativeComponent` 或 `@Component struct` |
|
|
47
|
-
|
|
48
|
-
### 2A. Codegen 架构注册链路定位
|
|
49
|
-
|
|
50
|
-
此流程适用于 JS 层使用 `codegenNativeComponent` 的库(如 react-native-webview、react-native-video、react-native-screens、react-native-keyboard-controller 等)。
|
|
51
|
-
|
|
52
|
-
#### 2A.1 步骤 5a:定位 JS 层组件注册
|
|
53
|
-
|
|
54
|
-
| 项目 | 说明 |
|
|
55
|
-
|------|------|
|
|
56
|
-
| 搜索位置 | RN 库 `src/` 目录及其子目录(常见子目录:`src/specs/`、`src/`根目录) |
|
|
57
|
-
| 搜索关键词 | `codegenNativeComponent` |
|
|
58
|
-
| 文件名模式 | `*NativeComponent.ts`、`*NativeComponent.js` |
|
|
59
|
-
| 目的 | 定位 JS 层原生组件注册,提取组件名和 NativeProps 类型定义 |
|
|
60
|
-
|
|
61
|
-
**代码模式**:
|
|
62
|
-
|
|
63
|
-
```typescript
|
|
64
|
-
// Codegen 注册模式(典型)
|
|
65
|
-
export const RNCWebView = codegenNativeComponent<NativeProps>(
|
|
66
|
-
'RNCWebView'
|
|
67
|
-
) as HostComponent<NativeProps>;
|
|
68
|
-
|
|
69
|
-
// 多组件库中每个组件独立注册
|
|
70
|
-
export default codegenNativeComponent<NativeProps>('RNSScreen', {});
|
|
71
|
-
export default codegenNativeComponent<NativeProps>('RNSScreenStack', {});
|
|
72
|
-
```
|
|
73
|
-
|
|
74
|
-
**NativeProps 类型定义模式**:
|
|
75
|
-
|
|
76
|
-
```typescript
|
|
77
|
-
// NativeProps 通常在同一文件或单独的 Types 文件中
|
|
78
|
-
export interface NativeProps extends ViewProps {
|
|
79
|
-
javaScriptEnabled?: WithDefault<boolean, true>;
|
|
80
|
-
source?: string | Object;
|
|
81
|
-
cacheMode?: WithDefault<CacheModeEnum, 'DEFAULT>;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
// NativeCommands 定义(可选)
|
|
85
|
-
export interface NativeCommands {
|
|
86
|
-
goBack(viewRef: ReactElementRef<HostComponent<NativeProps>>): void;
|
|
87
|
-
goForward(viewRef: ReactElementRef<HostComponent<NativeProps>>): void;
|
|
88
|
-
}
|
|
89
|
-
```
|
|
90
|
-
|
|
91
|
-
**提取要求**:
|
|
92
|
-
- 组件名(`codegenNativeComponent` 的字符串参数,如 `'RNCWebView'`、`'RNCVideo'`)
|
|
93
|
-
- **多组件库需提取所有组件名**(如 react-native-screens 有 11 个 `codegenNativeComponent`)
|
|
94
|
-
- NativeProps 接口文件路径和行号
|
|
95
|
-
- Props 完整列表(名称 + 类型)
|
|
96
|
-
- Commands 完整列表(名称 + 签名),若无 Commands 标注"⚠️ 无 Commands 定义"
|
|
97
|
-
|
|
98
|
-
#### 2A.2 步骤 5b:定位 OHOS Harmony 目录
|
|
99
|
-
|
|
100
|
-
| 项目 | 说明 |
|
|
101
|
-
|------|------|
|
|
102
|
-
| 搜索位置 | RN 库根目录下 |
|
|
103
|
-
| 关键标记 | `harmony/` 目录 |
|
|
104
|
-
| 目的 | 定位 OHOS 鸿蒙化代码的根目录 |
|
|
105
|
-
|
|
106
|
-
**Harmony 目录发现策略**:
|
|
107
|
-
|
|
108
|
-
```
|
|
109
|
-
1. 查找根目录下的 harmony/ 目录 → 大多数库的通用模式
|
|
110
|
-
2. 若根目录无 harmony/,查找子包目录(如 react-native-harmony-screens/harmony/)
|
|
111
|
-
3. 若仍无 harmony/ 目录 → ⛔ 该库可能未鸿蒙化,需进一步验证
|
|
112
|
-
|
|
113
|
-
harmony/ 目录内部结构:
|
|
114
|
-
harmony/<module_name>/ ← 模块名各异(rn_webview, rn_video, maps, svg, picker, screens, keyboard_controller 等)
|
|
115
|
-
<module_name>.har ← 预编译产物
|
|
116
|
-
src/main/ets/ ← ArkTS 源码目录
|
|
117
|
-
src/main/cpp/ ← C++ 源码目录
|
|
118
|
-
src/main/ets/generated/ ← Codegen 生成目录(模式 A 特征)
|
|
119
|
-
components/ ← 原生组件的 DescriptorWrapper 定义
|
|
120
|
-
turboModules/ ← TurboModule 的类型定义
|
|
121
|
-
index.ets
|
|
122
|
-
ts.ts
|
|
123
|
-
```
|
|
124
|
-
|
|
125
|
-
> ⚠️ **模块名不固定**:不同库的 harmony 子目录命名各异。`<module_name>` 不可按库名硬推,需通过目录探索确定。常见映射:webview→rn_webview, video→rn_video, maps→maps, svg→svg, picker→picker, screens→screens。
|
|
126
|
-
|
|
127
|
-
#### 2A.3 步骤 5c:定位 Package 注册类
|
|
128
|
-
|
|
129
|
-
| 项目 | 说明 |
|
|
130
|
-
|------|------|
|
|
131
|
-
| 搜索位置 | `harmony/<module_name>/src/main/ets/` 目录 |
|
|
132
|
-
| 搜索关键词 | `Package`(文件名 `*Package.ets` 或 `*Package.ts`) |
|
|
133
|
-
| 目的 | 定位 Package 注册类,提取原生组件名和 TurboModule 名 |
|
|
134
|
-
|
|
135
|
-
**两种 Package 基类的 API 区别**:
|
|
136
|
-
|
|
137
|
-
```typescript
|
|
138
|
-
// RNOHPackage(较新模式,如 react-native-webview)
|
|
139
|
-
export class RNCWebViewPackage extends RNOHPackage {
|
|
140
|
-
createDescriptorWrapperFactoryByDescriptorType(ctx): DescriptorWrapperFactoryByDescriptorType {
|
|
141
|
-
return {
|
|
142
|
-
"RNCWebView": (ctx) => new RNC.RNCWebView.DescriptorWrapper(ctx.descriptor)
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
createAnyThreadTurboModuleFactory(ctx): AnyThreadTurboModuleFactory {
|
|
146
|
-
return new WebViewTurboModulesFactory(ctx);
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
// RNPackage(常见模式,如 react-native-video)
|
|
151
|
-
export class RNCVideoPackage extends RNPackage {
|
|
152
|
-
createDescriptorWrapperFactoryByDescriptorType(ctx): DescriptorWrapperFactoryByDescriptorType {
|
|
153
|
-
return {
|
|
154
|
-
[RNC.RNCVideo.NAME]: (ctx) => new RNC.RNCVideo.DescriptorWrapper(ctx.descriptor),
|
|
155
|
-
};
|
|
156
|
-
}
|
|
157
|
-
createTurboModulesFactory(ctx: TurboModuleContext): TurboModulesFactory {
|
|
158
|
-
return new RNCVideoTurboModulesFactory(ctx);
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
```
|
|
162
|
-
|
|
163
|
-
> ⚠️ **Package 基类区别**:`RNOHPackage` 使用 `createAnyThreadTurboModuleFactory()` + `AnyThreadTurboModuleFactory`;`RNPackage` 使用 `createTurboModulesFactory()` + `TurboModulesFactory`。两者注册组件的方式相同(`createDescriptorWrapperFactoryByDescriptorType`),但 TurboModule 注册 API 不同。
|
|
164
|
-
|
|
165
|
-
> ⚠️ **文件扩展名**:Package 注册文件可以是 `.ets` 或 `.ts`,搜索时需同时覆盖两种扩展名。
|
|
166
|
-
|
|
167
|
-
**提取要求**:
|
|
168
|
-
- Package 类名和继承关系(`extends RNOHPackage` 或 `extends RNPackage`)
|
|
169
|
-
- `createDescriptorWrapperFactoryByDescriptorType` 返回值中所有组件名 → DescriptorWrapper 映射
|
|
170
|
-
- TurboModule 注册中所有 TurboModule 名
|
|
171
|
-
- Package 文件路径和行号
|
|
172
|
-
|
|
173
|
-
#### 2A.4 步骤 5d:定位 DescriptorWrapper 和 generated 类型
|
|
174
|
-
|
|
175
|
-
| 项目 | 说明 |
|
|
176
|
-
|------|------|
|
|
177
|
-
| 搜索位置 | `harmony/<module_name>/src/main/ets/generated/components/` 目录 |
|
|
178
|
-
| 搜索关键词 | 组件名(如 `RNCWebView.ts`、`RNCVideo.ts`) |
|
|
179
|
-
| 目的 | 提取 Codegen 生成的完整类型定义 |
|
|
180
|
-
|
|
181
|
-
**generated/components/ComponentName.ts 的关键结构**:
|
|
182
|
-
|
|
183
|
-
```typescript
|
|
184
|
-
export namespace ComponentName {
|
|
185
|
-
export const NAME = "ComponentName" as const // 组件名常量
|
|
186
|
-
|
|
187
|
-
export interface DirectRawProps { // 所有 Prop 定义(含类型)
|
|
188
|
-
propA?: boolean;
|
|
189
|
-
propB?: string;
|
|
190
|
-
// ...
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
export interface Props extends ViewBaseProps {} // 基础 Props
|
|
194
|
-
export interface State {} // State 定义
|
|
195
|
-
export interface RawProps extends ViewRawProps, DirectRawProps {} // 完整 RawProps
|
|
196
|
-
|
|
197
|
-
export class PropsSelector extends ViewPropsSelector<Props, RawProps> {
|
|
198
|
-
get propA() { return this.rawProps.propA ?? false } // 每个 Prop 的默认值
|
|
199
|
-
get propB() { return this.rawProps.propB } // 无默认值的 Prop
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
export type Descriptor = ComponentDescriptor<typeof NAME, Props, State, RawProps>
|
|
203
|
-
|
|
204
|
-
export class DescriptorWrapper extends ViewDescriptorWrapperBase<...> {
|
|
205
|
-
protected createPropsSelector() {
|
|
206
|
-
return new PropsSelector(this.descriptor.props, this.descriptor.rawProps)
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
export interface EventPayloadByName { // 所有事件名 + Payload 类型
|
|
211
|
-
"onLoad": {url: string, ...}
|
|
212
|
-
"onError": {code: number, ...}
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
export class EventEmitter {
|
|
216
|
-
emit<TEventName>(eventName: TEventName, payload: EventPayloadByName[TEventName]) {
|
|
217
|
-
this.rnInstance.emitComponentEvent(this.tag, eventName, payload)
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
export interface CommandArgvByName { // 所有 Command 名 + 参数类型
|
|
222
|
-
"goBack": []
|
|
223
|
-
"injectJavaScript": [string]
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
export class CommandReceiver {
|
|
227
|
-
subscribe<TCommandName>(commandName: TCommandName, listener: (argv: CommandArgvByName[TCommandName]) => void) {
|
|
228
|
-
// ...
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
|
-
```
|
|
233
|
-
|
|
234
|
-
**提取要求**:
|
|
235
|
-
- `NAME` 常量值
|
|
236
|
-
- `DirectRawProps` 中所有 Prop 名 + 类型 + 默认值(从 `PropsSelector` 中提取)
|
|
237
|
-
- `EventPayloadByName` 中所有事件名 + Payload 类型
|
|
238
|
-
- `CommandArgvByName` 中所有 Command 名 + 参数类型
|
|
239
|
-
- 若 `CommandArgvByName` 为空接口 `{}`,标注"⚠️ 无 Commands 定义"
|
|
240
|
-
- 若 `generated/components/ts.ts` 仅导出空对象 `export {}`,标注"⚠️ 该组件未在 generated 中注册"
|
|
241
|
-
|
|
242
|
-
#### 2A.5 步骤 5e:定位 ArkTS 组件实现
|
|
243
|
-
|
|
244
|
-
| 项目 | 说明 |
|
|
245
|
-
|------|------|
|
|
246
|
-
| 搜索位置 | `harmony/<module_name>/src/main/ets/` 目录(排除 generated 子目录) |
|
|
247
|
-
| 搜索关键词 | `@Component` + 组件名 |
|
|
248
|
-
| 目的 | 定位组件的实际 ArkTS 实现 |
|
|
249
|
-
|
|
250
|
-
**Codegen 架构的 ArkTS 组件实现模式**:
|
|
251
|
-
|
|
252
|
-
```typescript
|
|
253
|
-
// 典型 Codegen 架构实现(如 RNCWebView)
|
|
254
|
-
@Component
|
|
255
|
-
export struct RNCWebView {
|
|
256
|
-
public static readonly NAME = RNC.RNCWebView.NAME
|
|
257
|
-
ctx!: RNComponentContext
|
|
258
|
-
tag: number = 0
|
|
259
|
-
|
|
260
|
-
// Props 读取方式 1:通过 DescriptorWrapper.rawProps(常见于较早版本)
|
|
261
|
-
aboutToAppear() {
|
|
262
|
-
const javaScriptEnabled = this.descriptorWrapper.rawProps.javaScriptEnabled
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
// Props 读取方式 2:通过 ctx.descriptorRegistry(较新版本)
|
|
266
|
-
aboutToAppear() {
|
|
267
|
-
this.descriptor = this.ctx.descriptorRegistry.getDescriptor<Descriptor>(this.tag)
|
|
268
|
-
this.descriptor.rawProps.javaScriptEnabled
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
// Commands 注册方式 1:通过 CommandReceiver.subscribe(Codegen generated 方式)
|
|
272
|
-
aboutToAppear() {
|
|
273
|
-
const commandReceiver = new RNC.RNCWebView.CommandReceiver(
|
|
274
|
-
this.ctx.componentCommandReceiver, this.tag
|
|
275
|
-
)
|
|
276
|
-
commandReceiver.subscribe("goBack", (argv) => { this.goBack() })
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
// Commands 注册方式 2:通过 ctx.componentCommandReceiver(直接注册)
|
|
280
|
-
aboutToAppear() {
|
|
281
|
-
this.ctx.componentCommandReceiver.registerCommandCallback(this.tag, (command, args) => {
|
|
282
|
-
if (command === 'goBack') { this.goBack() }
|
|
283
|
-
})
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
// 事件发送方式 1:通过 generated EventEmitter
|
|
287
|
-
private emitter = new RNC.RNCWebView.EventEmitter(this.ctx.rnInstance, this.tag)
|
|
288
|
-
onNavigationStateChange(event) {
|
|
289
|
-
this.emitter.emit("onNavigationStateChange", {url: event.url, ...})
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
// 事件发送方式 2:通过 ctx.rnInstance.emitComponentEvent
|
|
293
|
-
this.ctx.rnInstance.emitComponentEvent(this.tag, "onNavigationStateChange", {url: ...})
|
|
294
|
-
|
|
295
|
-
build() {
|
|
296
|
-
Web({ src: this.source, controller: this.controller })
|
|
297
|
-
.javaScriptAccess(this.javaScriptEnabled)
|
|
298
|
-
}
|
|
299
|
-
}
|
|
300
|
-
```
|
|
301
|
-
|
|
302
|
-
**提取要求**:
|
|
303
|
-
- `@Component export struct` 或 `@Component struct` 组件名
|
|
304
|
-
- Props 读取方式和读取的 Prop 名列表
|
|
305
|
-
- Command 注册方式和注册的 Command 名列表
|
|
306
|
-
- 事件发送方式和发送的事件名列表
|
|
307
|
-
- 组件文件路径和关键行号
|
|
308
|
-
|
|
309
|
-
#### 2A.6 步骤 5f:定位 C++ Package 注册层
|
|
310
|
-
|
|
311
|
-
| 项目 | 说明 |
|
|
312
|
-
|------|------|
|
|
313
|
-
| 搜索位置 | `harmony/<module_name>/src/main/cpp/` 目录 |
|
|
314
|
-
| 搜索关键词 | `*Package.h`、`*Package.cpp`、`generated/RNOH/` |
|
|
315
|
-
| 目的 | 定位 C++ 层的组件注册和 TurboModule 注册,提取 JSIBinder 和 NapiBinder 映射 |
|
|
316
|
-
|
|
317
|
-
**C++ Package 的两种模式**:
|
|
318
|
-
|
|
319
|
-
```cpp
|
|
320
|
-
// 模式 1:Thin Wrapper(如 react-native-webview、react-native-video、react-native-screens 等)
|
|
321
|
-
// 仅继承 generated BaseReactNative*Package,不重写任何方法
|
|
322
|
-
class WebViewPackage : public BaseReactNativeWebViewPackage {
|
|
323
|
-
using Super = BaseReactNativeWebViewPackage;
|
|
324
|
-
// 所有注册逻辑由 generated BaseReactNativeWebViewPackage 提供
|
|
325
|
-
};
|
|
326
|
-
|
|
327
|
-
// 模式 2:Hand-Written Package(如 react-native-maps、react-native-svg 等)
|
|
328
|
-
// 手动实现所有注册方法,不依赖 generated
|
|
329
|
-
class MapsPackage : public Package {
|
|
330
|
-
MapsPackage(Package::Context ctx) : Package(ctx) {}
|
|
331
|
-
|
|
332
|
-
std::vector<react::ComponentDescriptorProvider> createComponentDescriptorProviders() {
|
|
333
|
-
return {
|
|
334
|
-
// 手动列出每个组件的 DescriptorProvider
|
|
335
|
-
facebook::react::AIRMapComponentDescriptorProvider(),
|
|
336
|
-
facebook::react::AIRMapMarkerComponentDescriptorProvider(),
|
|
337
|
-
};
|
|
338
|
-
}
|
|
339
|
-
|
|
340
|
-
ComponentJSIBinderByString createComponentJSIBinderByName() {
|
|
341
|
-
return {
|
|
342
|
-
// 手动列出每个组件名 → JSIBinder 映射
|
|
343
|
-
{"AIRMap", std::make_shared<AIRMapJSIBinder>()},
|
|
344
|
-
{"AIRMapMarker", std::make_shared<AIRMapMarkerJSIBinder>()},
|
|
345
|
-
};
|
|
346
|
-
}
|
|
347
|
-
|
|
348
|
-
ComponentNapiBinderByString createComponentNapiBinderByName() {
|
|
349
|
-
return {
|
|
350
|
-
// 手动列出每个组件名 → NapiBinder 映射
|
|
351
|
-
{"AIRMap", std::make_shared<AIRMapNapiBinder>()},
|
|
352
|
-
};
|
|
353
|
-
}
|
|
354
|
-
|
|
355
|
-
std::unique_ptr<TurboModuleFactoryDelegate> createTurboModuleFactoryDelegate() {
|
|
356
|
-
return std::make_unique<MapsTurboModuleFactoryDelegate>();
|
|
357
|
-
}
|
|
358
|
-
};
|
|
359
|
-
```
|
|
360
|
-
|
|
361
|
-
> ⚠️ **关键区别**:Thin Wrapper 模式的所有注册逻辑在 `generated/RNOH/generated/BaseReactNative*Package.h` 中自动生成,组件名、JSIBinder、NapiBinder、EventEmitRequestHandler 等均由 codegen 产出,不需要手动维护。Hand-Written 模式需手动实现所有注册方法。
|
|
362
|
-
|
|
363
|
-
**generated C++ 目录结构(Codegen 架构专属)**:
|
|
364
|
-
|
|
365
|
-
```
|
|
366
|
-
harmony/<module_name>/src/main/cpp/generated/RNOH/generated/
|
|
367
|
-
BaseReactNative<LibName>Package.h ← 自动生成的 Package 基类
|
|
368
|
-
# 包含:
|
|
369
|
-
# BaseReactNative*PackageTurboModuleFactoryDelegate ← TurboModule 工厂
|
|
370
|
-
# BaseReactNative*PackageEventEmitRequestHandler ← 事件处理器
|
|
371
|
-
# BaseReactNative*Package ← Package 基类
|
|
372
|
-
# createComponentDescriptorProviders() ← 自动生成的组件列表
|
|
373
|
-
# createComponentJSIBinderByName() ← 自动生成的 JSIBinder 映射
|
|
374
|
-
# createComponentNapiBinderByName() ← 自动生成的 NapiBinder 映射
|
|
375
|
-
# createTurboModuleFactoryDelegate() ← 自动生成的 TurboModule 工厂
|
|
376
|
-
|
|
377
|
-
components/
|
|
378
|
-
ComponentNameJSIBinder.h ← 自动生成的 JSIBinder(含 Props 序列化)
|
|
379
|
-
ComponentNameNapiBinder.h ← 自动生成的 NapiBinder(含 ArkTS ↔ C++ 属性绑定)
|
|
380
|
-
|
|
381
|
-
turboModules/
|
|
382
|
-
TurboModuleNameJSIBinder.h ← 自动生成的 TurboModule JSIBinder
|
|
383
|
-
```
|
|
384
|
-
|
|
385
|
-
**C++ JSIBinder 的关键结构(Props 序列化)**:
|
|
386
|
-
|
|
387
|
-
```cpp
|
|
388
|
-
// generated/components/RNCWebViewJSIBinder.h(Codegen 自动生成)
|
|
389
|
-
class RNCWebViewJSIBinder : public ViewComponentJSIBinder {
|
|
390
|
-
facebook::jsi::Object createJSIBinder(facebook::jsi::Runtime &rt) override {
|
|
391
|
-
auto obj = ViewComponentJSIBinder::createJSIBinder(rt);
|
|
392
|
-
// 每个 Prop 的序列化:propName → runtime 中写入
|
|
393
|
-
obj.setProperty(rt, "allowFileAccess", createValue(rt, allowFileAccess_));
|
|
394
|
-
obj.setProperty(rt, "javaScriptEnabled", createValue(rt, javaScriptEnabled_));
|
|
395
|
-
obj.setProperty(rt, "cacheMode", createValue(rt, cacheMode_));
|
|
396
|
-
// ... 所有 Props 逐一序列化
|
|
397
|
-
return obj;
|
|
398
|
-
}
|
|
399
|
-
|
|
400
|
-
// Props 值存储(通常为默认值或从 rawProps 读取)
|
|
401
|
-
bool allowFileAccess_ = false;
|
|
402
|
-
bool javaScriptEnabled_ = true;
|
|
403
|
-
std::string cacheMode_ = "LOAD_DEFAULT";
|
|
404
|
-
};
|
|
405
|
-
|
|
406
|
-
// Hand-Written JSIBinder(如 react-native-maps)
|
|
407
|
-
class AIRMapJSIBinder : public ViewComponentJSIBinder {
|
|
408
|
-
facebook::jsi::Object createJSIBinder(facebook::jsi::Runtime &rt) override {
|
|
409
|
-
auto obj = ViewComponentJSIBinder::createJSIBinder(rt);
|
|
410
|
-
obj.setProperty(rt, "provider", createValue(rt, provider_));
|
|
411
|
-
obj.setProperty(rt, "mapType", createValue(rt, mapType_));
|
|
412
|
-
obj.setProperty(rt, "zoomEnabled", createValue(rt, zoomEnabled_));
|
|
413
|
-
// ... 手动列出所有 Props
|
|
414
|
-
return obj;
|
|
415
|
-
}
|
|
416
|
-
std::string provider_;
|
|
417
|
-
std::string mapType_;
|
|
418
|
-
bool zoomEnabled_;
|
|
419
|
-
};
|
|
420
|
-
```
|
|
421
|
-
|
|
422
|
-
> ⚠️ **JSIBinder 是 C++ 层 Props 定义的关键文件**:`createJSIBinder()` 方法中的 `obj.setProperty(rt, "propName", ...)` 列出了该组件在 C++ 层注册的所有 Prop 名和默认值。这与 OHOS ArkTS `DirectRawProps`/`PropsSelector` 应完全一致。
|
|
423
|
-
|
|
424
|
-
**C++ NapiBinder 的关键结构(ArkTS ↔ C++ 属性桥接)**:
|
|
425
|
-
|
|
426
|
-
```cpp
|
|
427
|
-
class RNCWebViewNapiBinder : public ViewComponentNapiBinder {
|
|
428
|
-
napi_value createNapiBinder(napi_env env, napi_value thisObj) override {
|
|
429
|
-
// 将 ArkTS @Component struct 的属性绑定到 C++ 实例
|
|
430
|
-
NapiBinder::setProperty(env, thisObj, "javaScriptEnabled", javaScriptEnabled_);
|
|
431
|
-
NapiBinder::setProperty(env, thisObj, "cacheMode", cacheMode_);
|
|
432
|
-
// ... 所有从 ArkTS 读取的 Props
|
|
433
|
-
return thisObj;
|
|
434
|
-
}
|
|
435
|
-
};
|
|
436
|
-
```
|
|
437
|
-
|
|
438
|
-
**C++ EventEmitRequestHandler(事件发送桥接)**:
|
|
439
|
-
|
|
440
|
-
```cpp
|
|
441
|
-
// generated 中自动生成
|
|
442
|
-
class BaseReactNativeWebViewPackageEventEmitRequestHandler : public EventEmitRequestHandler {
|
|
443
|
-
void handleEvent(ConcurrentMessageQueue &mq, std::string eventName, napi_value eventPayload) override {
|
|
444
|
-
// 事件名 → JS 层事件映射
|
|
445
|
-
if (eventName == "onNavigationStateChange") { /* 处理 */ }
|
|
446
|
-
if (eventName == "onMessage") { /* 处理 */ }
|
|
447
|
-
// ...
|
|
448
|
-
}
|
|
449
|
-
};
|
|
450
|
-
```
|
|
451
|
-
|
|
452
|
-
**C++ TurboModuleFactoryDelegate(TurboModule 注册)**:
|
|
453
|
-
|
|
454
|
-
```cpp
|
|
455
|
-
// generated 中自动生成
|
|
456
|
-
class BaseReactNativeWebViewPackageTurboModuleFactoryDelegate : public TurboModuleFactoryDelegate {
|
|
457
|
-
std::unique_ptr<TurboModule> createTurboModule(std::string turboModuleName, TurboModule::Context ctx) override {
|
|
458
|
-
if (turboModuleName == "RNCWebViewModule") {
|
|
459
|
-
return std::make_unique<RNCWebViewModule>(ctx);
|
|
460
|
-
}
|
|
461
|
-
return nullptr;
|
|
462
|
-
}
|
|
463
|
-
};
|
|
464
|
-
|
|
465
|
-
// Hand-Written TurboModuleFactoryDelegate(如 react-native-maps)
|
|
466
|
-
class MapsTurboModuleFactoryDelegate : public TurboModuleFactoryDelegate {
|
|
467
|
-
std::unique_ptr<TurboModule> createTurboModule(std::string turboModuleName, TurboModule::Context ctx) override {
|
|
468
|
-
if (turboModuleName == "AIRMapManager") {
|
|
469
|
-
return std::make_unique<AIRMapManagerTurboModule>(ctx);
|
|
470
|
-
}
|
|
471
|
-
if (turboModuleName == "AIRMapMarkerManager") {
|
|
472
|
-
return std::make_shared<AIRMapMarkerManagerTurboModule>(ctx);
|
|
473
|
-
}
|
|
474
|
-
return nullptr;
|
|
475
|
-
}
|
|
476
|
-
};
|
|
477
|
-
```
|
|
478
|
-
|
|
479
|
-
**C++ ComponentInstanceFactoryDelegate(组件实例创建)**:
|
|
480
|
-
|
|
481
|
-
```cpp
|
|
482
|
-
// 如 react-native-svg 的 C++ Package
|
|
483
|
-
class SVGPackageComponentInstanceFactoryDelegate : public ComponentInstanceFactoryDelegate {
|
|
484
|
-
ComponentInstance::Shared createComponentInstance(const ComponentInstance::Context &ctx) override {
|
|
485
|
-
// 根据组件名创建对应的 C++ 组件实例
|
|
486
|
-
if (ctx.componentName == "RNSVGSvgView") {
|
|
487
|
-
return std::make_shared<RNSVGSvgViewComponentInstance>(ctx);
|
|
488
|
-
}
|
|
489
|
-
if (ctx.componentName == "RNSVGCircle") {
|
|
490
|
-
return std::make_shared<RNSVGCircleComponentInstance>(ctx);
|
|
491
|
-
}
|
|
492
|
-
// ...
|
|
493
|
-
}
|
|
494
|
-
};
|
|
495
|
-
```
|
|
496
|
-
|
|
497
|
-
> ⚠️ **ComponentInstanceFactoryDelegate 仅在需要 C++ 原生视图的组件中出现**。大多数 Codegen 架构的组件不使用此模式(视图完全由 ArkTS 渲染),但像 react-native-svg 这种复杂组件需要 C++ 层创建原生视图实例。
|
|
498
|
-
|
|
499
|
-
**CMakeLists.txt 分析**:
|
|
500
|
-
|
|
501
|
-
```cmake
|
|
502
|
-
# CMakeLists.txt 列出了所有编译的 C++ 源文件
|
|
503
|
-
add_library(rnoh_webview SHARED
|
|
504
|
-
WebViewPackage.cpp # 手写的 Package 实现
|
|
505
|
-
generated/RNOH/generated/RNCWebViewJSIBinder.cpp
|
|
506
|
-
generated/RNOH/generated/RNCWebViewNapiBinder.cpp
|
|
507
|
-
# ... 其他 generated 源文件
|
|
508
|
-
)
|
|
509
|
-
target_link_libraries(rnoh_webview PUBLIC rnoh_core)
|
|
510
|
-
```
|
|
511
|
-
|
|
512
|
-
**提取要求**:
|
|
513
|
-
- C++ Package 类名和继承模式(Thin Wrapper vs Hand-Written)
|
|
514
|
-
- 若为 Thin Wrapper,定位 `generated/RNOH/generated/BaseReactNative*Package.h` 并提取:
|
|
515
|
-
- `createComponentDescriptorProviders()` 中所有组件名
|
|
516
|
-
- `createComponentJSIBinderByName()` 中所有组件名 → JSIBinder 映射
|
|
517
|
-
- `createComponentNapiBinderByName()` 中所有组件名 → NapiBinder 映射
|
|
518
|
-
- `BaseReactNative*PackageEventEmitRequestHandler` 中所有事件名
|
|
519
|
-
- `BaseReactNative*PackageTurboModuleFactoryDelegate` 中所有 TurboModule 名
|
|
520
|
-
- 若为 Hand-Written,从 Package.h/cpp 中直接提取上述信息
|
|
521
|
-
- 从每个组件的 JSIBinder 中提取所有 Prop 名 + 默认值(`obj.setProperty(rt, "propName", ...)` 模式)
|
|
522
|
-
- 从每个组件的 NapiBinder 中提取 ArkTS → C++ 属性桥接的 Prop 名
|
|
523
|
-
- 从 TurboModuleFactoryDelegate 中提取所有 TurboModule 名
|
|
524
|
-
- 从 ComponentInstanceFactoryDelegate 中提取所有组件实例名(如有)
|
|
525
|
-
- CMakeLists.txt 中编译的源文件列表
|
|
526
|
-
- 若 C++ 层无组件注册,标注"⚠️ C++ 层无组件注册"
|
|
527
|
-
|
|
528
|
-
---
|
|
529
|
-
|
|
530
|
-
### 2B. Legacy/Descriptor 架构注册链路定位
|
|
531
|
-
|
|
532
|
-
此流程适用于 JS 层使用 `requireNativeComponent` 的库,或 JS 层无组件注册宏但 OHOS 层有 `@Component struct` 实现的库(如 react-native-maps、react-native-svg 等)。
|
|
533
|
-
|
|
534
|
-
#### 2B.1 步骤 5a:定位 JS 层组件注册
|
|
535
|
-
|
|
536
|
-
| 项目 | 说明 |
|
|
537
|
-
|------|------|
|
|
538
|
-
| 搜索位置 | RN 库 `src/` 目录及其子目录 |
|
|
539
|
-
| 搜索关键词 | `requireNativeComponent` |
|
|
540
|
-
| 目的 | 定位 Legacy 原生组件注册,提取组件名 |
|
|
541
|
-
|
|
542
|
-
**代码模式**:
|
|
543
|
-
|
|
544
|
-
```typescript
|
|
545
|
-
// requireNativeComponent 直接注册
|
|
546
|
-
const RNCWebView = requireNativeComponent<NativeProps>('RNCWebView');
|
|
547
|
-
|
|
548
|
-
// react-native-maps 的封装模式
|
|
549
|
-
function getNativeComponentName(provider, componentName) {
|
|
550
|
-
return provider === 'google'
|
|
551
|
-
? `AIRGoogle${componentName}`
|
|
552
|
-
: `AIR${componentName}`;
|
|
553
|
-
}
|
|
554
|
-
components[key] = requireNativeComponent(nativeComponentName);
|
|
555
|
-
|
|
556
|
-
// 典型 requireNativeComponent 注册
|
|
557
|
-
export default requireNativeComponent<NativeProps>('AIRMap');
|
|
558
|
-
```
|
|
559
|
-
|
|
560
|
-
> ⚠️ **动态组件名**:`requireNativeComponent` 的组件名参数可能是动态拼接的(如 react-native-maps 的 `AIRMap` vs `AIRGoogleMap`),需追踪完整的命名逻辑。
|
|
561
|
-
|
|
562
|
-
**无 JS 层组件注册的特殊情况**:
|
|
563
|
-
|
|
564
|
-
```typescript
|
|
565
|
-
// react-native-svg 在 JS 层不使用 requireNativeComponent 或 codegenNativeComponent
|
|
566
|
-
// 其原生组件通过纯 ArkTS/C++ 层注册,JS 层仅使用 SVG XML 渲染
|
|
567
|
-
// 此时需跳过 JS 层搜索,直接从 OHOS 层开始定位
|
|
568
|
-
```
|
|
569
|
-
|
|
570
|
-
**提取要求**:
|
|
571
|
-
- 所有 `requireNativeComponent` 注册的组件名(含动态拼接逻辑)
|
|
572
|
-
- 组件对应的 Props 类型定义文件路径
|
|
573
|
-
- 若 JS 层无组件注册宏,标注"⚠️ JS 层无原生组件注册宏,从 OHOS 层直接定位"
|
|
574
|
-
|
|
575
|
-
#### 2B.2 步骤 5b:定位 OHOS Harmony 目录
|
|
576
|
-
|
|
577
|
-
同 2A.2,此处不再重复。
|
|
578
|
-
|
|
579
|
-
#### 2B.3 步骤 5c:定位 Package 注册类和 ComponentFactory
|
|
580
|
-
|
|
581
|
-
| 项目 | 说明 |
|
|
582
|
-
|------|------|
|
|
583
|
-
| 搜索位置 | `harmony/<module_name>/src/main/ets/` 目录 |
|
|
584
|
-
| 搜索关键词 | `Package`、`ComponentFactory` |
|
|
585
|
-
| 目的 | 定位 Package 注册类和组件路由机制 |
|
|
586
|
-
|
|
587
|
-
**Legacy 架构的 Package 模式**:
|
|
588
|
-
|
|
589
|
-
```typescript
|
|
590
|
-
// 仅注册 TurboModule 的 Package(如 react-native-maps)
|
|
591
|
-
export class MapsPackage extends RNPackage {
|
|
592
|
-
createTurboModulesFactory(ctx: TurboModuleContext): TurboModulesFactory {
|
|
593
|
-
return new MapsTurboModulesFactory(ctx); // 仅 TurboModule,无 createDescriptorWrapperFactoryByDescriptorType
|
|
594
|
-
}
|
|
595
|
-
}
|
|
596
|
-
|
|
597
|
-
// 仅注册 TurboModule 的 Package(如 react-native-svg)
|
|
598
|
-
export class SvgPackage extends RNPackage {
|
|
599
|
-
createTurboModulesFactory(ctx: TurboModuleContext): TurboModulesFactory {
|
|
600
|
-
return new SvgTurboModulesFactory(ctx); // 仅 TurboModule,无组件注册
|
|
601
|
-
}
|
|
602
|
-
}
|
|
603
|
-
```
|
|
604
|
-
|
|
605
|
-
> ⚠️ **关键区别**:Legacy 架构的 Package 可能**不包含** `createDescriptorWrapperFactoryByDescriptorType` 方法。原生组件的注册通过其他机制实现(C++ Package、ComponentFactory、descriptorRegistry),而非 ArkTS Package。
|
|
606
|
-
|
|
607
|
-
**ComponentFactory 路由模式**:
|
|
608
|
-
|
|
609
|
-
```typescript
|
|
610
|
-
// 多组件库的 ComponentFactory 路由(如 react-native-maps)
|
|
611
|
-
@Component
|
|
612
|
-
export struct MapsComponentFactory {
|
|
613
|
-
public ctx!: RNComponentContext;
|
|
614
|
-
public tag: number = 0;
|
|
615
|
-
@State private componentName: string = '';
|
|
616
|
-
|
|
617
|
-
setDescriptor(newDescriptor: Descriptor) {
|
|
618
|
-
this.componentName = newDescriptor.type; // 从 descriptor 提取组件名
|
|
619
|
-
}
|
|
620
|
-
|
|
621
|
-
build() {
|
|
622
|
-
if (this.componentName === AIR_MAP_MARKER_TYPE) {
|
|
623
|
-
AIRMapMarker({ ctx: this.ctx, tag: this.tag })
|
|
624
|
-
} else if (this.componentName === AIR_MAP_POLYLINE_TYPE) {
|
|
625
|
-
AIRMapPolyline({ ctx: this.ctx, tag: this.tag })
|
|
626
|
-
} else if (this.componentName === AIR_MAP_CIRCLE_TYPE) {
|
|
627
|
-
AIRMapCircle({ ctx: this.ctx, tag: this.tag })
|
|
628
|
-
}
|
|
629
|
-
// ... 更多组件路由
|
|
630
|
-
}
|
|
631
|
-
}
|
|
632
|
-
```
|
|
633
|
-
|
|
634
|
-
**提取要求**:
|
|
635
|
-
- Package 类名和继承关系
|
|
636
|
-
- Package 中是否有 `createDescriptorWrapperFactoryByDescriptorType`(若无则标注"⚠️ Package 无组件注册方法,组件通过其他机制注册")
|
|
637
|
-
- TurboModule 名列表
|
|
638
|
-
- 若有 ComponentFactory,提取所有路由的组件名列表
|
|
639
|
-
- C++ Package 中注册的组件名(如有 `*Package.h`/`*Package.cpp`)
|
|
640
|
-
|
|
641
|
-
#### 2B.4 步骤 5d:定位手动定义的 Descriptor 类型
|
|
642
|
-
|
|
643
|
-
| 项目 | 说明 |
|
|
644
|
-
|------|------|
|
|
645
|
-
| 搜索位置 | `harmony/<module_name>/src/main/ets/` 目录 |
|
|
646
|
-
| 搜索关键词 | `Descriptor<`、`RawProps extends ViewRawProps` |
|
|
647
|
-
| 目的 | 定位手动定义的组件 Descriptor 类型(替代 generated/ 目录) |
|
|
648
|
-
|
|
649
|
-
**手动 Descriptor 定义模式**:
|
|
650
|
-
|
|
651
|
-
```typescript
|
|
652
|
-
// react-native-maps 的手动 Descriptor 定义
|
|
653
|
-
export interface AIRMapRawProps extends ViewRawProps {
|
|
654
|
-
cacheEnabled?: boolean;
|
|
655
|
-
camera?: Camera;
|
|
656
|
-
region?: Region;
|
|
657
|
-
mapType?: MapType;
|
|
658
|
-
zoomEnabled: boolean;
|
|
659
|
-
scrollEnabled: boolean;
|
|
660
|
-
showsUserLocation: boolean;
|
|
661
|
-
// ...
|
|
662
|
-
}
|
|
663
|
-
export type AIRMapDescriptor = Descriptor<"AIRMap", ViewBaseProps, AIRMapState, AIRMapRawProps>
|
|
664
|
-
```
|
|
665
|
-
|
|
666
|
-
> ⚠️ **区别**:Codegen 架构的 Descriptor 从 `generated/` 自动生成,Legacy 架构的 Descriptor 是**手动定义**的。手动定义的 RawProps 接口直接 `extends ViewRawProps`,类型为 `Descriptor<...>` 而非通过 `DescriptorWrapper`。
|
|
667
|
-
|
|
668
|
-
**提取要求**:
|
|
669
|
-
- 所有 `*RawProps` 接口中定义的 Prop 名 + 类型
|
|
670
|
-
- 所有 `*Descriptor` 类型定义(组件名 + 泛型参数)
|
|
671
|
-
- Descriptor 定义文件路径和行号
|
|
672
|
-
|
|
673
|
-
#### 2B.5 步骤 5e:定位 ArkTS 组件实现
|
|
674
|
-
|
|
675
|
-
| 项目 | 说明 |
|
|
676
|
-
|------|------|
|
|
677
|
-
| 搜索位置 | `harmony/<module_name>/src/main/ets/` 目录(及子目录如 `AIRMaps/`) |
|
|
678
|
-
| 搜索关键词 | `@Component` |
|
|
679
|
-
| 目的 | 定位所有 `@Component struct` 实现 |
|
|
680
|
-
|
|
681
|
-
**Legacy 架构的 ArkTS 组件实现模式**:
|
|
682
|
-
|
|
683
|
-
```typescript
|
|
684
|
-
// 典型 Legacy 架构实现(如 AIRMap)
|
|
685
|
-
@Component
|
|
686
|
-
export struct AIRMap {
|
|
687
|
-
ctx!: RNComponentContext
|
|
688
|
-
tag: number = 0
|
|
689
|
-
@State descriptor: AIRMapDescriptor = {} as AIRMapDescriptor
|
|
690
|
-
|
|
691
|
-
aboutToAppear() {
|
|
692
|
-
// Props 读取:通过 descriptorRegistry + 手动 Descriptor
|
|
693
|
-
this.descriptor = this.ctx.descriptorRegistry.getDescriptor<AIRMapDescriptor>(this.tag)
|
|
694
|
-
this.descriptor.rawProps.javaScriptEnabled
|
|
695
|
-
this.descriptor.rawProps.scrollEnabled
|
|
696
|
-
}
|
|
697
|
-
|
|
698
|
-
// 动态 Props 更新:订阅 descriptor 变化
|
|
699
|
-
aboutToAppear() {
|
|
700
|
-
this.cleanUpCallbacks.push(this.ctx.descriptorRegistry.subscribeToDescriptorChanges(
|
|
701
|
-
this.tag, (newDescriptor) => {
|
|
702
|
-
this.descriptor = newDescriptor as AIRMapDescriptor
|
|
703
|
-
this.mapController?.setZoomGesturesEnabled(this.descriptor.rawProps.zoomEnabled)
|
|
704
|
-
}
|
|
705
|
-
));
|
|
706
|
-
}
|
|
707
|
-
|
|
708
|
-
// Commands 注册:通过 ctx.componentCommandReceiver
|
|
709
|
-
aboutToAppear() {
|
|
710
|
-
this.ctx.componentCommandReceiver.registerCommandCallback(
|
|
711
|
-
this.tag,
|
|
712
|
-
(command, args) => {
|
|
713
|
-
// switch/if 分发命令
|
|
714
|
-
}
|
|
715
|
-
)
|
|
716
|
-
}
|
|
717
|
-
|
|
718
|
-
// 事件发送:通过 ctx.rnInstance.emitComponentEvent 或 TurboModule
|
|
719
|
-
this.ctx.rnInstance.emitComponentEvent(this.tag, "onRegionChange", {region: ...})
|
|
720
|
-
}
|
|
721
|
-
```
|
|
722
|
-
|
|
723
|
-
**提取要求**:
|
|
724
|
-
- 所有 `@Component struct` 组件名列表(多组件库可能有 10+ 个组件)
|
|
725
|
-
- 每个组件的 Props 读取方式和 Prop 名列表
|
|
726
|
-
- 每个组件的 Command 注册方式和 Command 名列表
|
|
727
|
-
- 每个组件的事件发送方式和事件名列表
|
|
728
|
-
- 组件文件路径和关键行号
|
|
729
|
-
|
|
730
|
-
#### 2B.6 步骤 5f:定位 C++ Package 注册层
|
|
731
|
-
| 项目 | 说明 |
|
|
732
|
-
|------|------|
|
|
733
|
-
| 搜索位置 | `harmony/<module_name>/src/main/cpp/` 目录 |
|
|
734
|
-
| 搜索关键词 | `*Package.h`、`*Package.cpp`、`*JSIBinder.h`、`*NapiBinder.h`、`ComponentDescriptorProvider` |
|
|
735
|
-
| 目的 | 定位 C++ 层的组件注册、Props 序列化、TurboModule 注册(Legacy 架构的组件主要通过 C++ 注册) |
|
|
736
|
-
|
|
737
|
-
> ⚠️ **Legacy 架构的 C++ Package 是组件注册的核心层**:由于 ArkTS Package 中无 `createDescriptorWrapperFactoryByDescriptorType`,组件的注册完全依赖 C++ Package。C++ Package 的 `createComponentJSIBinderByName()` 和 `createComponentNapiBinderByName()` 定义了组件名 → 绑定器的映射,而 JSIBinder 中列出了每个组件的所有 Props。
|
|
738
|
-
|
|
739
|
-
**Legacy 架构 C++ Package 的 Hand-Written 模式**:
|
|
740
|
-
|
|
741
|
-
```cpp
|
|
742
|
-
// react-native-maps 的 C++ Package(完全手写)
|
|
743
|
-
class MapsPackage : public Package {
|
|
744
|
-
MapsPackage(Package::Context ctx) : Package(ctx) {}
|
|
745
|
-
|
|
746
|
-
std::vector<react::ComponentDescriptorProvider> createComponentDescriptorProviders() override {
|
|
747
|
-
return {
|
|
748
|
-
facebook::react::AIRMapComponentDescriptorProvider(),
|
|
749
|
-
facebook::react::AIRMapMarkerComponentDescriptorProvider(),
|
|
750
|
-
facebook::react::AIRMapPolylineComponentDescriptorProvider(),
|
|
751
|
-
facebook::react::AIRMapPolygonComponentDescriptorProvider(),
|
|
752
|
-
facebook::react::AIRMapCircleComponentDescriptorProvider(),
|
|
753
|
-
// ... 所有组件
|
|
754
|
-
};
|
|
755
|
-
}
|
|
756
|
-
|
|
757
|
-
ComponentJSIBinderByString createComponentJSIBinderByName() override {
|
|
758
|
-
return {
|
|
759
|
-
{"AIRMap", std::make_shared<AIRMapJSIBinder>()},
|
|
760
|
-
{"AIRMapMarker", std::make_shared<AIRMapMarkerJSIBinder>()},
|
|
761
|
-
{"AIRMapPolyline", std::make_shared<AIRMapPolylineJSIBinder>()},
|
|
762
|
-
// ... 组件名 → JSIBinder 映射
|
|
763
|
-
};
|
|
764
|
-
}
|
|
765
|
-
|
|
766
|
-
ComponentNapiBinderByString createComponentNapiBinderByName() override {
|
|
767
|
-
return {
|
|
768
|
-
{"AIRMap", std::make_shared<AIRMapNapiBinder>()},
|
|
769
|
-
// ... 组件名 → NapiBinder 映射
|
|
770
|
-
};
|
|
771
|
-
}
|
|
772
|
-
|
|
773
|
-
std::unique_ptr<TurboModuleFactoryDelegate> createTurboModuleFactoryDelegate() override {
|
|
774
|
-
return std::make_unique<MapsTurboModuleFactoryDelegate>();
|
|
775
|
-
}
|
|
776
|
-
};
|
|
777
|
-
|
|
778
|
-
// react-native-svg 的 C++ Package(大量子组件 + ComponentInstanceFactoryDelegate)
|
|
779
|
-
class SVGPackage : public Package {
|
|
780
|
-
// createComponentDescriptorProviders(): 27+ SVG 子组件
|
|
781
|
-
// createComponentJSIBinderByName(): 27+ 组件名 → JSIBinder
|
|
782
|
-
// createComponentNapiBinderByName(): 返回空 {} (不使用 NapiBinder)
|
|
783
|
-
|
|
784
|
-
// 特殊:使用 ComponentInstanceFactoryDelegate 创建 C++ 原生视图实例
|
|
785
|
-
std::shared_ptr<ComponentInstanceFactoryDelegate> createComponentInstanceFactoryDelegate() override {
|
|
786
|
-
return std::make_shared<SVGPackageComponentInstanceFactoryDelegate>();
|
|
787
|
-
}
|
|
788
|
-
};
|
|
789
|
-
|
|
790
|
-
class SVGPackageComponentInstanceFactoryDelegate : public ComponentInstanceFactoryDelegate {
|
|
791
|
-
ComponentInstance::Shared createComponentInstance(const ComponentInstance::Context &ctx) override {
|
|
792
|
-
if (ctx.componentName == "RNSVGSvgView") {
|
|
793
|
-
return std::make_shared<RNSVGSvgViewComponentInstance>(ctx);
|
|
794
|
-
}
|
|
795
|
-
if (ctx.componentName == "RNSVGCircle") {
|
|
796
|
-
return std::make_shared<RNSVGCircleComponentInstance>(ctx);
|
|
797
|
-
}
|
|
798
|
-
// ... 每个组件创建对应的 C++ 实例
|
|
799
|
-
}
|
|
800
|
-
};
|
|
801
|
-
```
|
|
802
|
-
|
|
803
|
-
**Legacy 架构的 JSIBinder 结构(Props 序列化)**:
|
|
804
|
-
|
|
805
|
-
```cpp
|
|
806
|
-
// AIRMapJSIBinder.h
|
|
807
|
-
class AIRMapJSIBinder : public ViewComponentJSIBinder {
|
|
808
|
-
facebook::jsi::Object createJSIBinder(facebook::jsi::Runtime &rt) override {
|
|
809
|
-
auto obj = ViewComponentJSIBinder::createJSIBinder(rt);
|
|
810
|
-
obj.setProperty(rt, "provider", createValue(rt, provider_));
|
|
811
|
-
obj.setProperty(rt, "mapType", createValue(rt, mapType_));
|
|
812
|
-
obj.setProperty(rt, "zoomEnabled", createValue(rt, zoomEnabled_));
|
|
813
|
-
obj.setProperty(rt, "scrollEnabled", createValue(rt, scrollEnabled_));
|
|
814
|
-
obj.setProperty(rt, "showsUserLocation", createValue(rt, showsUserLocation_));
|
|
815
|
-
// ... 手动列出所有 Props
|
|
816
|
-
return obj;
|
|
817
|
-
}
|
|
818
|
-
|
|
819
|
-
// Props 默认值
|
|
820
|
-
std::string provider_ = "google";
|
|
821
|
-
std::string mapType_ = "standard";
|
|
822
|
-
bool zoomEnabled_ = true;
|
|
823
|
-
bool scrollEnabled_ = true;
|
|
824
|
-
bool showsUserLocation_ = false;
|
|
825
|
-
};
|
|
826
|
-
|
|
827
|
-
// SVG 子组件的 JSIBinder(继承 ViewComponentJSIBinder)
|
|
828
|
-
class RNSVGSvgViewJSIBinder : public ViewComponentJSIBinder {
|
|
829
|
-
facebook::jsi::Object createJSIBinder(facebook::jsi::Runtime &rt) override {
|
|
830
|
-
auto obj = ViewComponentJSIBinder::createJSIBinder(rt);
|
|
831
|
-
obj.setProperty(rt, "bbWidth", createValue(rt, bbWidth_));
|
|
832
|
-
obj.setProperty(rt, "bbHeight", createValue(rt, bbHeight_));
|
|
833
|
-
// ...
|
|
834
|
-
return obj;
|
|
835
|
-
}
|
|
836
|
-
};
|
|
837
|
-
```
|
|
838
|
-
|
|
839
|
-
**Legacy 架构的 TurboModuleFactoryDelegate**:
|
|
840
|
-
|
|
841
|
-
```cpp
|
|
842
|
-
class MapsTurboModuleFactoryDelegate : public TurboModuleFactoryDelegate {
|
|
843
|
-
std::unique_ptr<TurboModule> createTurboModule(std::string turboModuleName, TurboModule::Context ctx) override {
|
|
844
|
-
if (turboModuleName == "AIRMapManager") {
|
|
845
|
-
return std::make_unique<AIRMapManagerTurboModule>(ctx);
|
|
846
|
-
}
|
|
847
|
-
if (turboModuleName == "AIRMapMarkerManager") {
|
|
848
|
-
return std::make_unique<AIRMapMarkerManagerTurboModule>(ctx);
|
|
849
|
-
}
|
|
850
|
-
return nullptr;
|
|
851
|
-
}
|
|
852
|
-
};
|
|
853
|
-
```
|
|
854
|
-
|
|
855
|
-
**提取要求**:
|
|
856
|
-
- C++ Package 类名和继承模式(全部 Hand-Written)
|
|
857
|
-
- `createComponentDescriptorProviders()` 中注册的所有组件名
|
|
858
|
-
- `createComponentJSIBinderByName()` 中所有组件名 → JSIBinder 映射
|
|
859
|
-
- `createComponentNapiBinderByName()` 中所有组件名 → NapiBinder 映射
|
|
860
|
-
- 每个 JSIBinder 中 `obj.setProperty(rt, "propName", ...)` 列出的所有 Prop 名 + 默认值
|
|
861
|
-
- `createTurboModuleFactoryDelegate()` 或直接 `TurboModuleFactoryDelegate` 中所有 TurboModule 名
|
|
862
|
-
- `createComponentInstanceFactoryDelegate()` 中所有组件实例名(如有,如 react-native-svg)
|
|
863
|
-
- CMakeLists.txt 中编译的源文件列表
|
|
864
|
-
- 若 C++ 层无组件注册,标注"⚠️ C++ 层无组件注册"
|
|
865
|
-
|
|
866
|
-
---
|
|
867
|
-
|
|
868
|
-
## 3. 搜索结果记录模板
|
|
869
|
-
|
|
870
|
-
完成定位流程后,必须将结果整理为以下格式。根据架构模式选择对应模板。
|
|
871
|
-
|
|
872
|
-
### 3.1 Codegen 架构注册链路表
|
|
873
|
-
|
|
874
|
-
```markdown
|
|
875
|
-
| 原生组件名 | JS 层注册文件:行号 | NativeProps 类型文件 | generated 类型文件 | Package 注册文件:行号 | C++ Package 模式 | C++ JSIBinder 文件 | ArkTS 实现文件:行号 |
|
|
876
|
-
|------------|-------------------|--------------------|--------------------|---------------------|----------------|-------------------|---------------------|
|
|
877
|
-
| RNCWebView | RNCWebViewNativeComponent.ts:355 | RNCWebViewNativeComponent.ts:151 | generated/components/RNCWebView.ts:19 | RNCWebViewPackage.ets:16 | Thin Wrapper (BaseReactNativeWebViewPackage) | generated/RNOH/generated/components/RNCWebViewJSIBinder.h | RNCWebView.ets:51 |
|
|
878
|
-
| RNCVideo | VideoNativeComponent.ts:409 | VideoNativeComponent.ts:22 | generated/components/RNCVideo.ts:19 | RNCVideoPackage.ts:54 | Thin Wrapper (BaseReactNativeVideoPackage) | generated/RNOH/generated/components/RNCVideoJSIBinder.h | RNCVideo.ets:108 |
|
|
879
|
-
```
|
|
880
|
-
|
|
881
|
-
### 3.2 Legacy 架构注册链路表
|
|
882
|
-
|
|
883
|
-
```markdown
|
|
884
|
-
| 原生组件名 | JS 层注册方式 | JS 注册文件:行号 | Descriptor 类型文件 | ComponentFactory 文件 | Package 注册文件:行号 | C++ Package 模式 | C++ JSIBinder 文件 | ArkTS 实现文件:行号 |
|
|
885
|
-
|------------|-------------|-----------------|--------------------|----------------------|---------------------|----------------|-------------------|---------------------|
|
|
886
|
-
| AIRMap | requireNativeComponent | MapViewNativeComponent.ts:1226 | AIRMapDescriptorTypes.ts:69 | MapsComponentFactory.ets:48 | MapsPackage.ts:48 | Hand-Written (MapsPackage) | AIRMapJSIBinder.h | AIRMaps/AIRMap.ets:47 |
|
|
887
|
-
| AIRMapMarker | requireNativeComponent | MapMarkerNativeComponent.ts | AIRMapDescriptorTypes.ts:86 | MapsComponentFactory.ets:76 | MapsPackage.ts:48 | Hand-Written (MapsPackage) | AIRMapMarkerJSIBinder.h | AIRMaps/AIRMapMarker.ets:31 |
|
|
888
|
-
```
|
|
889
|
-
|
|
890
|
-
### 3.3 完整搜索记录示例
|
|
891
|
-
|
|
892
|
-
**Codegen 架构示例(react-native-webview)**:
|
|
893
|
-
|
|
894
|
-
```
|
|
895
|
-
模式判定: Codegen 架构(codegenNativeComponent)
|
|
896
|
-
|
|
897
|
-
5a: src/RNCWebViewNativeComponent.ts
|
|
898
|
-
→ codegenNativeComponent<NativeProps>('RNCWebView') as HostComponent<NativeProps>
|
|
899
|
-
→ 组件名: "RNCWebView"
|
|
900
|
-
→ NativeProps 接口: 35+ Props + 11 Commands
|
|
901
|
-
|
|
902
|
-
5b: harmony/rn_webview/
|
|
903
|
-
→ 模块名: rn_webview
|
|
904
|
-
|
|
905
|
-
5c: harmony/rn_webview/src/main/ets/RNCWebViewPackage.ets
|
|
906
|
-
→ class RNCWebViewPackage extends RNOHPackage
|
|
907
|
-
→ createDescriptorWrapperFactoryByDescriptorType: { "RNCWebView": RNC.RNCWebView.DescriptorWrapper }
|
|
908
|
-
→ createAnyThreadTurboModuleFactory: WebViewTurboModulesFactory
|
|
909
|
-
→ TurboModule: RNCWebViewModule.NAME
|
|
910
|
-
|
|
911
|
-
5d: harmony/rn_webview/src/main/ets/generated/components/RNCWebView.ts
|
|
912
|
-
→ NAME = "RNCWebView"
|
|
913
|
-
→ DirectRawProps: 50+ Props with types
|
|
914
|
-
→ PropsSelector: default values for each prop
|
|
915
|
-
→ EventPayloadByName: 14 events
|
|
916
|
-
→ CommandArgvByName: 11 commands
|
|
917
|
-
|
|
918
|
-
5e: harmony/rn_webview/src/main/ets/RNCWebView.ets
|
|
919
|
-
→ @Component export struct RNCWebView
|
|
920
|
-
→ 包含 Props 处理、事件发送、命令回调注册
|
|
921
|
-
|
|
922
|
-
5f: harmony/rn_webview/src/main/cpp/WebViewPackage.h
|
|
923
|
-
→ C++ Package 模式: Thin Wrapper (继承 BaseReactNativeWebViewPackage)
|
|
924
|
-
→ generated/RNOH/generated/BaseReactNativeWebViewPackage.h:
|
|
925
|
-
→ createComponentDescriptorProviders: [RNCWebView]
|
|
926
|
-
→ createComponentJSIBinderByName: {"RNCWebView" → RNCWebViewJSIBinder}
|
|
927
|
-
→ createComponentNapiBinderByName: {"RNCWebView" → RNCWebViewNapiBinder}
|
|
928
|
-
→ EventEmitRequestHandler: 14 events (onNavigationStateChange, onMessage, etc.)
|
|
929
|
-
→ TurboModuleFactoryDelegate: RNCWebViewModule
|
|
930
|
-
→ JSIBinder Props: 50+ props (obj.setProperty(rt, "javaScriptEnabled", ...), etc.)
|
|
931
|
-
→ NapiBinder Props: 桥接 ArkTS 属性到 C++
|
|
932
|
-
```
|
|
933
|
-
|
|
934
|
-
**Legacy 架构示例(react-native-maps)**:
|
|
935
|
-
|
|
936
|
-
```
|
|
937
|
-
模式判定: Legacy 架构(requireNativeComponent)
|
|
938
|
-
|
|
939
|
-
5a: src/MapView.tsx + src/decorateMapComponent.ts
|
|
940
|
-
→ requireNativeComponent('AIRMap') + requireNativeComponent('AIRGoogleMap')
|
|
941
|
-
→ 组件名: AIRMap, AIRMapMarker, AIRMapPolyline, AIRMapPolygon, AIRMapCircle, AIRMapCallout, etc.
|
|
942
|
-
→ NativeModules: AirMapModule, AIRMapManager
|
|
943
|
-
|
|
944
|
-
5b: harmony/maps/
|
|
945
|
-
→ 模块名: maps
|
|
946
|
-
|
|
947
|
-
5c: harmony/maps/src/main/ets/MapsPackage.ts
|
|
948
|
-
→ class MapsPackage extends RNPackage
|
|
949
|
-
→ ⚠️ 无 createDescriptorWrapperFactoryByDescriptorType(仅 TurboModule 注册)
|
|
950
|
-
→ TurboModules: AIRMapManager, AIRMapMarkerManager
|
|
951
|
-
→ ComponentFactory: MapsComponentFactory.ets(路由 11 个子组件)
|
|
952
|
-
|
|
953
|
-
5d: harmony/maps/src/main/ets/AIRMaps/AIRMapDescriptorTypes.ts
|
|
954
|
-
→ 手动定义: AIRMapRawProps (20+ Props), AIRMapMarkerRawProps, etc.
|
|
955
|
-
→ 手动 Descriptor 类型: AIRMapDescriptor, AIRMapMarkerDescriptor, etc.
|
|
956
|
-
|
|
957
|
-
5e: harmony/maps/src/main/ets/AIRMaps/AIRMap.ets + 11 个子组件
|
|
958
|
-
→ @Component export struct AIRMap { ctx.descriptorRegistry.getDescriptor }
|
|
959
|
-
→ @Component export struct AIRMapMarker { ... }
|
|
960
|
-
→ ...
|
|
961
|
-
|
|
962
|
-
5f: harmony/maps/src/main/cpp/MapsPackage.h
|
|
963
|
-
→ C++ Package 模式: Hand-Written (直接继承 Package)
|
|
964
|
-
→ createComponentDescriptorProviders: AIRMap, AIRMapMarker, AIRMapPolyline, AIRMapPolygon, AIRMapCircle, etc.
|
|
965
|
-
→ createComponentJSIBinderByName: {"AIRMap" → AIRMapJSIBinder, "AIRMapMarker" → AIRMapMarkerJSIBinder, ...}
|
|
966
|
-
→ createComponentNapiBinderByName: {"AIRMap" → AIRMapNapiBinder, ...}
|
|
967
|
-
→ TurboModuleFactoryDelegate: AIRMapManager, AIRMapMarkerManager
|
|
968
|
-
→ AIRMapJSIBinder Props: provider, mapType, zoomEnabled, scrollEnabled, showsUserLocation, etc.
|
|
969
|
-
```
|
|
970
|
-
|
|
971
|
-
### 3.4 无原生组件时的记录
|
|
972
|
-
|
|
973
|
-
若库不含原生组件(仅 TurboModule),记录为:
|
|
974
|
-
|
|
975
|
-
```markdown
|
|
976
|
-
| 原生组件名 | JS 层注册文件:行号 | ... | ArkTS 实现文件:行号 |
|
|
977
|
-
|------------|-------------------|-----|---------------------|
|
|
978
|
-
| ⚠️ 无原生组件 | — | ... | — |
|
|
979
|
-
```
|
|
980
|
-
|
|
981
|
-
---
|
|
982
|
-
|
|
983
|
-
## 4. 原生组件架构一致性检视对比规范
|
|
984
|
-
|
|
985
|
-
定位到注册链路后,需对比 Android/iOS 上游实现与 OHOS 实现的架构一致性。
|
|
986
|
-
|
|
987
|
-
### 4.1 检视项与扣分规则
|
|
988
|
-
|
|
989
|
-
| # | 检视项 | 对比对象 | 扣分规则 | 致命度 |
|
|
990
|
-
|---|--------|----------|----------|--------|
|
|
991
|
-
| 1 | 组件名注册 | Android ViewManager `getName()` / iOS `RCT_EXPORT_MODULE()` vs OHOS `NAME` 常量 / DescriptorWrapper / Descriptor 组件名 vs C++ `createComponentDescriptorProviders` 组件名 | 不一致扣 5 分 | 中等 |
|
|
992
|
-
| 2 | Props 类型定义 | RN 上游 NativeProps vs OHOS DirectRawProps/手动 RawProps vs C++ JSIBinder `obj.setProperty` 列出的 Prop 名 | 缺失 Prop 扣 3 分/个,类型不一致扣 5 分/个 | 严重 |
|
|
993
|
-
| 3 | Commands 注册 | RN 上游 Commands 列表 vs OHOS CommandArgvByName/registerCommandCallback 列表 vs C++ CommandDescriptor | 缺失 Command 扣 8 分/个 | 致命 |
|
|
994
|
-
| 4 | Props 传递机制 | Android `@ReactProp` / iOS `RCT_EXPORT_VIEW_PROPERTY` vs OHOS `rawProps.xxx` 读取 vs C++ JSIBinder `obj.setProperty` + NapiBinder 桥接 | 关键 Prop 未传递扣 8 分/个 | 致命 |
|
|
995
|
-
| 5 | Commands 实现 | Android `receiveCommand()` / iOS `RCT_EXPORT_METHOD` vs OHOS Command 回调实现 vs C++ Command 处理逻辑 | Command 逻辑缺失或不一致扣 8 分/个 | 致命 |
|
|
996
|
-
| 6 | 事件发送机制 | Android `RCTEventEmitter.receiveEvent()` / iOS `RCTDirectEventBlock` vs OHOS `EventEmitter.emit()` / `rnInstance.emitComponentEvent()` vs C++ `EventEmitRequestHandler` | 事件发送机制不一致扣 5 分/个 | 中等 |
|
|
997
|
-
| 7 | DescriptorWrapper 映射 | OHOS DescriptorWrapper 是否正确映射 rawProps 到 ArkTS 组件 Props(Codegen 模式) | 映射缺失扣 5 分/个 | 中等 |
|
|
998
|
-
| 8 | Descriptor 类型映射 | OHOS 手动 Descriptor 是否完整包含所有 Props(Legacy 模式) | 类型缺失扣 5 分/个 | 中等 |
|
|
999
|
-
| 9 | C++ JSIBinder ↔ OHOS Props 映射 | C++ JSIBinder 中 `obj.setProperty(rt, "propName", ...)` 列出的 Prop 名 vs OHOS `DirectRawProps`/`RawProps` 中定义的 Prop 名 | JSIBinder 有但 OHOS 无→C++→ArkTS断桥扣 8 分/个;OHOS 有但 JSIBinder 无→JS→C++断桥扣 8 分/个 | 致命 |
|
|
1000
|
-
| 10 | C++ NapiBinder ↔ ArkTS 属性桥接 | C++ NapiBinder 中桥接的 Prop 名 vs ArkTS `@Component struct` 中实际使用的 Prop 名 | NapiBinder 缺失导致 ArkTS 无法获取 C++ 侧 Prop 值,扣 5 分/个 | 中等 |
|
|
1001
|
-
| 11 | C++ EventEmitRequestHandler ↔ OHOS 事件 | C++ `handleEvent` 中注册的事件名 vs OHOS `EventEmitter.emit` / `rnInstance.emitComponentEvent` 发送的事件名 | 事件名不一致扣 5 分/个 | 中等 |
|
|
1002
|
-
| 12 | C++ TurboModule 注册 vs JS 层 | C++ `TurboModuleFactoryDelegate.createTurboModule` 中注册的 TurboModule 名 vs JS 层 `TurboModuleRegistry.get` 注册名 | 不一致扣 3 分/个 | 中等 |
|
|
1003
|
-
|
|
1004
|
-
### 4.2 Props 函数级对比格式
|
|
1005
|
-
|
|
1006
|
-
每个 Prop 必须逐项对比,而非笼统描述"Props 大致一致":
|
|
1007
|
-
|
|
1008
|
-
```markdown
|
|
1009
|
-
| # | Prop 名 | RN 上游 NativeProps 类型 | C++ JSIBinder 默认值 | OHOS 类型定义 | OHOS ArkTS rawProps 使用 | OHOS 文件:行号 | 状态 | 扣分 |
|
|
1010
|
-
|---|---------|------------------------|---------------------|-------------|-------------------------|---------------|------|------|
|
|
1011
|
-
| 1 | `javaScriptEnabled` | `WithDefault<boolean, true>` | `true` | `boolean?` (DirectRawProps) + `?? true` (PropsSelector) | `this.descriptor.rawProps.javaScriptEnabled` | `RNCWebView.ets:67` | ✅ 一致 | 0 |
|
|
1012
|
-
| 2 | `cacheMode` | `WithDefault<CacheModeEnum, 'DEFAULT'>` | `"LOAD_DEFAULT"` | `'LOAD_DEFAULT' | ...'` (DirectRawProps) + `?? 'LOAD_DEFAULT'` (PropsSelector) | `this.descriptor.rawProps.cacheMode as CACHE_MODE` | `RNCWebView.ets:738` | ⚠️ 映射需验证 | -3 |
|
|
1013
|
-
| 3 | `injectedJavaScript` | `string?` | 无默认值 | `string?` (DirectRawProps) | ⛔ 未在 rawProps 中读取 | — | ❌ 缺失 | -8 |
|
|
1014
|
-
| 4 | `customMapStyle` | `object?` | ⛔ JSIBinder 中无此 Prop | `MapStyleElement[]?` (AIRMapRawProps) | `this.descriptor.rawProps.customMapStyle` | `AIRMap.ets:92` | ❌ JS→C++断桥 | -8 |
|
|
1015
|
-
```
|
|
1016
|
-
|
|
1017
|
-
**Codegen vs Legacy 模式对比差异**:
|
|
1018
|
-
|
|
1019
|
-
| 对比维度 | Codegen 模式 | Legacy 模式 |
|
|
1020
|
-
|---------|-------------|------------|
|
|
1021
|
-
| Props 类型来源 | `generated/components/ComponentName.ts` 的 `DirectRawProps` + `PropsSelector` | 手动 `*DescriptorTypes.ts` 的 `*RawProps extends ViewRawProps` |
|
|
1022
|
-
| 默认值 | `PropsSelector` 中 `?? defaultValue` | `*RawProps` 接口中可选 `?` 表示有默认值,但默认值可能未定义 |
|
|
1023
|
-
| Props 读取方式 | `descriptorWrapper.rawProps.xxx` 或 `descriptor.rawProps.xxx` | `descriptor.rawProps.xxx`(通过 `ctx.descriptorRegistry.getDescriptor`) |
|
|
1024
|
-
|
|
1025
|
-
**常见问题模式**:
|
|
1026
|
-
|
|
1027
|
-
| 问题 | 识别方式 | 扣分 |
|
|
1028
|
-
|------|----------|------|
|
|
1029
|
-
| Prop 未从 rawProps 读取 | ArkTS 实现中无 `rawProps.xxx` 读取 | 关键 Prop -8/个,次要 Prop -3/个 |
|
|
1030
|
-
| Prop 类型映射错误 | rawProps 读取后有错误的 `as` 类型转换(如 `as string` 而非 `as boolean`) | -5/个 |
|
|
1031
|
-
| Prop 默认值不一致 | OHOS `PropsSelector` 或 `RawProps` 的默认值与上游不同 | -3/个 |
|
|
1032
|
-
| Prop 只读未使用 | rawProps 读取后未在 `build()` 中传递给原生组件 | 关键 Prop -5/个 |
|
|
1033
|
-
| 手动 RawProps 缺失 Prop(Legacy 模式) | 手动定义的 `*RawProps` 接口中缺少上游存在的 Prop | -5/个 |
|
|
1034
|
-
| C++ JSIBinder 缺失 Prop | C++ JSIBinder 的 `obj.setProperty(rt, "propName", ...)` 中缺少 JS 上游存在的 Prop → JS→C++ 断桥,JS 传入值无法到达 C++/ArkTS | 致命 Prop -8/个,次要 Prop -3/个 |
|
|
1035
|
-
| C++ NapiBinder 缺失 Prop | C++ NapiBinder 的 `setProperty(env, thisObj, "propName", ...)` 中缺少 Prop → C++→ArkTS 断桥,C++ 侧值无法传递给 ArkTS | -5/个 |
|
|
1036
|
-
| OHOS RawProps 缺失 JSIBinder 中存在的 Prop | C++ JSIBinder 有此 Prop 但 OHOS `DirectRawProps`/`RawProps` 中未定义 → ArkTS 无法接收 | -5/个 |
|
|
1037
|
-
|
|
1038
|
-
### 4.3 Commands 函数级对比格式
|
|
1039
|
-
|
|
1040
|
-
每个 Command 必须逐项对比:
|
|
1041
|
-
|
|
1042
|
-
```markdown
|
|
1043
|
-
| # | Command 名 | RN 上游签名 | C++ Command 处理 | OHOS 注册方式 | OHOS ArkTS 实现文件:行号 | 状态 | 扣分 |
|
|
1044
|
-
|---|-----------|-------------|------------------|--------------|-------------------------|------|------|
|
|
1045
|
-
| 1 | `goBack` | `goBack(viewRef): void` | ✅ C++ CommandDescriptor | CommandReceiver.subscribe("goBack", handler) → `controller.backward()` | `WebViewBaseOperate.ets:361` | ✅ 一致 | 0 |
|
|
1046
|
-
| 2 | `clearFormData` | `clearFormData(viewRef): void` | ⛔ 无 C++ CommandDescriptor | ⛔ 不在 CommandArgvByName | — | ⚠️ 缺失(已文档化) | -8 |
|
|
1047
|
-
| 3 | `reload` | `reload(viewRef): void` | ✅ C++ CommandDescriptor | CommandReceiver.subscribe("reload", handler) → 空实现 `// TODO` | `WebViewBaseOperate.ets:402` | ❌ Stub | -8 |
|
|
1048
|
-
| 4 | `animateToRegion` | `animateToRegion(viewRef, region, duration): void` | ✅ C++ TurboModule 方法 | ctx.componentCommandReceiver → 注释掉 | `AIRMap.ets:97` | ❌ 注释/空实现 | -8 |
|
|
1049
|
-
```
|
|
1050
|
-
|
|
1051
|
-
**Codegen vs Legacy 模式 Command 对比差异**:
|
|
1052
|
-
|
|
1053
|
-
| 对比维度 | Codegen 模式 | Legacy 模式 |
|
|
1054
|
-
|---------|-------------|------------|
|
|
1055
|
-
| Command 定义来源 | `generated/` 的 `CommandArgvByName` 接口 | JS 层 `NativeCommands` 或 `requireNativeComponent` 伴随的命令定义 |
|
|
1056
|
-
| Command 注册方式 | `CommandReceiver.subscribe(commandName, handler)` | `ctx.componentCommandReceiver.registerCommandCallback(tag, (command, args) => { if (command === ...) })` |
|
|
1057
|
-
| Command 分发方式 | 每个 Command 独立订阅回调 | switch/if-else 分发 |
|
|
1058
|
-
|
|
1059
|
-
**常见问题模式**:
|
|
1060
|
-
|
|
1061
|
-
| 问题 | 识别方式 | 扣分 |
|
|
1062
|
-
|------|----------|------|
|
|
1063
|
-
| Command 未注册 | Codegen: `CommandArgvByName` 中缺失;Legacy: `registerCommandCallback` 中无对应分支;C++: 无 CommandDescriptor 或 TurboModule 方法 | -8/个 |
|
|
1064
|
-
| Command 回调为空实现 | `// TODO`、注释代码、空方法体 | -8/个 |
|
|
1065
|
-
| Command 逻辑与上游不一致 | Android `receiveCommand` 的实际操作与 OHOS 回调操作不同 | -8/个 |
|
|
1066
|
-
| C++ Command 未实现 | C++ 层无对应 CommandDescriptor 或 TurboModule 方法 → Command 无法从 JS 传递到 ArkTS | -8/个 |
|
|
1067
|
-
|
|
1068
|
-
### 4.4 事件发送对比格式
|
|
1069
|
-
|
|
1070
|
-
```markdown
|
|
1071
|
-
| # | 事件名 | Android/iOS 触发方式 | C++ EventEmitRequestHandler | OHOS 触发方式 | OHOS 文件:行号 | 数据格式一致 | 状态 | 扣分 |
|
|
1072
|
-
|---|--------|---------------------|----------------------------|-------------|---------------|-------------|------|------|
|
|
1073
|
-
| 1 | `onNavigationStateChange` | `RCTEventEmitter.receiveEvent` | ✅ handled in EventEmitRequestHandler | `EventEmitter.emit("onNavigationStateChange", payload)` | `RNCWebView.ets:156` | ✅ | ✅ 一致 | 0 |
|
|
1074
|
-
| 2 | `onMessage` | iOS: `RCTDirectEventBlock onMessage` | ⛔ 未在 handler 中注册 | ⛔ 未在 emit 中注册 | — | — | ❌ C++ 层未注册 | -5 |
|
|
1075
|
-
| 3 | `onRegionChange` | Android: `onRegionChange` event | ✅ handled | `ctx.rnInstance.emitComponentEvent(tag, "onRegionChange", {region})` | `AIRMap.ets:xxx` | ⚠️ | ⚠️ Payload 不一致 | -5 |
|
|
1076
|
-
```
|
|
1077
|
-
|
|
1078
|
-
**Codegen vs Legacy 模式事件对比差异**:
|
|
1079
|
-
|
|
1080
|
-
| 对比维度 | Codegen 模式 | Legacy 模式 |
|
|
1081
|
-
|---------|-------------|------------|
|
|
1082
|
-
| 事件类型来源 | `generated/` 的 `EventPayloadByName` 接口 | JS 层组件 Props 中的 `onXxx?: DirectEventHandler<...>` 或手动定义 |
|
|
1083
|
-
| 事件发送方式 | `EventEmitter.emit(eventName, payload)` | `ctx.rnInstance.emitComponentEvent(tag, eventName, payload)` 或通过 TurboModule 间接发送 |
|
|
1084
|
-
| 事件 Payload 格式 | `EventPayloadByName` 中定义的精确类型 | 手动构造的 Object |
|
|
1085
|
-
|
|
1086
|
-
---
|
|
1087
|
-
|
|
1088
|
-
## 5. 各平台原生组件实现特征对比
|
|
1089
|
-
|
|
1090
|
-
### 5.1 Android ViewManager 实现特征
|
|
1091
|
-
|
|
1092
|
-
| 特征 | 代码模式 | 说明 |
|
|
1093
|
-
|------|----------|------|
|
|
1094
|
-
| 组件名注册 | `getName() → "RNCWebView"` | ViewManager 暴露给 JS 的组件名 |
|
|
1095
|
-
| Props 注册 | `@ReactProp(name = "javaScriptEnabled", defaultBoolean = true)` | 每个 Prop 单独注解 |
|
|
1096
|
-
| Commands 注册 | `@ReactProp(name = COMMAND_GOBACK)` 常量 + `receiveCommand(view, commandId, args)` | Commands 通过常量映射 + switch 分发 |
|
|
1097
|
-
| 事件发送 | `getReactApplicationContext().getJSModule(RCTEventEmitter.class).receiveEvent(id, "onNavigationStateChange", event)` | 通过 RCTEventEmitter 发送 |
|
|
1098
|
-
| 视图创建 | `createViewInstance(reactContext) → WebView(context)` | 返回原生视图实例 |
|
|
1099
|
-
|
|
1100
|
-
### 5.2 iOS ViewManager 实现特征
|
|
1101
|
-
|
|
1102
|
-
| 特征 | 代码模式 | 说明 |
|
|
1103
|
-
|------|----------|------|
|
|
1104
|
-
| 组件名注册 | `RCT_EXPORT_MODULE(RNCWebView)` | 宏导出组件名 |
|
|
1105
|
-
| Props 注册 | `RCT_EXPORT_VIEW_PROPERTY(javaScriptEnabled, BOOL)` | 每个 Prop 单独宏 |
|
|
1106
|
-
| Commands 注册 | `RCT_EXPORT_METHOD(goBack:(RCTComponentTag *)reactTag)` | 每个 Command 单独宏 |
|
|
1107
|
-
| 事件发送 | `self.onNavigationStateChange(@{@"url": url, ...})` | Block 回调 |
|
|
1108
|
-
| 视图创建 | `view() → WKWebView()` | 返回原生视图实例 |
|
|
1109
|
-
|
|
1110
|
-
### 5.3 OHOS ArkTS + C++ 组件实现特征(Codegen 架构)
|
|
1111
|
-
|
|
1112
|
-
| 层级 | 特征 | 代码模式 | 说明 |
|
|
1113
|
-
|------|------|----------|------|
|
|
1114
|
-
| ArkTS | 组件名注册 | Package `createDescriptorWrapperFactoryByDescriptorType` 中 `"RNCWebView": DescriptorWrapper` | 通过 Package 注册组件名 |
|
|
1115
|
-
| ArkTS | Props 类型 | `generated/` 中 `DirectRawProps` + `PropsSelector`(含默认值) | Codegen 自动生成 |
|
|
1116
|
-
| ArkTS | Props 读取 | `descriptorWrapper.rawProps.xxx` 或 `descriptor.rawProps.xxx` | 从 rawProps 读取所有 Prop |
|
|
1117
|
-
| ArkTS | Commands 注册 | `CommandReceiver.subscribe(commandName, handler)` | 通过 CommandReceiver 订阅 |
|
|
1118
|
-
| ArkTS | 事件发送 | `EventEmitter.emit(eventName, payload)` | 通过 generated EventEmitter 发送 |
|
|
1119
|
-
| ArkTS | 视图渲染 | `build() { Web({src: ...}).javaScriptAccess(...) }` | ArkUI 声明式渲染 |
|
|
1120
|
-
| C++ | Package 模式 | Thin Wrapper `class XxxPackage extends BaseReactNativeXxxPackage` | 仅继承 generated 基类,不重写方法 |
|
|
1121
|
-
| C++ | 组件注册 | `BaseReactNative*Package.h` 中 `createComponentDescriptorProviders()` 自动列出 | Codegen 自动生成组件列表 |
|
|
1122
|
-
| C++ | Props 序列化 | `*JSIBinder.h` 中 `obj.setProperty(rt, "propName", value)` | 每个 Prop 从 JS 序列化到 C++ |
|
|
1123
|
-
| C++ | Props 桥接 | `*NapiBinder.h` 中 `setProperty(env, thisObj, "propName", value)` | C++ 侧 Prop 桥接到 ArkTS |
|
|
1124
|
-
| C++ | 事件处理 | `BaseReactNative*PackageEventEmitRequestHandler` 中 `handleEvent` | 自动生成事件分发 |
|
|
1125
|
-
| C++ | TurboModule | `BaseReactNative*PackageTurboModuleFactoryDelegate` 中 `createTurboModule` | 自动生成 TurboModule 工厂 |
|
|
1126
|
-
|
|
1127
|
-
### 5.4 OHOS ArkTS + C++ 组件实现特征(Legacy 架构)
|
|
1128
|
-
|
|
1129
|
-
| 层级 | 特征 | 代码模式 | 说明 |
|
|
1130
|
-
|------|------|----------|------|
|
|
1131
|
-
| ArkTS | 组件名注册 | 手动 `Descriptor<"ComponentName", ...>` 类型 + C++ `ComponentDescriptorProvider` 或 ComponentFactory 路由 | 通过手动 Descriptor 或 C++ 注册 |
|
|
1132
|
-
| ArkTS | Props 类型 | 手动 `*RawProps extends ViewRawProps` 接口 | 手动定义,无自动默认值 |
|
|
1133
|
-
| ArkTS | Props 读取 | `ctx.descriptorRegistry.getDescriptor<Tag>(this.tag).rawProps.xxx` | 通过 descriptorRegistry 获取 |
|
|
1134
|
-
| ArkTS | Commands 注册 | `ctx.componentCommandReceiver.registerCommandCallback(tag, (command, args) => { if/switch })` | 直接注册 + 分发 |
|
|
1135
|
-
| ArkTS | 事件发送 | `ctx.rnInstance.emitComponentEvent(tag, eventName, payload)` | 直接调用 rnInstance |
|
|
1136
|
-
| ArkTS | 多组件路由 | `ComponentFactory.ets` 的 `build()` 中 if-else 分发 | 多组件库使用工厂模式路由 |
|
|
1137
|
-
| ArkTS | 视图渲染 | `build() { MapComponent(...).xxx(...) }` | ArkUI 声明式渲染 |
|
|
1138
|
-
| C++ | Package 模式 | Hand-Written `class XxxPackage : public Package` | 手动实现所有注册方法 |
|
|
1139
|
-
| C++ | 组件注册 | `createComponentDescriptorProviders()` 手动列出每个组件 | 手动维护组件列表 |
|
|
1140
|
-
| C++ | Props 序列化 | 每个 `*JSIBinder.h` 中 `obj.setProperty(rt, "propName", value)` 手动列出 | 手动定义 Props 序列化 |
|
|
1141
|
-
| C++ | Props 桥接 | 每个 `*NapiBinder.h` 中 `setProperty(env, thisObj, "propName", value)` 手动列出 | 手动定义 C++→ArkTS 桥接 |
|
|
1142
|
-
| C++ | TurboModule | `TurboModuleFactoryDelegate` 中 `createTurboModule` 手动列出 | 手动定义 TurboModule 工厂 |
|
|
1143
|
-
| C++ | 组件实例 | `ComponentInstanceFactoryDelegate::createComponentInstance` 中 if-else 分发(如 react-native-svg) | 需 C++ 原生视图的组件 |
|
|
1144
|
-
|
|
1145
|
-
---
|
|
1146
|
-
|
|
1147
|
-
## 6. 特殊场景与注意事项
|
|
1148
|
-
|
|
1149
|
-
### 6.1 多组件库
|
|
1150
|
-
|
|
1151
|
-
若库包含多个原生组件(如 react-native-maps 有 AIRMap + AIRMapMarker + AIRMapPolyline + AIRMapPolygon + AIRMapCircle 等;react-native-screens 有 11 个组件),需对每个组件独立执行定位流程,并在 4.2-4.4 中分别对比。
|
|
1152
|
-
|
|
1153
|
-
### 6.2 仅 Props 无 Commands 的组件
|
|
1154
|
-
|
|
1155
|
-
部分组件仅定义 Props 而无 Commands(如简单的进度条组件、react-native-video 的 RNCVideo `CommandArgvByName` 为空接口 `{}`)。此时 Commands 对比表标注"⚠️ 无 Commands 定义"即可,不扣分。
|
|
1156
|
-
|
|
1157
|
-
### 6.3 Codegen 生成的类型文件
|
|
1158
|
-
|
|
1159
|
-
OHOS 鸿蒙化代码中 `generated/` 目录存放 Codegen 自动生成的类型定义文件。关键结构:
|
|
1160
|
-
|
|
1161
|
-
```
|
|
1162
|
-
generated/
|
|
1163
|
-
components/
|
|
1164
|
-
ComponentName.ts ← 原生组件的完整类型(NAME, RawProps, PropsSelector, DescriptorWrapper, EventEmitter, CommandReceiver)
|
|
1165
|
-
ts.ts ← 组件命名空间导出汇总
|
|
1166
|
-
turboModules/
|
|
1167
|
-
TurboModuleName.ts ← TurboModule 的类型定义
|
|
1168
|
-
ts.ts ← TurboModule 导出汇总
|
|
1169
|
-
index.ets ← 全量导出
|
|
1170
|
-
ts.ts ← RNC + TM 命名空间导出
|
|
1171
|
-
```
|
|
1172
|
-
|
|
1173
|
-
这些文件中的 DirectRawProps、PropsSelector、EventPayloadByName、CommandArgvByName 定义应与上游 RN 保持一致;若不一致,说明鸿蒙化方手动修改了 Codegen 产出,需重点关注差异。
|
|
1174
|
-
|
|
1175
|
-
若 `generated/components/ts.ts` 仅导出空对象(`export {}`),说明该库的组件未通过 Codegen generated 机制注册,需检查是否通过 Legacy/Descriptor 模式或其他方式注册。
|
|
1176
|
-
|
|
1177
|
-
### 6.4 Fragment 组件
|
|
1178
|
-
|
|
1179
|
-
部分组件(如 ReactFragment)不以 `@Component export struct` 形式实现,而是以普通 ArkTS class 实现。搜索 5e 时需同时搜索 `export class 组件名` 模式。
|
|
1180
|
-
|
|
1181
|
-
### 6.5 库含原生组件但 OHOS 未实现
|
|
1182
|
-
|
|
1183
|
-
若 5a 找到 `codegenNativeComponent` 或 `requireNativeComponent` 但 5c/5e 未找到对应 OHOS Package 注册和组件实现,说明原生组件未鸿蒙化。判定为"⛔ 原生组件缺失",每个缺失组件扣 15 分(致命)。
|
|
1184
|
-
|
|
1185
|
-
### 6.6 Package 基类选择
|
|
1186
|
-
|
|
1187
|
-
| 基类 | TurboModule Factory 方法 | 适用场景 | 典型库 |
|
|
1188
|
-
|------|--------------------------|---------|--------|
|
|
1189
|
-
| `RNOHPackage` | `createAnyThreadTurboModuleFactory()` → `AnyThreadTurboModuleFactory` | 较新的鸿蒙化实现 | react-native-webview |
|
|
1190
|
-
| `RNPackage` | `createTurboModulesFactory()` → `TurboModulesFactory` | 常见的鸿蒙化实现 | react-native-video, react-native-maps, react-native-svg, react-native-picker |
|
|
1191
|
-
|
|
1192
|
-
两者在组件注册方式上相同(都通过 `createDescriptorWrapperFactoryByDescriptorType`),仅在 TurboModule 注册 API 上有区别。检视时不因基类不同而扣分,但需正确识别以提取 TurboModule 名。
|
|
1193
|
-
|
|
1194
|
-
### 6.7 JS 层无组件注册宏的库
|
|
1195
|
-
|
|
1196
|
-
部分库(如 react-native-svg)在 JS 层不使用 `codegenNativeComponent` 或 `requireNativeComponent`,但 OHOS 层有大量 `@Component struct` 实现。此时判定流程需调整:
|
|
1197
|
-
|
|
1198
|
-
```
|
|
1199
|
-
1. JS 层无 codegenNativeComponent 或 requireNativeComponent
|
|
1200
|
-
2. 但 harmony/ 目录中存在 @Component struct 实现
|
|
1201
|
-
3. → 判定为 Legacy 架构,从 OHOS 层直接开始定位
|
|
1202
|
-
```
|
|
1203
|
-
|
|
1204
|
-
### 6.8 requireNativeComponent 的动态组件名
|
|
1205
|
-
|
|
1206
|
-
`requireNativeComponent` 的组件名可能是动态拼接的(如 react-native-maps 的 `AIRMap` vs `AIRGoogleMap`,根据 provider 属性决定)。检视时需追踪完整的命名逻辑,提取所有可能的组件名变体。
|
|
1207
|
-
|
|
1208
|
-
### 6.9 Harmony 目录位置不固定
|
|
1209
|
-
|
|
1210
|
-
| 库 | harmony 目录位置 | 模块子目录名 |
|
|
1211
|
-
|----|-----------------|-------------|
|
|
1212
|
-
| react-native-webview | `harmony/rn_webview/` | rn_webview |
|
|
1213
|
-
| react-native-video | `harmony/rn_video/` | rn_video |
|
|
1214
|
-
| react-native-maps | `harmony/maps/` | maps |
|
|
1215
|
-
| react-native-svg | `harmony/svg/` | svg |
|
|
1216
|
-
| react-native-picker | `harmony/picker/` | picker |
|
|
1217
|
-
| react-native-screens | `react-native-harmony-screens/harmony/screens/` | screens |
|
|
1218
|
-
| react-native-linear-gradient | `harmony/linear_gradient/`(待确认) | linear_gradient |
|
|
1219
|
-
|
|
1220
|
-
> ⚠️ 模块子目录名不可按库名硬推。必须通过实际目录探索确定。
|
|
1221
|
-
|
|
1222
|
-
### 6.10 TurboModule 充当 ViewManager 的特殊情况
|
|
1223
|
-
|
|
1224
|
-
某些库(如 react-native-picker)在 JS 层使用 `TurboModuleRegistry.get("RNCPickerView")` 注册,但在 OHOS 层的 Package 中将其实现为 TurboModule。如果该 TurboModule 负责创建/管理 UI 视图(而非仅提供方法调用),则应同时按 TurboModule 和原生组件两个维度检视。
|
|
1225
|
-
|
|
1226
|
-
---
|
|
1227
|
-
|
|
1228
|
-
## 7. C++ ↔ OHOS 特征提取与跨层验证方法
|
|
1229
|
-
|
|
1230
|
-
C++ Package 层是 RN 原生桥接的核心层——它将 JS 层的 Props/Commands/Events 定义序列化为 C++ 数据结构,再通过 NapiBinder 桥接到 ArkTS 组件。检视时必须验证 C++ ↔ ArkTS 层的特征一致性。
|
|
1231
|
-
|
|
1232
|
-
### 7.1 C++ ↔ ArkTS Props 映射验证
|
|
1233
|
-
|
|
1234
|
-
**验证链路**:`JS NativeProps → C++ JSIBinder Props → C++ NapiBinder Props → ArkTS DirectRawProps/手动 RawProps → ArkTS rawProps 读取`
|
|
1235
|
-
|
|
1236
|
-
```markdown
|
|
1237
|
-
| # | Prop 名 | JS NativeProps 类型 | C++ JSIBinder 默认值 | C++ NapiBinder 桥接 | OHOS DirectRawProps/RawProps | OHOS PropsSelector 默认值 | ArkTS rawProps 使用 | 状态 | 扣分 |
|
|
1238
|
-
|---|---------|---------------------|---------------------|---------------------|---------------------------|-------------------------|-------------------------|------|------|
|
|
1239
|
-
| 1 | `javaScriptEnabled` | `WithDefault<boolean, true>` | `true` (JSIBinder) | ✅ (NapiBinder) | `boolean?` + `?? true` | `?? true` | `this.descriptor.rawProps.javaScriptEnabled` | ✅ 全链路一致 | 0 |
|
|
1240
|
-
| 2 | `cacheMode` | `WithDefault<CacheModeEnum, 'DEFAULT'>` | `"LOAD_DEFAULT"` (JSIBinder) | ✅ (NapiBinder) | `'LOAD_DEFAULT'|...` + `?? 'LOAD_DEFAULT'` | `?? 'LOAD_DEFAULT'` | `this.descriptor.rawProps.cacheMode as CACHE_MODE` | ⚠️ 类型映射需验证 | -3 |
|
|
1241
|
-
| 3 | `injectedJavaScript` | `string?` | 无默认值 (JSIBinder) | ⛔ 未桥接 (NapiBinder) | `string?` (DirectRawProps) | — | ⛔ 未读取 | ❌ C++ 层已断桥 | -8 |
|
|
1242
|
-
```
|
|
1243
|
-
|
|
1244
|
-
**跨层断桥的识别方式**:
|
|
1245
|
-
|
|
1246
|
-
| 断桥位置 | 识别方式 | 说明 |
|
|
1247
|
-
|---------|----------|------|
|
|
1248
|
-
| JS → C++ 断桥 | C++ JSIBinder 中无该 Prop 的 `obj.setProperty` | Prop 未在 C++ 层注册,JS 侧传入的值会被丢弃 |
|
|
1249
|
-
| C++ → ArkTS 断桥 | C++ NapiBinder 中无该 Prop 的 `setProperty` | C++ 层有该值但未传递给 ArkTS 组件 |
|
|
1250
|
-
| ArkTS 未使用 | ArkTS 组件中无 `rawProps.xxx` 读取 | Prop 已传入但组件未使用 |
|
|
1251
|
-
|
|
1252
|
-
> ⚠️ **关键**:C++ JSIBinder 是 RN 新架构(Fabric)的核心 Props 序列化层。即使 ArkTS `DirectRawProps` 中定义了某个 Prop,如果 C++ JSIBinder 中未包含该 Prop,JS 侧传入的值将无法传递到组件。因此 JSIBinder 是 Props 完整性的最终判定标准。
|
|
1253
|
-
|
|
1254
|
-
### 7.2 C++ ↔ ArkTS Commands 映射验证
|
|
1255
|
-
|
|
1256
|
-
**验证链路**:`JS NativeCommands → C++ CommandDescriptor(如 Fabric CommandDescriptor)→ ArkTS CommandReceiver/CommandCallback`
|
|
1257
|
-
|
|
1258
|
-
```markdown
|
|
1259
|
-
| # | Command 名 | JS NativeCommands 签名 | C++ Command 处理 | ArkTS CommandReceiver/registerCommandCallback | OHOS 实现文件:行号 | 状态 | 扣分 |
|
|
1260
|
-
|---|-----------|----------------------|------------------|---------------------------------------------|----------------------|------|------|
|
|
1261
|
-
| 1 | `goBack` | `goBack(viewRef): void` | ✅ C++ CommandDescriptor | ✅ CommandReceiver.subscribe | `WebViewBaseOperate.ets:361` | ✅ 全链路一致 | 0 |
|
|
1262
|
-
| 2 | `clearFormData` | `clearFormData(viewRef): void` | ⛔ 无 C++ CommandDescriptor | ⛔ 无 CommandArgvByName | — | ❌ C++ 层未注册 | -8 |
|
|
1263
|
-
```
|
|
1264
|
-
|
|
1265
|
-
> ⚠️ **Codegen 架构的 Commands 在 C++ 中通过 `CommandArgvByName` 接口自动生成**;Legacy 架构的 Commands 通过 C++ TurboModule 方法暴露(如 `AIRMapManager.animateToRegion()`),不走 CommandDescriptor 路径。
|
|
1266
|
-
|
|
1267
|
-
### 7.3 C++ ↔ ArkTS Events 映射验证
|
|
1268
|
-
|
|
1269
|
-
**验证链路**:`JS onXxx Props → C++ EventEmitRequestHandler → ArkTS EventEmitter.emit / rnInstance.emitComponentEvent`
|
|
1270
|
-
|
|
1271
|
-
```markdown
|
|
1272
|
-
| # | 事件名 | JS onXxx Prop | C++ EventEmitRequestHandler | ArkTS 发送方式 | OHOS 文件:行号 | 状态 | 扣分 |
|
|
1273
|
-
|---|--------|-------------|----------------------------|---------------|---------------|------|------|
|
|
1274
|
-
| 1 | `onNavigationStateChange` | `onNavigationStateChange?: DirectEventHandler<...>` | ✅ handled in EventEmitRequestHandler | ✅ EventEmitter.emit | `RNCWebView.ets:156` | ✅ 全链路一致 | 0 |
|
|
1275
|
-
| 2 | `onMessage` | `onMessage?: DirectEventHandler<...>` | ⛔ 未在 handler 中注册 | ⛔ 未 emit | — | ❌ C++ 层未注册 | -5 |
|
|
1276
|
-
```
|
|
1277
|
-
|
|
1278
|
-
**C++ EventEmitRequestHandler 的两种模式**:
|
|
1279
|
-
|
|
1280
|
-
| 模式 | 代码特征 | 适用场景 |
|
|
1281
|
-
|------|----------|---------|
|
|
1282
|
-
| Codegen 自动生成 | `BaseReactNative*PackageEventEmitRequestHandler` 中自动列出所有事件 | Codegen 架构 |
|
|
1283
|
-
| Hand-Written | 手写 `handleEvent()` 方法中 if-else 分发 | Legacy 架构 |
|
|
1284
|
-
|
|
1285
|
-
### 7.4 C++ ↔ ArkTS TurboModule 映射验证
|
|
1286
|
-
|
|
1287
|
-
**验证链路**:`JS TurboModuleRegistry.get('XXX') → C++ TurboModuleFactoryDelegate → ArkTS TurboModule 实现`
|
|
1288
|
-
|
|
1289
|
-
```markdown
|
|
1290
|
-
| # | TurboModule 名 | JS Spec 定义 | C++ TurboModuleFactoryDelegate | ArkTS TurboModule 实现 | OHOS 文件:行号 | 状态 |
|
|
1291
|
-
|---|--------------|------------|----------------------------|---------------------|---------------|------|
|
|
1292
|
-
| 1 | `RNCWebViewModule` | ✅ NativeRNCWebViewModule.ts | ✅ BaseReactNativeWebViewPackageTurboModuleFactoryDelegate | ✅ WebViewTurboModule | `WebViewTurboModule.ets` | ✅ 一致 |
|
|
1293
|
-
| 2 | `AIRMapManager` | ✅ NativeModules.AIRMapManager | ✅ MapsTurboModuleFactoryDelegate | ✅ AIRMapManager | `AIRMaps/AIRMapManager.ts` | ✅ 一致 |
|
|
1294
|
-
```
|
|
1295
|
-
|
|
1296
|
-
### 7.5 C++ Package 模式判定快速指南
|
|
1297
|
-
|
|
1298
|
-
```
|
|
1299
|
-
1. 检查 harmony/<module>/src/main/cpp/ 目录是否存在
|
|
1300
|
-
→ 不存在 → ⚠️ 无 C++ 层(组件注册完全在 ArkTS 层)
|
|
1301
|
-
→ 存在 → 继续判定
|
|
1302
|
-
|
|
1303
|
-
2. 检查 *Package.h 文件内容
|
|
1304
|
-
→ 类继承 BaseReactNative*Package → Thin Wrapper 模式(Codegen)
|
|
1305
|
-
→ 所有注册信息在 generated/RNOH/generated/BaseReactNative*Package.h 中
|
|
1306
|
-
→ 需读取该 generated 文件提取组件名、JSIBinder 映射、事件名、TurboModule 名
|
|
1307
|
-
→ 类直接继承 Package → Hand-Written 模式(Legacy)
|
|
1308
|
-
→ 所有注册信息在 *Package.h/cpp 中直接定义
|
|
1309
|
-
→ 需逐方法读取提取
|
|
1310
|
-
|
|
1311
|
-
3. 检查 generated/RNOH/generated/ 目录
|
|
1312
|
-
→ 存在 → Codegen 架构确认
|
|
1313
|
-
→ 不存在 → Legacy 架构确认
|
|
1314
|
-
|
|
1315
|
-
4. 检查 *JSIBinder.h 文件
|
|
1316
|
-
→ 在 generated/components/ → 自动生成的 JSIBinder(Codegen)
|
|
1317
|
-
→ 在 cpp/ 根目录或子目录 → 手写的 JSIBinder(Legacy)
|
|
1318
|
-
|
|
1319
|
-
5. 检查 ComponentInstanceFactoryDelegate
|
|
1320
|
-
→ 存在 → 该库有 C++ 原生视图实例创建(如 react-native-svg)
|
|
1321
|
-
→ 不存在 → 该库的视图完全由 ArkTS 渲染
|
|
1322
|
-
```
|
|
1323
|
-
|
|
1324
|
-
### 7.6 C++ 层特征提取操作指令
|
|
1325
|
-
|
|
1326
|
-
**提取 JSIBinder Props 的操作流程**:
|
|
1327
|
-
|
|
1328
|
-
```
|
|
1329
|
-
1. 定位 JSIBinder 文件:
|
|
1330
|
-
- Codegen: harmony/<module>/src/main/cpp/generated/RNOH/generated/components/ComponentNameJSIBinder.h
|
|
1331
|
-
- Legacy: harmony/<module>/src/main/cpp/*JSIBinder.h
|
|
1332
|
-
|
|
1333
|
-
2. 在 JSIBinder 文件中搜索 createJSIBinder 方法
|
|
1334
|
-
3. 提取所有 obj.setProperty(rt, "propName", createValue(rt, propName_)) 行
|
|
1335
|
-
4. 提取所有 propName_ 成员变量的默认值
|
|
1336
|
-
5. 对比 propName 列表与 JS NativeProps 接口中的 Prop 名列表
|
|
1337
|
-
6. 对比 propName 列表与 OHOS DirectRawProps/RawProps 接口中的 Prop 名列表
|
|
1338
|
-
7. 标注任何 JS 中存在但 C++ JSIBinder 中缺失的 Prop(→ JS→C++ 断桥)
|
|
1339
|
-
8. 标注任何 C++ JSIBinder 中存在但 OHOS RawProps 中缺失的 Prop(→ C++→ArkTS 断桥)
|
|
1340
|
-
```
|
|
1341
|
-
|
|
1342
|
-
**提取 TurboModule 名的操作流程**:
|
|
1343
|
-
|
|
1344
|
-
```
|
|
1345
|
-
1. 定位 TurboModuleFactoryDelegate 文件:
|
|
1346
|
-
- Codegen: harmony/<module>/src/main/cpp/generated/RNOH/generated/BaseReactNative*Package.h
|
|
1347
|
-
- Legacy: harmony/<module>/src/main/cpp/*Package.h 或 *TurboModuleFactoryDelegate.h
|
|
1348
|
-
|
|
1349
|
-
2. 在 TurboModuleFactoryDelegate 的 createTurboModule 方法中提取所有 turboModuleName 条件
|
|
1350
|
-
3. 对比提取的 TurboModule 名与 JS 层 TurboModuleRegistry/NativeModules 注册名
|
|
1351
|
-
4. 对比提取的 TurboModule 名与 ArkTS TurboModule 实现类名
|
|
1352
|
-
```
|
|
1353
|
-
|
|
1354
|
-
**提取 EventEmitRequestHandler 事件名的操作流程**:
|
|
1355
|
-
|
|
1356
|
-
```
|
|
1357
|
-
1. 定位 EventEmitRequestHandler 文件:
|
|
1358
|
-
- Codegen: harmony/<module>/src/main/cpp/generated/RNOH/generated/BaseReactNative*Package.h
|
|
1359
|
-
- Legacy: 在 *Package.h/cpp 中搜索 EventEmitRequestHandler
|
|
1360
|
-
|
|
1361
|
-
2. 在 handleEvent 方法中提取所有 eventName 条件
|
|
1362
|
-
3. 对比提取的事件名与 JS 层 onXxx Props 列表
|
|
1363
|
-
4. 对比提取的事件名与 OHOS EventEmitter/emitComponentEvent 发送的事件名
|
|
1364
|
-
```
|
|
1365
|
-
|
|
1366
|
-
**提取 ComponentInstanceFactoryDelegate 组件名的操作流程**:
|
|
1367
|
-
|
|
1368
|
-
```
|
|
1369
|
-
1. 在 *Package.h 中搜索 ComponentInstanceFactoryDelegate
|
|
1370
|
-
2. 在 createComponentInstance 方法中提取所有 ctx.componentName 条件
|
|
1371
|
-
3. 这些组件名即为需要 C++ 原生视图实例的组件
|
|
1372
|
-
4. 对比这些组件名与 ArkTS @Component struct 组件名列表
|
|
1373
|
-
```
|
|
1
|
+
# RN 原生组件(ViewManager)识别与定位指南
|
|
2
|
+
|
|
3
|
+
本文档定义 RN 一致性检视中**原生组件(ViewManager)**的识别方法、注册链路定位流程和检视对比规范,确保检视人员能准确区分 TurboModule/NativeModule(方法级桥接)与原生组件(UI 组件桥接),并系统性地定位组件的完整注册链路。
|
|
4
|
+
|
|
5
|
+
> ⚠️ **核心定位**:RN 库可同时包含两类原生桥接——**TurboModule/NativeModule**(方法级桥接)和**原生组件(ViewManager)**(UI 组件桥接)。两者独立检视、独立扣分,不可混为一谈。
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## 1. 原生组件 vs TurboModule/NativeModule 区分
|
|
10
|
+
|
|
11
|
+
### 1.1 两类桥接的本质区别
|
|
12
|
+
|
|
13
|
+
| 桥接类型 | 本质 | JS 层注册方式 | 代码特征 | 检视维度 |
|
|
14
|
+
|----------|------|---------------|----------|----------|
|
|
15
|
+
| TurboModule/NativeModule | 方法级桥接(JS 调用原生方法) | `TurboModuleRegistry.getEnforcing<Spec>('XXX')` 或 `NativeModules.XXX` | JS 层导出 `Spec extends TurboModule`,ArkTS 层继承 `TurboModule` | 方法签名、参数类型、返回值、事件 |
|
|
16
|
+
| 原生组件(ViewManager) | UI 组件桥接(JS 渲染原生视图) | `codegenNativeComponent<NativeProps>('ComponentName')` 或 `requireNativeComponent<Props>('ComponentName')` | JS 层定义 `NativeProps` + `NativeCommands`,ArkTS 层 `@Component export struct` 或 `@Component struct` | Props、Commands、事件发送、DescriptorWrapper |
|
|
17
|
+
|
|
18
|
+
### 1.2 判定流程
|
|
19
|
+
|
|
20
|
+
```
|
|
21
|
+
搜索 RN 库 JS 源码中的注册入口(搜索范围:src/ 目录及其所有子目录):
|
|
22
|
+
|
|
23
|
+
1. 找到 codegenNativeComponent → ✅ 含 Codegen 原生组件 → 执行本文档 2A 流程
|
|
24
|
+
2. 找到 requireNativeComponent → ✅ 含 Legacy 原生组件 → 执行本文档 2B 流程
|
|
25
|
+
3. 找到 TurboModuleRegistry → ✅ 含 TurboModule → 仅执行方法级对比(见 FUNCTION_COMPARISON_GUIDE.md)
|
|
26
|
+
4. 找到 NativeModules 但无 1/2 → ✅ 仅含 NativeModule(方法级) → 仅执行方法级对比
|
|
27
|
+
5. 1+2+3 均找到 → ✅ 同时含原生组件和 TurboModule → 分别执行两类检视
|
|
28
|
+
6. 1+3 找到但无 2 → ✅ Codegen 原生组件 + TurboModule → 分别执行两类检视
|
|
29
|
+
7. 2+3 找到但无 1 → ✅ Legacy 原生组件 + TurboModule → 分别执行两类检视
|
|
30
|
+
8. 均未找到 → ❌ 纯 JS 库 → 无原生桥接检视需求
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
> 💡 **共存示例**:react-native-webview 同时有 `RNCWebView` 原生组件(codegenNativeComponent)和 `RNCWebViewModule` TurboModule(TurboModuleRegistry)。react-native-maps 同时有多个 Legacy 原生组件(requireNativeComponent)和 TurboModule(NativeModules)。
|
|
34
|
+
|
|
35
|
+
> ⚠️ **重要**:`requireNativeComponent` 是 RN 旧架构的原生组件注册方式,与 `codegenNativeComponent` 功能等价(都是注册 UI 组件),但注册链路追踪方式不同。不可因未找到 `codegenNativeComponent` 就判定库不含原生组件。
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## 2. 原生组件注册链路定位流程
|
|
40
|
+
|
|
41
|
+
原生组件存在两种注册架构模式,必须先判定模式再执行对应流程:
|
|
42
|
+
|
|
43
|
+
| 模式 | JS 层特征 | OHOS Package 特征 | 识别方法 |
|
|
44
|
+
|------|-----------|-------------------|----------|
|
|
45
|
+
| **模式 A:Codegen 架构** | `codegenNativeComponent` | Package 有 `createDescriptorWrapperFactoryByDescriptorType` 返回组件名 → DescriptorWrapper 映射;存在 `generated/` 目录 | 找到 `codegenNativeComponent` |
|
|
46
|
+
| **模式 B:Legacy/Descriptor 架构** | `requireNativeComponent` 或无 JS 层组件注册宏 | Package 仅注册 TurboModule(无 `createDescriptorWrapperFactoryByDescriptorType`);手动定义 Descriptor 类型;可能有 `ComponentFactory` 脚本路由 | 未找到 `codegenNativeComponent` 但找到 `requireNativeComponent` 或 `@Component struct` |
|
|
47
|
+
|
|
48
|
+
### 2A. Codegen 架构注册链路定位
|
|
49
|
+
|
|
50
|
+
此流程适用于 JS 层使用 `codegenNativeComponent` 的库(如 react-native-webview、react-native-video、react-native-screens、react-native-keyboard-controller 等)。
|
|
51
|
+
|
|
52
|
+
#### 2A.1 步骤 5a:定位 JS 层组件注册
|
|
53
|
+
|
|
54
|
+
| 项目 | 说明 |
|
|
55
|
+
|------|------|
|
|
56
|
+
| 搜索位置 | RN 库 `src/` 目录及其子目录(常见子目录:`src/specs/`、`src/`根目录) |
|
|
57
|
+
| 搜索关键词 | `codegenNativeComponent` |
|
|
58
|
+
| 文件名模式 | `*NativeComponent.ts`、`*NativeComponent.js` |
|
|
59
|
+
| 目的 | 定位 JS 层原生组件注册,提取组件名和 NativeProps 类型定义 |
|
|
60
|
+
|
|
61
|
+
**代码模式**:
|
|
62
|
+
|
|
63
|
+
```typescript
|
|
64
|
+
// Codegen 注册模式(典型)
|
|
65
|
+
export const RNCWebView = codegenNativeComponent<NativeProps>(
|
|
66
|
+
'RNCWebView'
|
|
67
|
+
) as HostComponent<NativeProps>;
|
|
68
|
+
|
|
69
|
+
// 多组件库中每个组件独立注册
|
|
70
|
+
export default codegenNativeComponent<NativeProps>('RNSScreen', {});
|
|
71
|
+
export default codegenNativeComponent<NativeProps>('RNSScreenStack', {});
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
**NativeProps 类型定义模式**:
|
|
75
|
+
|
|
76
|
+
```typescript
|
|
77
|
+
// NativeProps 通常在同一文件或单独的 Types 文件中
|
|
78
|
+
export interface NativeProps extends ViewProps {
|
|
79
|
+
javaScriptEnabled?: WithDefault<boolean, true>;
|
|
80
|
+
source?: string | Object;
|
|
81
|
+
cacheMode?: WithDefault<CacheModeEnum, 'DEFAULT>;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// NativeCommands 定义(可选)
|
|
85
|
+
export interface NativeCommands {
|
|
86
|
+
goBack(viewRef: ReactElementRef<HostComponent<NativeProps>>): void;
|
|
87
|
+
goForward(viewRef: ReactElementRef<HostComponent<NativeProps>>): void;
|
|
88
|
+
}
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
**提取要求**:
|
|
92
|
+
- 组件名(`codegenNativeComponent` 的字符串参数,如 `'RNCWebView'`、`'RNCVideo'`)
|
|
93
|
+
- **多组件库需提取所有组件名**(如 react-native-screens 有 11 个 `codegenNativeComponent`)
|
|
94
|
+
- NativeProps 接口文件路径和行号
|
|
95
|
+
- Props 完整列表(名称 + 类型)
|
|
96
|
+
- Commands 完整列表(名称 + 签名),若无 Commands 标注"⚠️ 无 Commands 定义"
|
|
97
|
+
|
|
98
|
+
#### 2A.2 步骤 5b:定位 OHOS Harmony 目录
|
|
99
|
+
|
|
100
|
+
| 项目 | 说明 |
|
|
101
|
+
|------|------|
|
|
102
|
+
| 搜索位置 | RN 库根目录下 |
|
|
103
|
+
| 关键标记 | `harmony/` 目录 |
|
|
104
|
+
| 目的 | 定位 OHOS 鸿蒙化代码的根目录 |
|
|
105
|
+
|
|
106
|
+
**Harmony 目录发现策略**:
|
|
107
|
+
|
|
108
|
+
```
|
|
109
|
+
1. 查找根目录下的 harmony/ 目录 → 大多数库的通用模式
|
|
110
|
+
2. 若根目录无 harmony/,查找子包目录(如 react-native-harmony-screens/harmony/)
|
|
111
|
+
3. 若仍无 harmony/ 目录 → ⛔ 该库可能未鸿蒙化,需进一步验证
|
|
112
|
+
|
|
113
|
+
harmony/ 目录内部结构:
|
|
114
|
+
harmony/<module_name>/ ← 模块名各异(rn_webview, rn_video, maps, svg, picker, screens, keyboard_controller 等)
|
|
115
|
+
<module_name>.har ← 预编译产物
|
|
116
|
+
src/main/ets/ ← ArkTS 源码目录
|
|
117
|
+
src/main/cpp/ ← C++ 源码目录
|
|
118
|
+
src/main/ets/generated/ ← Codegen 生成目录(模式 A 特征)
|
|
119
|
+
components/ ← 原生组件的 DescriptorWrapper 定义
|
|
120
|
+
turboModules/ ← TurboModule 的类型定义
|
|
121
|
+
index.ets
|
|
122
|
+
ts.ts
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
> ⚠️ **模块名不固定**:不同库的 harmony 子目录命名各异。`<module_name>` 不可按库名硬推,需通过目录探索确定。常见映射:webview→rn_webview, video→rn_video, maps→maps, svg→svg, picker→picker, screens→screens。
|
|
126
|
+
|
|
127
|
+
#### 2A.3 步骤 5c:定位 Package 注册类
|
|
128
|
+
|
|
129
|
+
| 项目 | 说明 |
|
|
130
|
+
|------|------|
|
|
131
|
+
| 搜索位置 | `harmony/<module_name>/src/main/ets/` 目录 |
|
|
132
|
+
| 搜索关键词 | `Package`(文件名 `*Package.ets` 或 `*Package.ts`) |
|
|
133
|
+
| 目的 | 定位 Package 注册类,提取原生组件名和 TurboModule 名 |
|
|
134
|
+
|
|
135
|
+
**两种 Package 基类的 API 区别**:
|
|
136
|
+
|
|
137
|
+
```typescript
|
|
138
|
+
// RNOHPackage(较新模式,如 react-native-webview)
|
|
139
|
+
export class RNCWebViewPackage extends RNOHPackage {
|
|
140
|
+
createDescriptorWrapperFactoryByDescriptorType(ctx): DescriptorWrapperFactoryByDescriptorType {
|
|
141
|
+
return {
|
|
142
|
+
"RNCWebView": (ctx) => new RNC.RNCWebView.DescriptorWrapper(ctx.descriptor)
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
createAnyThreadTurboModuleFactory(ctx): AnyThreadTurboModuleFactory {
|
|
146
|
+
return new WebViewTurboModulesFactory(ctx);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// RNPackage(常见模式,如 react-native-video)
|
|
151
|
+
export class RNCVideoPackage extends RNPackage {
|
|
152
|
+
createDescriptorWrapperFactoryByDescriptorType(ctx): DescriptorWrapperFactoryByDescriptorType {
|
|
153
|
+
return {
|
|
154
|
+
[RNC.RNCVideo.NAME]: (ctx) => new RNC.RNCVideo.DescriptorWrapper(ctx.descriptor),
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
createTurboModulesFactory(ctx: TurboModuleContext): TurboModulesFactory {
|
|
158
|
+
return new RNCVideoTurboModulesFactory(ctx);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
> ⚠️ **Package 基类区别**:`RNOHPackage` 使用 `createAnyThreadTurboModuleFactory()` + `AnyThreadTurboModuleFactory`;`RNPackage` 使用 `createTurboModulesFactory()` + `TurboModulesFactory`。两者注册组件的方式相同(`createDescriptorWrapperFactoryByDescriptorType`),但 TurboModule 注册 API 不同。
|
|
164
|
+
|
|
165
|
+
> ⚠️ **文件扩展名**:Package 注册文件可以是 `.ets` 或 `.ts`,搜索时需同时覆盖两种扩展名。
|
|
166
|
+
|
|
167
|
+
**提取要求**:
|
|
168
|
+
- Package 类名和继承关系(`extends RNOHPackage` 或 `extends RNPackage`)
|
|
169
|
+
- `createDescriptorWrapperFactoryByDescriptorType` 返回值中所有组件名 → DescriptorWrapper 映射
|
|
170
|
+
- TurboModule 注册中所有 TurboModule 名
|
|
171
|
+
- Package 文件路径和行号
|
|
172
|
+
|
|
173
|
+
#### 2A.4 步骤 5d:定位 DescriptorWrapper 和 generated 类型
|
|
174
|
+
|
|
175
|
+
| 项目 | 说明 |
|
|
176
|
+
|------|------|
|
|
177
|
+
| 搜索位置 | `harmony/<module_name>/src/main/ets/generated/components/` 目录 |
|
|
178
|
+
| 搜索关键词 | 组件名(如 `RNCWebView.ts`、`RNCVideo.ts`) |
|
|
179
|
+
| 目的 | 提取 Codegen 生成的完整类型定义 |
|
|
180
|
+
|
|
181
|
+
**generated/components/ComponentName.ts 的关键结构**:
|
|
182
|
+
|
|
183
|
+
```typescript
|
|
184
|
+
export namespace ComponentName {
|
|
185
|
+
export const NAME = "ComponentName" as const // 组件名常量
|
|
186
|
+
|
|
187
|
+
export interface DirectRawProps { // 所有 Prop 定义(含类型)
|
|
188
|
+
propA?: boolean;
|
|
189
|
+
propB?: string;
|
|
190
|
+
// ...
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
export interface Props extends ViewBaseProps {} // 基础 Props
|
|
194
|
+
export interface State {} // State 定义
|
|
195
|
+
export interface RawProps extends ViewRawProps, DirectRawProps {} // 完整 RawProps
|
|
196
|
+
|
|
197
|
+
export class PropsSelector extends ViewPropsSelector<Props, RawProps> {
|
|
198
|
+
get propA() { return this.rawProps.propA ?? false } // 每个 Prop 的默认值
|
|
199
|
+
get propB() { return this.rawProps.propB } // 无默认值的 Prop
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
export type Descriptor = ComponentDescriptor<typeof NAME, Props, State, RawProps>
|
|
203
|
+
|
|
204
|
+
export class DescriptorWrapper extends ViewDescriptorWrapperBase<...> {
|
|
205
|
+
protected createPropsSelector() {
|
|
206
|
+
return new PropsSelector(this.descriptor.props, this.descriptor.rawProps)
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
export interface EventPayloadByName { // 所有事件名 + Payload 类型
|
|
211
|
+
"onLoad": {url: string, ...}
|
|
212
|
+
"onError": {code: number, ...}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
export class EventEmitter {
|
|
216
|
+
emit<TEventName>(eventName: TEventName, payload: EventPayloadByName[TEventName]) {
|
|
217
|
+
this.rnInstance.emitComponentEvent(this.tag, eventName, payload)
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
export interface CommandArgvByName { // 所有 Command 名 + 参数类型
|
|
222
|
+
"goBack": []
|
|
223
|
+
"injectJavaScript": [string]
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
export class CommandReceiver {
|
|
227
|
+
subscribe<TCommandName>(commandName: TCommandName, listener: (argv: CommandArgvByName[TCommandName]) => void) {
|
|
228
|
+
// ...
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
**提取要求**:
|
|
235
|
+
- `NAME` 常量值
|
|
236
|
+
- `DirectRawProps` 中所有 Prop 名 + 类型 + 默认值(从 `PropsSelector` 中提取)
|
|
237
|
+
- `EventPayloadByName` 中所有事件名 + Payload 类型
|
|
238
|
+
- `CommandArgvByName` 中所有 Command 名 + 参数类型
|
|
239
|
+
- 若 `CommandArgvByName` 为空接口 `{}`,标注"⚠️ 无 Commands 定义"
|
|
240
|
+
- 若 `generated/components/ts.ts` 仅导出空对象 `export {}`,标注"⚠️ 该组件未在 generated 中注册"
|
|
241
|
+
|
|
242
|
+
#### 2A.5 步骤 5e:定位 ArkTS 组件实现
|
|
243
|
+
|
|
244
|
+
| 项目 | 说明 |
|
|
245
|
+
|------|------|
|
|
246
|
+
| 搜索位置 | `harmony/<module_name>/src/main/ets/` 目录(排除 generated 子目录) |
|
|
247
|
+
| 搜索关键词 | `@Component` + 组件名 |
|
|
248
|
+
| 目的 | 定位组件的实际 ArkTS 实现 |
|
|
249
|
+
|
|
250
|
+
**Codegen 架构的 ArkTS 组件实现模式**:
|
|
251
|
+
|
|
252
|
+
```typescript
|
|
253
|
+
// 典型 Codegen 架构实现(如 RNCWebView)
|
|
254
|
+
@Component
|
|
255
|
+
export struct RNCWebView {
|
|
256
|
+
public static readonly NAME = RNC.RNCWebView.NAME
|
|
257
|
+
ctx!: RNComponentContext
|
|
258
|
+
tag: number = 0
|
|
259
|
+
|
|
260
|
+
// Props 读取方式 1:通过 DescriptorWrapper.rawProps(常见于较早版本)
|
|
261
|
+
aboutToAppear() {
|
|
262
|
+
const javaScriptEnabled = this.descriptorWrapper.rawProps.javaScriptEnabled
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
// Props 读取方式 2:通过 ctx.descriptorRegistry(较新版本)
|
|
266
|
+
aboutToAppear() {
|
|
267
|
+
this.descriptor = this.ctx.descriptorRegistry.getDescriptor<Descriptor>(this.tag)
|
|
268
|
+
this.descriptor.rawProps.javaScriptEnabled
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
// Commands 注册方式 1:通过 CommandReceiver.subscribe(Codegen generated 方式)
|
|
272
|
+
aboutToAppear() {
|
|
273
|
+
const commandReceiver = new RNC.RNCWebView.CommandReceiver(
|
|
274
|
+
this.ctx.componentCommandReceiver, this.tag
|
|
275
|
+
)
|
|
276
|
+
commandReceiver.subscribe("goBack", (argv) => { this.goBack() })
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
// Commands 注册方式 2:通过 ctx.componentCommandReceiver(直接注册)
|
|
280
|
+
aboutToAppear() {
|
|
281
|
+
this.ctx.componentCommandReceiver.registerCommandCallback(this.tag, (command, args) => {
|
|
282
|
+
if (command === 'goBack') { this.goBack() }
|
|
283
|
+
})
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
// 事件发送方式 1:通过 generated EventEmitter
|
|
287
|
+
private emitter = new RNC.RNCWebView.EventEmitter(this.ctx.rnInstance, this.tag)
|
|
288
|
+
onNavigationStateChange(event) {
|
|
289
|
+
this.emitter.emit("onNavigationStateChange", {url: event.url, ...})
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
// 事件发送方式 2:通过 ctx.rnInstance.emitComponentEvent
|
|
293
|
+
this.ctx.rnInstance.emitComponentEvent(this.tag, "onNavigationStateChange", {url: ...})
|
|
294
|
+
|
|
295
|
+
build() {
|
|
296
|
+
Web({ src: this.source, controller: this.controller })
|
|
297
|
+
.javaScriptAccess(this.javaScriptEnabled)
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
**提取要求**:
|
|
303
|
+
- `@Component export struct` 或 `@Component struct` 组件名
|
|
304
|
+
- Props 读取方式和读取的 Prop 名列表
|
|
305
|
+
- Command 注册方式和注册的 Command 名列表
|
|
306
|
+
- 事件发送方式和发送的事件名列表
|
|
307
|
+
- 组件文件路径和关键行号
|
|
308
|
+
|
|
309
|
+
#### 2A.6 步骤 5f:定位 C++ Package 注册层
|
|
310
|
+
|
|
311
|
+
| 项目 | 说明 |
|
|
312
|
+
|------|------|
|
|
313
|
+
| 搜索位置 | `harmony/<module_name>/src/main/cpp/` 目录 |
|
|
314
|
+
| 搜索关键词 | `*Package.h`、`*Package.cpp`、`generated/RNOH/` |
|
|
315
|
+
| 目的 | 定位 C++ 层的组件注册和 TurboModule 注册,提取 JSIBinder 和 NapiBinder 映射 |
|
|
316
|
+
|
|
317
|
+
**C++ Package 的两种模式**:
|
|
318
|
+
|
|
319
|
+
```cpp
|
|
320
|
+
// 模式 1:Thin Wrapper(如 react-native-webview、react-native-video、react-native-screens 等)
|
|
321
|
+
// 仅继承 generated BaseReactNative*Package,不重写任何方法
|
|
322
|
+
class WebViewPackage : public BaseReactNativeWebViewPackage {
|
|
323
|
+
using Super = BaseReactNativeWebViewPackage;
|
|
324
|
+
// 所有注册逻辑由 generated BaseReactNativeWebViewPackage 提供
|
|
325
|
+
};
|
|
326
|
+
|
|
327
|
+
// 模式 2:Hand-Written Package(如 react-native-maps、react-native-svg 等)
|
|
328
|
+
// 手动实现所有注册方法,不依赖 generated
|
|
329
|
+
class MapsPackage : public Package {
|
|
330
|
+
MapsPackage(Package::Context ctx) : Package(ctx) {}
|
|
331
|
+
|
|
332
|
+
std::vector<react::ComponentDescriptorProvider> createComponentDescriptorProviders() {
|
|
333
|
+
return {
|
|
334
|
+
// 手动列出每个组件的 DescriptorProvider
|
|
335
|
+
facebook::react::AIRMapComponentDescriptorProvider(),
|
|
336
|
+
facebook::react::AIRMapMarkerComponentDescriptorProvider(),
|
|
337
|
+
};
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
ComponentJSIBinderByString createComponentJSIBinderByName() {
|
|
341
|
+
return {
|
|
342
|
+
// 手动列出每个组件名 → JSIBinder 映射
|
|
343
|
+
{"AIRMap", std::make_shared<AIRMapJSIBinder>()},
|
|
344
|
+
{"AIRMapMarker", std::make_shared<AIRMapMarkerJSIBinder>()},
|
|
345
|
+
};
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
ComponentNapiBinderByString createComponentNapiBinderByName() {
|
|
349
|
+
return {
|
|
350
|
+
// 手动列出每个组件名 → NapiBinder 映射
|
|
351
|
+
{"AIRMap", std::make_shared<AIRMapNapiBinder>()},
|
|
352
|
+
};
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
std::unique_ptr<TurboModuleFactoryDelegate> createTurboModuleFactoryDelegate() {
|
|
356
|
+
return std::make_unique<MapsTurboModuleFactoryDelegate>();
|
|
357
|
+
}
|
|
358
|
+
};
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
> ⚠️ **关键区别**:Thin Wrapper 模式的所有注册逻辑在 `generated/RNOH/generated/BaseReactNative*Package.h` 中自动生成,组件名、JSIBinder、NapiBinder、EventEmitRequestHandler 等均由 codegen 产出,不需要手动维护。Hand-Written 模式需手动实现所有注册方法。
|
|
362
|
+
|
|
363
|
+
**generated C++ 目录结构(Codegen 架构专属)**:
|
|
364
|
+
|
|
365
|
+
```
|
|
366
|
+
harmony/<module_name>/src/main/cpp/generated/RNOH/generated/
|
|
367
|
+
BaseReactNative<LibName>Package.h ← 自动生成的 Package 基类
|
|
368
|
+
# 包含:
|
|
369
|
+
# BaseReactNative*PackageTurboModuleFactoryDelegate ← TurboModule 工厂
|
|
370
|
+
# BaseReactNative*PackageEventEmitRequestHandler ← 事件处理器
|
|
371
|
+
# BaseReactNative*Package ← Package 基类
|
|
372
|
+
# createComponentDescriptorProviders() ← 自动生成的组件列表
|
|
373
|
+
# createComponentJSIBinderByName() ← 自动生成的 JSIBinder 映射
|
|
374
|
+
# createComponentNapiBinderByName() ← 自动生成的 NapiBinder 映射
|
|
375
|
+
# createTurboModuleFactoryDelegate() ← 自动生成的 TurboModule 工厂
|
|
376
|
+
|
|
377
|
+
components/
|
|
378
|
+
ComponentNameJSIBinder.h ← 自动生成的 JSIBinder(含 Props 序列化)
|
|
379
|
+
ComponentNameNapiBinder.h ← 自动生成的 NapiBinder(含 ArkTS ↔ C++ 属性绑定)
|
|
380
|
+
|
|
381
|
+
turboModules/
|
|
382
|
+
TurboModuleNameJSIBinder.h ← 自动生成的 TurboModule JSIBinder
|
|
383
|
+
```
|
|
384
|
+
|
|
385
|
+
**C++ JSIBinder 的关键结构(Props 序列化)**:
|
|
386
|
+
|
|
387
|
+
```cpp
|
|
388
|
+
// generated/components/RNCWebViewJSIBinder.h(Codegen 自动生成)
|
|
389
|
+
class RNCWebViewJSIBinder : public ViewComponentJSIBinder {
|
|
390
|
+
facebook::jsi::Object createJSIBinder(facebook::jsi::Runtime &rt) override {
|
|
391
|
+
auto obj = ViewComponentJSIBinder::createJSIBinder(rt);
|
|
392
|
+
// 每个 Prop 的序列化:propName → runtime 中写入
|
|
393
|
+
obj.setProperty(rt, "allowFileAccess", createValue(rt, allowFileAccess_));
|
|
394
|
+
obj.setProperty(rt, "javaScriptEnabled", createValue(rt, javaScriptEnabled_));
|
|
395
|
+
obj.setProperty(rt, "cacheMode", createValue(rt, cacheMode_));
|
|
396
|
+
// ... 所有 Props 逐一序列化
|
|
397
|
+
return obj;
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
// Props 值存储(通常为默认值或从 rawProps 读取)
|
|
401
|
+
bool allowFileAccess_ = false;
|
|
402
|
+
bool javaScriptEnabled_ = true;
|
|
403
|
+
std::string cacheMode_ = "LOAD_DEFAULT";
|
|
404
|
+
};
|
|
405
|
+
|
|
406
|
+
// Hand-Written JSIBinder(如 react-native-maps)
|
|
407
|
+
class AIRMapJSIBinder : public ViewComponentJSIBinder {
|
|
408
|
+
facebook::jsi::Object createJSIBinder(facebook::jsi::Runtime &rt) override {
|
|
409
|
+
auto obj = ViewComponentJSIBinder::createJSIBinder(rt);
|
|
410
|
+
obj.setProperty(rt, "provider", createValue(rt, provider_));
|
|
411
|
+
obj.setProperty(rt, "mapType", createValue(rt, mapType_));
|
|
412
|
+
obj.setProperty(rt, "zoomEnabled", createValue(rt, zoomEnabled_));
|
|
413
|
+
// ... 手动列出所有 Props
|
|
414
|
+
return obj;
|
|
415
|
+
}
|
|
416
|
+
std::string provider_;
|
|
417
|
+
std::string mapType_;
|
|
418
|
+
bool zoomEnabled_;
|
|
419
|
+
};
|
|
420
|
+
```
|
|
421
|
+
|
|
422
|
+
> ⚠️ **JSIBinder 是 C++ 层 Props 定义的关键文件**:`createJSIBinder()` 方法中的 `obj.setProperty(rt, "propName", ...)` 列出了该组件在 C++ 层注册的所有 Prop 名和默认值。这与 OHOS ArkTS `DirectRawProps`/`PropsSelector` 应完全一致。
|
|
423
|
+
|
|
424
|
+
**C++ NapiBinder 的关键结构(ArkTS ↔ C++ 属性桥接)**:
|
|
425
|
+
|
|
426
|
+
```cpp
|
|
427
|
+
class RNCWebViewNapiBinder : public ViewComponentNapiBinder {
|
|
428
|
+
napi_value createNapiBinder(napi_env env, napi_value thisObj) override {
|
|
429
|
+
// 将 ArkTS @Component struct 的属性绑定到 C++ 实例
|
|
430
|
+
NapiBinder::setProperty(env, thisObj, "javaScriptEnabled", javaScriptEnabled_);
|
|
431
|
+
NapiBinder::setProperty(env, thisObj, "cacheMode", cacheMode_);
|
|
432
|
+
// ... 所有从 ArkTS 读取的 Props
|
|
433
|
+
return thisObj;
|
|
434
|
+
}
|
|
435
|
+
};
|
|
436
|
+
```
|
|
437
|
+
|
|
438
|
+
**C++ EventEmitRequestHandler(事件发送桥接)**:
|
|
439
|
+
|
|
440
|
+
```cpp
|
|
441
|
+
// generated 中自动生成
|
|
442
|
+
class BaseReactNativeWebViewPackageEventEmitRequestHandler : public EventEmitRequestHandler {
|
|
443
|
+
void handleEvent(ConcurrentMessageQueue &mq, std::string eventName, napi_value eventPayload) override {
|
|
444
|
+
// 事件名 → JS 层事件映射
|
|
445
|
+
if (eventName == "onNavigationStateChange") { /* 处理 */ }
|
|
446
|
+
if (eventName == "onMessage") { /* 处理 */ }
|
|
447
|
+
// ...
|
|
448
|
+
}
|
|
449
|
+
};
|
|
450
|
+
```
|
|
451
|
+
|
|
452
|
+
**C++ TurboModuleFactoryDelegate(TurboModule 注册)**:
|
|
453
|
+
|
|
454
|
+
```cpp
|
|
455
|
+
// generated 中自动生成
|
|
456
|
+
class BaseReactNativeWebViewPackageTurboModuleFactoryDelegate : public TurboModuleFactoryDelegate {
|
|
457
|
+
std::unique_ptr<TurboModule> createTurboModule(std::string turboModuleName, TurboModule::Context ctx) override {
|
|
458
|
+
if (turboModuleName == "RNCWebViewModule") {
|
|
459
|
+
return std::make_unique<RNCWebViewModule>(ctx);
|
|
460
|
+
}
|
|
461
|
+
return nullptr;
|
|
462
|
+
}
|
|
463
|
+
};
|
|
464
|
+
|
|
465
|
+
// Hand-Written TurboModuleFactoryDelegate(如 react-native-maps)
|
|
466
|
+
class MapsTurboModuleFactoryDelegate : public TurboModuleFactoryDelegate {
|
|
467
|
+
std::unique_ptr<TurboModule> createTurboModule(std::string turboModuleName, TurboModule::Context ctx) override {
|
|
468
|
+
if (turboModuleName == "AIRMapManager") {
|
|
469
|
+
return std::make_unique<AIRMapManagerTurboModule>(ctx);
|
|
470
|
+
}
|
|
471
|
+
if (turboModuleName == "AIRMapMarkerManager") {
|
|
472
|
+
return std::make_shared<AIRMapMarkerManagerTurboModule>(ctx);
|
|
473
|
+
}
|
|
474
|
+
return nullptr;
|
|
475
|
+
}
|
|
476
|
+
};
|
|
477
|
+
```
|
|
478
|
+
|
|
479
|
+
**C++ ComponentInstanceFactoryDelegate(组件实例创建)**:
|
|
480
|
+
|
|
481
|
+
```cpp
|
|
482
|
+
// 如 react-native-svg 的 C++ Package
|
|
483
|
+
class SVGPackageComponentInstanceFactoryDelegate : public ComponentInstanceFactoryDelegate {
|
|
484
|
+
ComponentInstance::Shared createComponentInstance(const ComponentInstance::Context &ctx) override {
|
|
485
|
+
// 根据组件名创建对应的 C++ 组件实例
|
|
486
|
+
if (ctx.componentName == "RNSVGSvgView") {
|
|
487
|
+
return std::make_shared<RNSVGSvgViewComponentInstance>(ctx);
|
|
488
|
+
}
|
|
489
|
+
if (ctx.componentName == "RNSVGCircle") {
|
|
490
|
+
return std::make_shared<RNSVGCircleComponentInstance>(ctx);
|
|
491
|
+
}
|
|
492
|
+
// ...
|
|
493
|
+
}
|
|
494
|
+
};
|
|
495
|
+
```
|
|
496
|
+
|
|
497
|
+
> ⚠️ **ComponentInstanceFactoryDelegate 仅在需要 C++ 原生视图的组件中出现**。大多数 Codegen 架构的组件不使用此模式(视图完全由 ArkTS 渲染),但像 react-native-svg 这种复杂组件需要 C++ 层创建原生视图实例。
|
|
498
|
+
|
|
499
|
+
**CMakeLists.txt 分析**:
|
|
500
|
+
|
|
501
|
+
```cmake
|
|
502
|
+
# CMakeLists.txt 列出了所有编译的 C++ 源文件
|
|
503
|
+
add_library(rnoh_webview SHARED
|
|
504
|
+
WebViewPackage.cpp # 手写的 Package 实现
|
|
505
|
+
generated/RNOH/generated/RNCWebViewJSIBinder.cpp
|
|
506
|
+
generated/RNOH/generated/RNCWebViewNapiBinder.cpp
|
|
507
|
+
# ... 其他 generated 源文件
|
|
508
|
+
)
|
|
509
|
+
target_link_libraries(rnoh_webview PUBLIC rnoh_core)
|
|
510
|
+
```
|
|
511
|
+
|
|
512
|
+
**提取要求**:
|
|
513
|
+
- C++ Package 类名和继承模式(Thin Wrapper vs Hand-Written)
|
|
514
|
+
- 若为 Thin Wrapper,定位 `generated/RNOH/generated/BaseReactNative*Package.h` 并提取:
|
|
515
|
+
- `createComponentDescriptorProviders()` 中所有组件名
|
|
516
|
+
- `createComponentJSIBinderByName()` 中所有组件名 → JSIBinder 映射
|
|
517
|
+
- `createComponentNapiBinderByName()` 中所有组件名 → NapiBinder 映射
|
|
518
|
+
- `BaseReactNative*PackageEventEmitRequestHandler` 中所有事件名
|
|
519
|
+
- `BaseReactNative*PackageTurboModuleFactoryDelegate` 中所有 TurboModule 名
|
|
520
|
+
- 若为 Hand-Written,从 Package.h/cpp 中直接提取上述信息
|
|
521
|
+
- 从每个组件的 JSIBinder 中提取所有 Prop 名 + 默认值(`obj.setProperty(rt, "propName", ...)` 模式)
|
|
522
|
+
- 从每个组件的 NapiBinder 中提取 ArkTS → C++ 属性桥接的 Prop 名
|
|
523
|
+
- 从 TurboModuleFactoryDelegate 中提取所有 TurboModule 名
|
|
524
|
+
- 从 ComponentInstanceFactoryDelegate 中提取所有组件实例名(如有)
|
|
525
|
+
- CMakeLists.txt 中编译的源文件列表
|
|
526
|
+
- 若 C++ 层无组件注册,标注"⚠️ C++ 层无组件注册"
|
|
527
|
+
|
|
528
|
+
---
|
|
529
|
+
|
|
530
|
+
### 2B. Legacy/Descriptor 架构注册链路定位
|
|
531
|
+
|
|
532
|
+
此流程适用于 JS 层使用 `requireNativeComponent` 的库,或 JS 层无组件注册宏但 OHOS 层有 `@Component struct` 实现的库(如 react-native-maps、react-native-svg 等)。
|
|
533
|
+
|
|
534
|
+
#### 2B.1 步骤 5a:定位 JS 层组件注册
|
|
535
|
+
|
|
536
|
+
| 项目 | 说明 |
|
|
537
|
+
|------|------|
|
|
538
|
+
| 搜索位置 | RN 库 `src/` 目录及其子目录 |
|
|
539
|
+
| 搜索关键词 | `requireNativeComponent` |
|
|
540
|
+
| 目的 | 定位 Legacy 原生组件注册,提取组件名 |
|
|
541
|
+
|
|
542
|
+
**代码模式**:
|
|
543
|
+
|
|
544
|
+
```typescript
|
|
545
|
+
// requireNativeComponent 直接注册
|
|
546
|
+
const RNCWebView = requireNativeComponent<NativeProps>('RNCWebView');
|
|
547
|
+
|
|
548
|
+
// react-native-maps 的封装模式
|
|
549
|
+
function getNativeComponentName(provider, componentName) {
|
|
550
|
+
return provider === 'google'
|
|
551
|
+
? `AIRGoogle${componentName}`
|
|
552
|
+
: `AIR${componentName}`;
|
|
553
|
+
}
|
|
554
|
+
components[key] = requireNativeComponent(nativeComponentName);
|
|
555
|
+
|
|
556
|
+
// 典型 requireNativeComponent 注册
|
|
557
|
+
export default requireNativeComponent<NativeProps>('AIRMap');
|
|
558
|
+
```
|
|
559
|
+
|
|
560
|
+
> ⚠️ **动态组件名**:`requireNativeComponent` 的组件名参数可能是动态拼接的(如 react-native-maps 的 `AIRMap` vs `AIRGoogleMap`),需追踪完整的命名逻辑。
|
|
561
|
+
|
|
562
|
+
**无 JS 层组件注册的特殊情况**:
|
|
563
|
+
|
|
564
|
+
```typescript
|
|
565
|
+
// react-native-svg 在 JS 层不使用 requireNativeComponent 或 codegenNativeComponent
|
|
566
|
+
// 其原生组件通过纯 ArkTS/C++ 层注册,JS 层仅使用 SVG XML 渲染
|
|
567
|
+
// 此时需跳过 JS 层搜索,直接从 OHOS 层开始定位
|
|
568
|
+
```
|
|
569
|
+
|
|
570
|
+
**提取要求**:
|
|
571
|
+
- 所有 `requireNativeComponent` 注册的组件名(含动态拼接逻辑)
|
|
572
|
+
- 组件对应的 Props 类型定义文件路径
|
|
573
|
+
- 若 JS 层无组件注册宏,标注"⚠️ JS 层无原生组件注册宏,从 OHOS 层直接定位"
|
|
574
|
+
|
|
575
|
+
#### 2B.2 步骤 5b:定位 OHOS Harmony 目录
|
|
576
|
+
|
|
577
|
+
同 2A.2,此处不再重复。
|
|
578
|
+
|
|
579
|
+
#### 2B.3 步骤 5c:定位 Package 注册类和 ComponentFactory
|
|
580
|
+
|
|
581
|
+
| 项目 | 说明 |
|
|
582
|
+
|------|------|
|
|
583
|
+
| 搜索位置 | `harmony/<module_name>/src/main/ets/` 目录 |
|
|
584
|
+
| 搜索关键词 | `Package`、`ComponentFactory` |
|
|
585
|
+
| 目的 | 定位 Package 注册类和组件路由机制 |
|
|
586
|
+
|
|
587
|
+
**Legacy 架构的 Package 模式**:
|
|
588
|
+
|
|
589
|
+
```typescript
|
|
590
|
+
// 仅注册 TurboModule 的 Package(如 react-native-maps)
|
|
591
|
+
export class MapsPackage extends RNPackage {
|
|
592
|
+
createTurboModulesFactory(ctx: TurboModuleContext): TurboModulesFactory {
|
|
593
|
+
return new MapsTurboModulesFactory(ctx); // 仅 TurboModule,无 createDescriptorWrapperFactoryByDescriptorType
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
// 仅注册 TurboModule 的 Package(如 react-native-svg)
|
|
598
|
+
export class SvgPackage extends RNPackage {
|
|
599
|
+
createTurboModulesFactory(ctx: TurboModuleContext): TurboModulesFactory {
|
|
600
|
+
return new SvgTurboModulesFactory(ctx); // 仅 TurboModule,无组件注册
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
```
|
|
604
|
+
|
|
605
|
+
> ⚠️ **关键区别**:Legacy 架构的 Package 可能**不包含** `createDescriptorWrapperFactoryByDescriptorType` 方法。原生组件的注册通过其他机制实现(C++ Package、ComponentFactory、descriptorRegistry),而非 ArkTS Package。
|
|
606
|
+
|
|
607
|
+
**ComponentFactory 路由模式**:
|
|
608
|
+
|
|
609
|
+
```typescript
|
|
610
|
+
// 多组件库的 ComponentFactory 路由(如 react-native-maps)
|
|
611
|
+
@Component
|
|
612
|
+
export struct MapsComponentFactory {
|
|
613
|
+
public ctx!: RNComponentContext;
|
|
614
|
+
public tag: number = 0;
|
|
615
|
+
@State private componentName: string = '';
|
|
616
|
+
|
|
617
|
+
setDescriptor(newDescriptor: Descriptor) {
|
|
618
|
+
this.componentName = newDescriptor.type; // 从 descriptor 提取组件名
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
build() {
|
|
622
|
+
if (this.componentName === AIR_MAP_MARKER_TYPE) {
|
|
623
|
+
AIRMapMarker({ ctx: this.ctx, tag: this.tag })
|
|
624
|
+
} else if (this.componentName === AIR_MAP_POLYLINE_TYPE) {
|
|
625
|
+
AIRMapPolyline({ ctx: this.ctx, tag: this.tag })
|
|
626
|
+
} else if (this.componentName === AIR_MAP_CIRCLE_TYPE) {
|
|
627
|
+
AIRMapCircle({ ctx: this.ctx, tag: this.tag })
|
|
628
|
+
}
|
|
629
|
+
// ... 更多组件路由
|
|
630
|
+
}
|
|
631
|
+
}
|
|
632
|
+
```
|
|
633
|
+
|
|
634
|
+
**提取要求**:
|
|
635
|
+
- Package 类名和继承关系
|
|
636
|
+
- Package 中是否有 `createDescriptorWrapperFactoryByDescriptorType`(若无则标注"⚠️ Package 无组件注册方法,组件通过其他机制注册")
|
|
637
|
+
- TurboModule 名列表
|
|
638
|
+
- 若有 ComponentFactory,提取所有路由的组件名列表
|
|
639
|
+
- C++ Package 中注册的组件名(如有 `*Package.h`/`*Package.cpp`)
|
|
640
|
+
|
|
641
|
+
#### 2B.4 步骤 5d:定位手动定义的 Descriptor 类型
|
|
642
|
+
|
|
643
|
+
| 项目 | 说明 |
|
|
644
|
+
|------|------|
|
|
645
|
+
| 搜索位置 | `harmony/<module_name>/src/main/ets/` 目录 |
|
|
646
|
+
| 搜索关键词 | `Descriptor<`、`RawProps extends ViewRawProps` |
|
|
647
|
+
| 目的 | 定位手动定义的组件 Descriptor 类型(替代 generated/ 目录) |
|
|
648
|
+
|
|
649
|
+
**手动 Descriptor 定义模式**:
|
|
650
|
+
|
|
651
|
+
```typescript
|
|
652
|
+
// react-native-maps 的手动 Descriptor 定义
|
|
653
|
+
export interface AIRMapRawProps extends ViewRawProps {
|
|
654
|
+
cacheEnabled?: boolean;
|
|
655
|
+
camera?: Camera;
|
|
656
|
+
region?: Region;
|
|
657
|
+
mapType?: MapType;
|
|
658
|
+
zoomEnabled: boolean;
|
|
659
|
+
scrollEnabled: boolean;
|
|
660
|
+
showsUserLocation: boolean;
|
|
661
|
+
// ...
|
|
662
|
+
}
|
|
663
|
+
export type AIRMapDescriptor = Descriptor<"AIRMap", ViewBaseProps, AIRMapState, AIRMapRawProps>
|
|
664
|
+
```
|
|
665
|
+
|
|
666
|
+
> ⚠️ **区别**:Codegen 架构的 Descriptor 从 `generated/` 自动生成,Legacy 架构的 Descriptor 是**手动定义**的。手动定义的 RawProps 接口直接 `extends ViewRawProps`,类型为 `Descriptor<...>` 而非通过 `DescriptorWrapper`。
|
|
667
|
+
|
|
668
|
+
**提取要求**:
|
|
669
|
+
- 所有 `*RawProps` 接口中定义的 Prop 名 + 类型
|
|
670
|
+
- 所有 `*Descriptor` 类型定义(组件名 + 泛型参数)
|
|
671
|
+
- Descriptor 定义文件路径和行号
|
|
672
|
+
|
|
673
|
+
#### 2B.5 步骤 5e:定位 ArkTS 组件实现
|
|
674
|
+
|
|
675
|
+
| 项目 | 说明 |
|
|
676
|
+
|------|------|
|
|
677
|
+
| 搜索位置 | `harmony/<module_name>/src/main/ets/` 目录(及子目录如 `AIRMaps/`) |
|
|
678
|
+
| 搜索关键词 | `@Component` |
|
|
679
|
+
| 目的 | 定位所有 `@Component struct` 实现 |
|
|
680
|
+
|
|
681
|
+
**Legacy 架构的 ArkTS 组件实现模式**:
|
|
682
|
+
|
|
683
|
+
```typescript
|
|
684
|
+
// 典型 Legacy 架构实现(如 AIRMap)
|
|
685
|
+
@Component
|
|
686
|
+
export struct AIRMap {
|
|
687
|
+
ctx!: RNComponentContext
|
|
688
|
+
tag: number = 0
|
|
689
|
+
@State descriptor: AIRMapDescriptor = {} as AIRMapDescriptor
|
|
690
|
+
|
|
691
|
+
aboutToAppear() {
|
|
692
|
+
// Props 读取:通过 descriptorRegistry + 手动 Descriptor
|
|
693
|
+
this.descriptor = this.ctx.descriptorRegistry.getDescriptor<AIRMapDescriptor>(this.tag)
|
|
694
|
+
this.descriptor.rawProps.javaScriptEnabled
|
|
695
|
+
this.descriptor.rawProps.scrollEnabled
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
// 动态 Props 更新:订阅 descriptor 变化
|
|
699
|
+
aboutToAppear() {
|
|
700
|
+
this.cleanUpCallbacks.push(this.ctx.descriptorRegistry.subscribeToDescriptorChanges(
|
|
701
|
+
this.tag, (newDescriptor) => {
|
|
702
|
+
this.descriptor = newDescriptor as AIRMapDescriptor
|
|
703
|
+
this.mapController?.setZoomGesturesEnabled(this.descriptor.rawProps.zoomEnabled)
|
|
704
|
+
}
|
|
705
|
+
));
|
|
706
|
+
}
|
|
707
|
+
|
|
708
|
+
// Commands 注册:通过 ctx.componentCommandReceiver
|
|
709
|
+
aboutToAppear() {
|
|
710
|
+
this.ctx.componentCommandReceiver.registerCommandCallback(
|
|
711
|
+
this.tag,
|
|
712
|
+
(command, args) => {
|
|
713
|
+
// switch/if 分发命令
|
|
714
|
+
}
|
|
715
|
+
)
|
|
716
|
+
}
|
|
717
|
+
|
|
718
|
+
// 事件发送:通过 ctx.rnInstance.emitComponentEvent 或 TurboModule
|
|
719
|
+
this.ctx.rnInstance.emitComponentEvent(this.tag, "onRegionChange", {region: ...})
|
|
720
|
+
}
|
|
721
|
+
```
|
|
722
|
+
|
|
723
|
+
**提取要求**:
|
|
724
|
+
- 所有 `@Component struct` 组件名列表(多组件库可能有 10+ 个组件)
|
|
725
|
+
- 每个组件的 Props 读取方式和 Prop 名列表
|
|
726
|
+
- 每个组件的 Command 注册方式和 Command 名列表
|
|
727
|
+
- 每个组件的事件发送方式和事件名列表
|
|
728
|
+
- 组件文件路径和关键行号
|
|
729
|
+
|
|
730
|
+
#### 2B.6 步骤 5f:定位 C++ Package 注册层
|
|
731
|
+
| 项目 | 说明 |
|
|
732
|
+
|------|------|
|
|
733
|
+
| 搜索位置 | `harmony/<module_name>/src/main/cpp/` 目录 |
|
|
734
|
+
| 搜索关键词 | `*Package.h`、`*Package.cpp`、`*JSIBinder.h`、`*NapiBinder.h`、`ComponentDescriptorProvider` |
|
|
735
|
+
| 目的 | 定位 C++ 层的组件注册、Props 序列化、TurboModule 注册(Legacy 架构的组件主要通过 C++ 注册) |
|
|
736
|
+
|
|
737
|
+
> ⚠️ **Legacy 架构的 C++ Package 是组件注册的核心层**:由于 ArkTS Package 中无 `createDescriptorWrapperFactoryByDescriptorType`,组件的注册完全依赖 C++ Package。C++ Package 的 `createComponentJSIBinderByName()` 和 `createComponentNapiBinderByName()` 定义了组件名 → 绑定器的映射,而 JSIBinder 中列出了每个组件的所有 Props。
|
|
738
|
+
|
|
739
|
+
**Legacy 架构 C++ Package 的 Hand-Written 模式**:
|
|
740
|
+
|
|
741
|
+
```cpp
|
|
742
|
+
// react-native-maps 的 C++ Package(完全手写)
|
|
743
|
+
class MapsPackage : public Package {
|
|
744
|
+
MapsPackage(Package::Context ctx) : Package(ctx) {}
|
|
745
|
+
|
|
746
|
+
std::vector<react::ComponentDescriptorProvider> createComponentDescriptorProviders() override {
|
|
747
|
+
return {
|
|
748
|
+
facebook::react::AIRMapComponentDescriptorProvider(),
|
|
749
|
+
facebook::react::AIRMapMarkerComponentDescriptorProvider(),
|
|
750
|
+
facebook::react::AIRMapPolylineComponentDescriptorProvider(),
|
|
751
|
+
facebook::react::AIRMapPolygonComponentDescriptorProvider(),
|
|
752
|
+
facebook::react::AIRMapCircleComponentDescriptorProvider(),
|
|
753
|
+
// ... 所有组件
|
|
754
|
+
};
|
|
755
|
+
}
|
|
756
|
+
|
|
757
|
+
ComponentJSIBinderByString createComponentJSIBinderByName() override {
|
|
758
|
+
return {
|
|
759
|
+
{"AIRMap", std::make_shared<AIRMapJSIBinder>()},
|
|
760
|
+
{"AIRMapMarker", std::make_shared<AIRMapMarkerJSIBinder>()},
|
|
761
|
+
{"AIRMapPolyline", std::make_shared<AIRMapPolylineJSIBinder>()},
|
|
762
|
+
// ... 组件名 → JSIBinder 映射
|
|
763
|
+
};
|
|
764
|
+
}
|
|
765
|
+
|
|
766
|
+
ComponentNapiBinderByString createComponentNapiBinderByName() override {
|
|
767
|
+
return {
|
|
768
|
+
{"AIRMap", std::make_shared<AIRMapNapiBinder>()},
|
|
769
|
+
// ... 组件名 → NapiBinder 映射
|
|
770
|
+
};
|
|
771
|
+
}
|
|
772
|
+
|
|
773
|
+
std::unique_ptr<TurboModuleFactoryDelegate> createTurboModuleFactoryDelegate() override {
|
|
774
|
+
return std::make_unique<MapsTurboModuleFactoryDelegate>();
|
|
775
|
+
}
|
|
776
|
+
};
|
|
777
|
+
|
|
778
|
+
// react-native-svg 的 C++ Package(大量子组件 + ComponentInstanceFactoryDelegate)
|
|
779
|
+
class SVGPackage : public Package {
|
|
780
|
+
// createComponentDescriptorProviders(): 27+ SVG 子组件
|
|
781
|
+
// createComponentJSIBinderByName(): 27+ 组件名 → JSIBinder
|
|
782
|
+
// createComponentNapiBinderByName(): 返回空 {} (不使用 NapiBinder)
|
|
783
|
+
|
|
784
|
+
// 特殊:使用 ComponentInstanceFactoryDelegate 创建 C++ 原生视图实例
|
|
785
|
+
std::shared_ptr<ComponentInstanceFactoryDelegate> createComponentInstanceFactoryDelegate() override {
|
|
786
|
+
return std::make_shared<SVGPackageComponentInstanceFactoryDelegate>();
|
|
787
|
+
}
|
|
788
|
+
};
|
|
789
|
+
|
|
790
|
+
class SVGPackageComponentInstanceFactoryDelegate : public ComponentInstanceFactoryDelegate {
|
|
791
|
+
ComponentInstance::Shared createComponentInstance(const ComponentInstance::Context &ctx) override {
|
|
792
|
+
if (ctx.componentName == "RNSVGSvgView") {
|
|
793
|
+
return std::make_shared<RNSVGSvgViewComponentInstance>(ctx);
|
|
794
|
+
}
|
|
795
|
+
if (ctx.componentName == "RNSVGCircle") {
|
|
796
|
+
return std::make_shared<RNSVGCircleComponentInstance>(ctx);
|
|
797
|
+
}
|
|
798
|
+
// ... 每个组件创建对应的 C++ 实例
|
|
799
|
+
}
|
|
800
|
+
};
|
|
801
|
+
```
|
|
802
|
+
|
|
803
|
+
**Legacy 架构的 JSIBinder 结构(Props 序列化)**:
|
|
804
|
+
|
|
805
|
+
```cpp
|
|
806
|
+
// AIRMapJSIBinder.h
|
|
807
|
+
class AIRMapJSIBinder : public ViewComponentJSIBinder {
|
|
808
|
+
facebook::jsi::Object createJSIBinder(facebook::jsi::Runtime &rt) override {
|
|
809
|
+
auto obj = ViewComponentJSIBinder::createJSIBinder(rt);
|
|
810
|
+
obj.setProperty(rt, "provider", createValue(rt, provider_));
|
|
811
|
+
obj.setProperty(rt, "mapType", createValue(rt, mapType_));
|
|
812
|
+
obj.setProperty(rt, "zoomEnabled", createValue(rt, zoomEnabled_));
|
|
813
|
+
obj.setProperty(rt, "scrollEnabled", createValue(rt, scrollEnabled_));
|
|
814
|
+
obj.setProperty(rt, "showsUserLocation", createValue(rt, showsUserLocation_));
|
|
815
|
+
// ... 手动列出所有 Props
|
|
816
|
+
return obj;
|
|
817
|
+
}
|
|
818
|
+
|
|
819
|
+
// Props 默认值
|
|
820
|
+
std::string provider_ = "google";
|
|
821
|
+
std::string mapType_ = "standard";
|
|
822
|
+
bool zoomEnabled_ = true;
|
|
823
|
+
bool scrollEnabled_ = true;
|
|
824
|
+
bool showsUserLocation_ = false;
|
|
825
|
+
};
|
|
826
|
+
|
|
827
|
+
// SVG 子组件的 JSIBinder(继承 ViewComponentJSIBinder)
|
|
828
|
+
class RNSVGSvgViewJSIBinder : public ViewComponentJSIBinder {
|
|
829
|
+
facebook::jsi::Object createJSIBinder(facebook::jsi::Runtime &rt) override {
|
|
830
|
+
auto obj = ViewComponentJSIBinder::createJSIBinder(rt);
|
|
831
|
+
obj.setProperty(rt, "bbWidth", createValue(rt, bbWidth_));
|
|
832
|
+
obj.setProperty(rt, "bbHeight", createValue(rt, bbHeight_));
|
|
833
|
+
// ...
|
|
834
|
+
return obj;
|
|
835
|
+
}
|
|
836
|
+
};
|
|
837
|
+
```
|
|
838
|
+
|
|
839
|
+
**Legacy 架构的 TurboModuleFactoryDelegate**:
|
|
840
|
+
|
|
841
|
+
```cpp
|
|
842
|
+
class MapsTurboModuleFactoryDelegate : public TurboModuleFactoryDelegate {
|
|
843
|
+
std::unique_ptr<TurboModule> createTurboModule(std::string turboModuleName, TurboModule::Context ctx) override {
|
|
844
|
+
if (turboModuleName == "AIRMapManager") {
|
|
845
|
+
return std::make_unique<AIRMapManagerTurboModule>(ctx);
|
|
846
|
+
}
|
|
847
|
+
if (turboModuleName == "AIRMapMarkerManager") {
|
|
848
|
+
return std::make_unique<AIRMapMarkerManagerTurboModule>(ctx);
|
|
849
|
+
}
|
|
850
|
+
return nullptr;
|
|
851
|
+
}
|
|
852
|
+
};
|
|
853
|
+
```
|
|
854
|
+
|
|
855
|
+
**提取要求**:
|
|
856
|
+
- C++ Package 类名和继承模式(全部 Hand-Written)
|
|
857
|
+
- `createComponentDescriptorProviders()` 中注册的所有组件名
|
|
858
|
+
- `createComponentJSIBinderByName()` 中所有组件名 → JSIBinder 映射
|
|
859
|
+
- `createComponentNapiBinderByName()` 中所有组件名 → NapiBinder 映射
|
|
860
|
+
- 每个 JSIBinder 中 `obj.setProperty(rt, "propName", ...)` 列出的所有 Prop 名 + 默认值
|
|
861
|
+
- `createTurboModuleFactoryDelegate()` 或直接 `TurboModuleFactoryDelegate` 中所有 TurboModule 名
|
|
862
|
+
- `createComponentInstanceFactoryDelegate()` 中所有组件实例名(如有,如 react-native-svg)
|
|
863
|
+
- CMakeLists.txt 中编译的源文件列表
|
|
864
|
+
- 若 C++ 层无组件注册,标注"⚠️ C++ 层无组件注册"
|
|
865
|
+
|
|
866
|
+
---
|
|
867
|
+
|
|
868
|
+
## 3. 搜索结果记录模板
|
|
869
|
+
|
|
870
|
+
完成定位流程后,必须将结果整理为以下格式。根据架构模式选择对应模板。
|
|
871
|
+
|
|
872
|
+
### 3.1 Codegen 架构注册链路表
|
|
873
|
+
|
|
874
|
+
```markdown
|
|
875
|
+
| 原生组件名 | JS 层注册文件:行号 | NativeProps 类型文件 | generated 类型文件 | Package 注册文件:行号 | C++ Package 模式 | C++ JSIBinder 文件 | ArkTS 实现文件:行号 |
|
|
876
|
+
|------------|-------------------|--------------------|--------------------|---------------------|----------------|-------------------|---------------------|
|
|
877
|
+
| RNCWebView | RNCWebViewNativeComponent.ts:355 | RNCWebViewNativeComponent.ts:151 | generated/components/RNCWebView.ts:19 | RNCWebViewPackage.ets:16 | Thin Wrapper (BaseReactNativeWebViewPackage) | generated/RNOH/generated/components/RNCWebViewJSIBinder.h | RNCWebView.ets:51 |
|
|
878
|
+
| RNCVideo | VideoNativeComponent.ts:409 | VideoNativeComponent.ts:22 | generated/components/RNCVideo.ts:19 | RNCVideoPackage.ts:54 | Thin Wrapper (BaseReactNativeVideoPackage) | generated/RNOH/generated/components/RNCVideoJSIBinder.h | RNCVideo.ets:108 |
|
|
879
|
+
```
|
|
880
|
+
|
|
881
|
+
### 3.2 Legacy 架构注册链路表
|
|
882
|
+
|
|
883
|
+
```markdown
|
|
884
|
+
| 原生组件名 | JS 层注册方式 | JS 注册文件:行号 | Descriptor 类型文件 | ComponentFactory 文件 | Package 注册文件:行号 | C++ Package 模式 | C++ JSIBinder 文件 | ArkTS 实现文件:行号 |
|
|
885
|
+
|------------|-------------|-----------------|--------------------|----------------------|---------------------|----------------|-------------------|---------------------|
|
|
886
|
+
| AIRMap | requireNativeComponent | MapViewNativeComponent.ts:1226 | AIRMapDescriptorTypes.ts:69 | MapsComponentFactory.ets:48 | MapsPackage.ts:48 | Hand-Written (MapsPackage) | AIRMapJSIBinder.h | AIRMaps/AIRMap.ets:47 |
|
|
887
|
+
| AIRMapMarker | requireNativeComponent | MapMarkerNativeComponent.ts | AIRMapDescriptorTypes.ts:86 | MapsComponentFactory.ets:76 | MapsPackage.ts:48 | Hand-Written (MapsPackage) | AIRMapMarkerJSIBinder.h | AIRMaps/AIRMapMarker.ets:31 |
|
|
888
|
+
```
|
|
889
|
+
|
|
890
|
+
### 3.3 完整搜索记录示例
|
|
891
|
+
|
|
892
|
+
**Codegen 架构示例(react-native-webview)**:
|
|
893
|
+
|
|
894
|
+
```
|
|
895
|
+
模式判定: Codegen 架构(codegenNativeComponent)
|
|
896
|
+
|
|
897
|
+
5a: src/RNCWebViewNativeComponent.ts
|
|
898
|
+
→ codegenNativeComponent<NativeProps>('RNCWebView') as HostComponent<NativeProps>
|
|
899
|
+
→ 组件名: "RNCWebView"
|
|
900
|
+
→ NativeProps 接口: 35+ Props + 11 Commands
|
|
901
|
+
|
|
902
|
+
5b: harmony/rn_webview/
|
|
903
|
+
→ 模块名: rn_webview
|
|
904
|
+
|
|
905
|
+
5c: harmony/rn_webview/src/main/ets/RNCWebViewPackage.ets
|
|
906
|
+
→ class RNCWebViewPackage extends RNOHPackage
|
|
907
|
+
→ createDescriptorWrapperFactoryByDescriptorType: { "RNCWebView": RNC.RNCWebView.DescriptorWrapper }
|
|
908
|
+
→ createAnyThreadTurboModuleFactory: WebViewTurboModulesFactory
|
|
909
|
+
→ TurboModule: RNCWebViewModule.NAME
|
|
910
|
+
|
|
911
|
+
5d: harmony/rn_webview/src/main/ets/generated/components/RNCWebView.ts
|
|
912
|
+
→ NAME = "RNCWebView"
|
|
913
|
+
→ DirectRawProps: 50+ Props with types
|
|
914
|
+
→ PropsSelector: default values for each prop
|
|
915
|
+
→ EventPayloadByName: 14 events
|
|
916
|
+
→ CommandArgvByName: 11 commands
|
|
917
|
+
|
|
918
|
+
5e: harmony/rn_webview/src/main/ets/RNCWebView.ets
|
|
919
|
+
→ @Component export struct RNCWebView
|
|
920
|
+
→ 包含 Props 处理、事件发送、命令回调注册
|
|
921
|
+
|
|
922
|
+
5f: harmony/rn_webview/src/main/cpp/WebViewPackage.h
|
|
923
|
+
→ C++ Package 模式: Thin Wrapper (继承 BaseReactNativeWebViewPackage)
|
|
924
|
+
→ generated/RNOH/generated/BaseReactNativeWebViewPackage.h:
|
|
925
|
+
→ createComponentDescriptorProviders: [RNCWebView]
|
|
926
|
+
→ createComponentJSIBinderByName: {"RNCWebView" → RNCWebViewJSIBinder}
|
|
927
|
+
→ createComponentNapiBinderByName: {"RNCWebView" → RNCWebViewNapiBinder}
|
|
928
|
+
→ EventEmitRequestHandler: 14 events (onNavigationStateChange, onMessage, etc.)
|
|
929
|
+
→ TurboModuleFactoryDelegate: RNCWebViewModule
|
|
930
|
+
→ JSIBinder Props: 50+ props (obj.setProperty(rt, "javaScriptEnabled", ...), etc.)
|
|
931
|
+
→ NapiBinder Props: 桥接 ArkTS 属性到 C++
|
|
932
|
+
```
|
|
933
|
+
|
|
934
|
+
**Legacy 架构示例(react-native-maps)**:
|
|
935
|
+
|
|
936
|
+
```
|
|
937
|
+
模式判定: Legacy 架构(requireNativeComponent)
|
|
938
|
+
|
|
939
|
+
5a: src/MapView.tsx + src/decorateMapComponent.ts
|
|
940
|
+
→ requireNativeComponent('AIRMap') + requireNativeComponent('AIRGoogleMap')
|
|
941
|
+
→ 组件名: AIRMap, AIRMapMarker, AIRMapPolyline, AIRMapPolygon, AIRMapCircle, AIRMapCallout, etc.
|
|
942
|
+
→ NativeModules: AirMapModule, AIRMapManager
|
|
943
|
+
|
|
944
|
+
5b: harmony/maps/
|
|
945
|
+
→ 模块名: maps
|
|
946
|
+
|
|
947
|
+
5c: harmony/maps/src/main/ets/MapsPackage.ts
|
|
948
|
+
→ class MapsPackage extends RNPackage
|
|
949
|
+
→ ⚠️ 无 createDescriptorWrapperFactoryByDescriptorType(仅 TurboModule 注册)
|
|
950
|
+
→ TurboModules: AIRMapManager, AIRMapMarkerManager
|
|
951
|
+
→ ComponentFactory: MapsComponentFactory.ets(路由 11 个子组件)
|
|
952
|
+
|
|
953
|
+
5d: harmony/maps/src/main/ets/AIRMaps/AIRMapDescriptorTypes.ts
|
|
954
|
+
→ 手动定义: AIRMapRawProps (20+ Props), AIRMapMarkerRawProps, etc.
|
|
955
|
+
→ 手动 Descriptor 类型: AIRMapDescriptor, AIRMapMarkerDescriptor, etc.
|
|
956
|
+
|
|
957
|
+
5e: harmony/maps/src/main/ets/AIRMaps/AIRMap.ets + 11 个子组件
|
|
958
|
+
→ @Component export struct AIRMap { ctx.descriptorRegistry.getDescriptor }
|
|
959
|
+
→ @Component export struct AIRMapMarker { ... }
|
|
960
|
+
→ ...
|
|
961
|
+
|
|
962
|
+
5f: harmony/maps/src/main/cpp/MapsPackage.h
|
|
963
|
+
→ C++ Package 模式: Hand-Written (直接继承 Package)
|
|
964
|
+
→ createComponentDescriptorProviders: AIRMap, AIRMapMarker, AIRMapPolyline, AIRMapPolygon, AIRMapCircle, etc.
|
|
965
|
+
→ createComponentJSIBinderByName: {"AIRMap" → AIRMapJSIBinder, "AIRMapMarker" → AIRMapMarkerJSIBinder, ...}
|
|
966
|
+
→ createComponentNapiBinderByName: {"AIRMap" → AIRMapNapiBinder, ...}
|
|
967
|
+
→ TurboModuleFactoryDelegate: AIRMapManager, AIRMapMarkerManager
|
|
968
|
+
→ AIRMapJSIBinder Props: provider, mapType, zoomEnabled, scrollEnabled, showsUserLocation, etc.
|
|
969
|
+
```
|
|
970
|
+
|
|
971
|
+
### 3.4 无原生组件时的记录
|
|
972
|
+
|
|
973
|
+
若库不含原生组件(仅 TurboModule),记录为:
|
|
974
|
+
|
|
975
|
+
```markdown
|
|
976
|
+
| 原生组件名 | JS 层注册文件:行号 | ... | ArkTS 实现文件:行号 |
|
|
977
|
+
|------------|-------------------|-----|---------------------|
|
|
978
|
+
| ⚠️ 无原生组件 | — | ... | — |
|
|
979
|
+
```
|
|
980
|
+
|
|
981
|
+
---
|
|
982
|
+
|
|
983
|
+
## 4. 原生组件架构一致性检视对比规范
|
|
984
|
+
|
|
985
|
+
定位到注册链路后,需对比 Android/iOS 上游实现与 OHOS 实现的架构一致性。
|
|
986
|
+
|
|
987
|
+
### 4.1 检视项与扣分规则
|
|
988
|
+
|
|
989
|
+
| # | 检视项 | 对比对象 | 扣分规则 | 致命度 |
|
|
990
|
+
|---|--------|----------|----------|--------|
|
|
991
|
+
| 1 | 组件名注册 | Android ViewManager `getName()` / iOS `RCT_EXPORT_MODULE()` vs OHOS `NAME` 常量 / DescriptorWrapper / Descriptor 组件名 vs C++ `createComponentDescriptorProviders` 组件名 | 不一致扣 5 分 | 中等 |
|
|
992
|
+
| 2 | Props 类型定义 | RN 上游 NativeProps vs OHOS DirectRawProps/手动 RawProps vs C++ JSIBinder `obj.setProperty` 列出的 Prop 名 | 缺失 Prop 扣 3 分/个,类型不一致扣 5 分/个 | 严重 |
|
|
993
|
+
| 3 | Commands 注册 | RN 上游 Commands 列表 vs OHOS CommandArgvByName/registerCommandCallback 列表 vs C++ CommandDescriptor | 缺失 Command 扣 8 分/个 | 致命 |
|
|
994
|
+
| 4 | Props 传递机制 | Android `@ReactProp` / iOS `RCT_EXPORT_VIEW_PROPERTY` vs OHOS `rawProps.xxx` 读取 vs C++ JSIBinder `obj.setProperty` + NapiBinder 桥接 | 关键 Prop 未传递扣 8 分/个 | 致命 |
|
|
995
|
+
| 5 | Commands 实现 | Android `receiveCommand()` / iOS `RCT_EXPORT_METHOD` vs OHOS Command 回调实现 vs C++ Command 处理逻辑 | Command 逻辑缺失或不一致扣 8 分/个 | 致命 |
|
|
996
|
+
| 6 | 事件发送机制 | Android `RCTEventEmitter.receiveEvent()` / iOS `RCTDirectEventBlock` vs OHOS `EventEmitter.emit()` / `rnInstance.emitComponentEvent()` vs C++ `EventEmitRequestHandler` | 事件发送机制不一致扣 5 分/个 | 中等 |
|
|
997
|
+
| 7 | DescriptorWrapper 映射 | OHOS DescriptorWrapper 是否正确映射 rawProps 到 ArkTS 组件 Props(Codegen 模式) | 映射缺失扣 5 分/个 | 中等 |
|
|
998
|
+
| 8 | Descriptor 类型映射 | OHOS 手动 Descriptor 是否完整包含所有 Props(Legacy 模式) | 类型缺失扣 5 分/个 | 中等 |
|
|
999
|
+
| 9 | C++ JSIBinder ↔ OHOS Props 映射 | C++ JSIBinder 中 `obj.setProperty(rt, "propName", ...)` 列出的 Prop 名 vs OHOS `DirectRawProps`/`RawProps` 中定义的 Prop 名 | JSIBinder 有但 OHOS 无→C++→ArkTS断桥扣 8 分/个;OHOS 有但 JSIBinder 无→JS→C++断桥扣 8 分/个 | 致命 |
|
|
1000
|
+
| 10 | C++ NapiBinder ↔ ArkTS 属性桥接 | C++ NapiBinder 中桥接的 Prop 名 vs ArkTS `@Component struct` 中实际使用的 Prop 名 | NapiBinder 缺失导致 ArkTS 无法获取 C++ 侧 Prop 值,扣 5 分/个 | 中等 |
|
|
1001
|
+
| 11 | C++ EventEmitRequestHandler ↔ OHOS 事件 | C++ `handleEvent` 中注册的事件名 vs OHOS `EventEmitter.emit` / `rnInstance.emitComponentEvent` 发送的事件名 | 事件名不一致扣 5 分/个 | 中等 |
|
|
1002
|
+
| 12 | C++ TurboModule 注册 vs JS 层 | C++ `TurboModuleFactoryDelegate.createTurboModule` 中注册的 TurboModule 名 vs JS 层 `TurboModuleRegistry.get` 注册名 | 不一致扣 3 分/个 | 中等 |
|
|
1003
|
+
|
|
1004
|
+
### 4.2 Props 函数级对比格式
|
|
1005
|
+
|
|
1006
|
+
每个 Prop 必须逐项对比,而非笼统描述"Props 大致一致":
|
|
1007
|
+
|
|
1008
|
+
```markdown
|
|
1009
|
+
| # | Prop 名 | RN 上游 NativeProps 类型 | C++ JSIBinder 默认值 | OHOS 类型定义 | OHOS ArkTS rawProps 使用 | OHOS 文件:行号 | 状态 | 扣分 |
|
|
1010
|
+
|---|---------|------------------------|---------------------|-------------|-------------------------|---------------|------|------|
|
|
1011
|
+
| 1 | `javaScriptEnabled` | `WithDefault<boolean, true>` | `true` | `boolean?` (DirectRawProps) + `?? true` (PropsSelector) | `this.descriptor.rawProps.javaScriptEnabled` | `RNCWebView.ets:67` | ✅ 一致 | 0 |
|
|
1012
|
+
| 2 | `cacheMode` | `WithDefault<CacheModeEnum, 'DEFAULT'>` | `"LOAD_DEFAULT"` | `'LOAD_DEFAULT' | ...'` (DirectRawProps) + `?? 'LOAD_DEFAULT'` (PropsSelector) | `this.descriptor.rawProps.cacheMode as CACHE_MODE` | `RNCWebView.ets:738` | ⚠️ 映射需验证 | -3 |
|
|
1013
|
+
| 3 | `injectedJavaScript` | `string?` | 无默认值 | `string?` (DirectRawProps) | ⛔ 未在 rawProps 中读取 | — | ❌ 缺失 | -8 |
|
|
1014
|
+
| 4 | `customMapStyle` | `object?` | ⛔ JSIBinder 中无此 Prop | `MapStyleElement[]?` (AIRMapRawProps) | `this.descriptor.rawProps.customMapStyle` | `AIRMap.ets:92` | ❌ JS→C++断桥 | -8 |
|
|
1015
|
+
```
|
|
1016
|
+
|
|
1017
|
+
**Codegen vs Legacy 模式对比差异**:
|
|
1018
|
+
|
|
1019
|
+
| 对比维度 | Codegen 模式 | Legacy 模式 |
|
|
1020
|
+
|---------|-------------|------------|
|
|
1021
|
+
| Props 类型来源 | `generated/components/ComponentName.ts` 的 `DirectRawProps` + `PropsSelector` | 手动 `*DescriptorTypes.ts` 的 `*RawProps extends ViewRawProps` |
|
|
1022
|
+
| 默认值 | `PropsSelector` 中 `?? defaultValue` | `*RawProps` 接口中可选 `?` 表示有默认值,但默认值可能未定义 |
|
|
1023
|
+
| Props 读取方式 | `descriptorWrapper.rawProps.xxx` 或 `descriptor.rawProps.xxx` | `descriptor.rawProps.xxx`(通过 `ctx.descriptorRegistry.getDescriptor`) |
|
|
1024
|
+
|
|
1025
|
+
**常见问题模式**:
|
|
1026
|
+
|
|
1027
|
+
| 问题 | 识别方式 | 扣分 |
|
|
1028
|
+
|------|----------|------|
|
|
1029
|
+
| Prop 未从 rawProps 读取 | ArkTS 实现中无 `rawProps.xxx` 读取 | 关键 Prop -8/个,次要 Prop -3/个 |
|
|
1030
|
+
| Prop 类型映射错误 | rawProps 读取后有错误的 `as` 类型转换(如 `as string` 而非 `as boolean`) | -5/个 |
|
|
1031
|
+
| Prop 默认值不一致 | OHOS `PropsSelector` 或 `RawProps` 的默认值与上游不同 | -3/个 |
|
|
1032
|
+
| Prop 只读未使用 | rawProps 读取后未在 `build()` 中传递给原生组件 | 关键 Prop -5/个 |
|
|
1033
|
+
| 手动 RawProps 缺失 Prop(Legacy 模式) | 手动定义的 `*RawProps` 接口中缺少上游存在的 Prop | -5/个 |
|
|
1034
|
+
| C++ JSIBinder 缺失 Prop | C++ JSIBinder 的 `obj.setProperty(rt, "propName", ...)` 中缺少 JS 上游存在的 Prop → JS→C++ 断桥,JS 传入值无法到达 C++/ArkTS | 致命 Prop -8/个,次要 Prop -3/个 |
|
|
1035
|
+
| C++ NapiBinder 缺失 Prop | C++ NapiBinder 的 `setProperty(env, thisObj, "propName", ...)` 中缺少 Prop → C++→ArkTS 断桥,C++ 侧值无法传递给 ArkTS | -5/个 |
|
|
1036
|
+
| OHOS RawProps 缺失 JSIBinder 中存在的 Prop | C++ JSIBinder 有此 Prop 但 OHOS `DirectRawProps`/`RawProps` 中未定义 → ArkTS 无法接收 | -5/个 |
|
|
1037
|
+
|
|
1038
|
+
### 4.3 Commands 函数级对比格式
|
|
1039
|
+
|
|
1040
|
+
每个 Command 必须逐项对比:
|
|
1041
|
+
|
|
1042
|
+
```markdown
|
|
1043
|
+
| # | Command 名 | RN 上游签名 | C++ Command 处理 | OHOS 注册方式 | OHOS ArkTS 实现文件:行号 | 状态 | 扣分 |
|
|
1044
|
+
|---|-----------|-------------|------------------|--------------|-------------------------|------|------|
|
|
1045
|
+
| 1 | `goBack` | `goBack(viewRef): void` | ✅ C++ CommandDescriptor | CommandReceiver.subscribe("goBack", handler) → `controller.backward()` | `WebViewBaseOperate.ets:361` | ✅ 一致 | 0 |
|
|
1046
|
+
| 2 | `clearFormData` | `clearFormData(viewRef): void` | ⛔ 无 C++ CommandDescriptor | ⛔ 不在 CommandArgvByName | — | ⚠️ 缺失(已文档化) | -8 |
|
|
1047
|
+
| 3 | `reload` | `reload(viewRef): void` | ✅ C++ CommandDescriptor | CommandReceiver.subscribe("reload", handler) → 空实现 `// TODO` | `WebViewBaseOperate.ets:402` | ❌ Stub | -8 |
|
|
1048
|
+
| 4 | `animateToRegion` | `animateToRegion(viewRef, region, duration): void` | ✅ C++ TurboModule 方法 | ctx.componentCommandReceiver → 注释掉 | `AIRMap.ets:97` | ❌ 注释/空实现 | -8 |
|
|
1049
|
+
```
|
|
1050
|
+
|
|
1051
|
+
**Codegen vs Legacy 模式 Command 对比差异**:
|
|
1052
|
+
|
|
1053
|
+
| 对比维度 | Codegen 模式 | Legacy 模式 |
|
|
1054
|
+
|---------|-------------|------------|
|
|
1055
|
+
| Command 定义来源 | `generated/` 的 `CommandArgvByName` 接口 | JS 层 `NativeCommands` 或 `requireNativeComponent` 伴随的命令定义 |
|
|
1056
|
+
| Command 注册方式 | `CommandReceiver.subscribe(commandName, handler)` | `ctx.componentCommandReceiver.registerCommandCallback(tag, (command, args) => { if (command === ...) })` |
|
|
1057
|
+
| Command 分发方式 | 每个 Command 独立订阅回调 | switch/if-else 分发 |
|
|
1058
|
+
|
|
1059
|
+
**常见问题模式**:
|
|
1060
|
+
|
|
1061
|
+
| 问题 | 识别方式 | 扣分 |
|
|
1062
|
+
|------|----------|------|
|
|
1063
|
+
| Command 未注册 | Codegen: `CommandArgvByName` 中缺失;Legacy: `registerCommandCallback` 中无对应分支;C++: 无 CommandDescriptor 或 TurboModule 方法 | -8/个 |
|
|
1064
|
+
| Command 回调为空实现 | `// TODO`、注释代码、空方法体 | -8/个 |
|
|
1065
|
+
| Command 逻辑与上游不一致 | Android `receiveCommand` 的实际操作与 OHOS 回调操作不同 | -8/个 |
|
|
1066
|
+
| C++ Command 未实现 | C++ 层无对应 CommandDescriptor 或 TurboModule 方法 → Command 无法从 JS 传递到 ArkTS | -8/个 |
|
|
1067
|
+
|
|
1068
|
+
### 4.4 事件发送对比格式
|
|
1069
|
+
|
|
1070
|
+
```markdown
|
|
1071
|
+
| # | 事件名 | Android/iOS 触发方式 | C++ EventEmitRequestHandler | OHOS 触发方式 | OHOS 文件:行号 | 数据格式一致 | 状态 | 扣分 |
|
|
1072
|
+
|---|--------|---------------------|----------------------------|-------------|---------------|-------------|------|------|
|
|
1073
|
+
| 1 | `onNavigationStateChange` | `RCTEventEmitter.receiveEvent` | ✅ handled in EventEmitRequestHandler | `EventEmitter.emit("onNavigationStateChange", payload)` | `RNCWebView.ets:156` | ✅ | ✅ 一致 | 0 |
|
|
1074
|
+
| 2 | `onMessage` | iOS: `RCTDirectEventBlock onMessage` | ⛔ 未在 handler 中注册 | ⛔ 未在 emit 中注册 | — | — | ❌ C++ 层未注册 | -5 |
|
|
1075
|
+
| 3 | `onRegionChange` | Android: `onRegionChange` event | ✅ handled | `ctx.rnInstance.emitComponentEvent(tag, "onRegionChange", {region})` | `AIRMap.ets:xxx` | ⚠️ | ⚠️ Payload 不一致 | -5 |
|
|
1076
|
+
```
|
|
1077
|
+
|
|
1078
|
+
**Codegen vs Legacy 模式事件对比差异**:
|
|
1079
|
+
|
|
1080
|
+
| 对比维度 | Codegen 模式 | Legacy 模式 |
|
|
1081
|
+
|---------|-------------|------------|
|
|
1082
|
+
| 事件类型来源 | `generated/` 的 `EventPayloadByName` 接口 | JS 层组件 Props 中的 `onXxx?: DirectEventHandler<...>` 或手动定义 |
|
|
1083
|
+
| 事件发送方式 | `EventEmitter.emit(eventName, payload)` | `ctx.rnInstance.emitComponentEvent(tag, eventName, payload)` 或通过 TurboModule 间接发送 |
|
|
1084
|
+
| 事件 Payload 格式 | `EventPayloadByName` 中定义的精确类型 | 手动构造的 Object |
|
|
1085
|
+
|
|
1086
|
+
---
|
|
1087
|
+
|
|
1088
|
+
## 5. 各平台原生组件实现特征对比
|
|
1089
|
+
|
|
1090
|
+
### 5.1 Android ViewManager 实现特征
|
|
1091
|
+
|
|
1092
|
+
| 特征 | 代码模式 | 说明 |
|
|
1093
|
+
|------|----------|------|
|
|
1094
|
+
| 组件名注册 | `getName() → "RNCWebView"` | ViewManager 暴露给 JS 的组件名 |
|
|
1095
|
+
| Props 注册 | `@ReactProp(name = "javaScriptEnabled", defaultBoolean = true)` | 每个 Prop 单独注解 |
|
|
1096
|
+
| Commands 注册 | `@ReactProp(name = COMMAND_GOBACK)` 常量 + `receiveCommand(view, commandId, args)` | Commands 通过常量映射 + switch 分发 |
|
|
1097
|
+
| 事件发送 | `getReactApplicationContext().getJSModule(RCTEventEmitter.class).receiveEvent(id, "onNavigationStateChange", event)` | 通过 RCTEventEmitter 发送 |
|
|
1098
|
+
| 视图创建 | `createViewInstance(reactContext) → WebView(context)` | 返回原生视图实例 |
|
|
1099
|
+
|
|
1100
|
+
### 5.2 iOS ViewManager 实现特征
|
|
1101
|
+
|
|
1102
|
+
| 特征 | 代码模式 | 说明 |
|
|
1103
|
+
|------|----------|------|
|
|
1104
|
+
| 组件名注册 | `RCT_EXPORT_MODULE(RNCWebView)` | 宏导出组件名 |
|
|
1105
|
+
| Props 注册 | `RCT_EXPORT_VIEW_PROPERTY(javaScriptEnabled, BOOL)` | 每个 Prop 单独宏 |
|
|
1106
|
+
| Commands 注册 | `RCT_EXPORT_METHOD(goBack:(RCTComponentTag *)reactTag)` | 每个 Command 单独宏 |
|
|
1107
|
+
| 事件发送 | `self.onNavigationStateChange(@{@"url": url, ...})` | Block 回调 |
|
|
1108
|
+
| 视图创建 | `view() → WKWebView()` | 返回原生视图实例 |
|
|
1109
|
+
|
|
1110
|
+
### 5.3 OHOS ArkTS + C++ 组件实现特征(Codegen 架构)
|
|
1111
|
+
|
|
1112
|
+
| 层级 | 特征 | 代码模式 | 说明 |
|
|
1113
|
+
|------|------|----------|------|
|
|
1114
|
+
| ArkTS | 组件名注册 | Package `createDescriptorWrapperFactoryByDescriptorType` 中 `"RNCWebView": DescriptorWrapper` | 通过 Package 注册组件名 |
|
|
1115
|
+
| ArkTS | Props 类型 | `generated/` 中 `DirectRawProps` + `PropsSelector`(含默认值) | Codegen 自动生成 |
|
|
1116
|
+
| ArkTS | Props 读取 | `descriptorWrapper.rawProps.xxx` 或 `descriptor.rawProps.xxx` | 从 rawProps 读取所有 Prop |
|
|
1117
|
+
| ArkTS | Commands 注册 | `CommandReceiver.subscribe(commandName, handler)` | 通过 CommandReceiver 订阅 |
|
|
1118
|
+
| ArkTS | 事件发送 | `EventEmitter.emit(eventName, payload)` | 通过 generated EventEmitter 发送 |
|
|
1119
|
+
| ArkTS | 视图渲染 | `build() { Web({src: ...}).javaScriptAccess(...) }` | ArkUI 声明式渲染 |
|
|
1120
|
+
| C++ | Package 模式 | Thin Wrapper `class XxxPackage extends BaseReactNativeXxxPackage` | 仅继承 generated 基类,不重写方法 |
|
|
1121
|
+
| C++ | 组件注册 | `BaseReactNative*Package.h` 中 `createComponentDescriptorProviders()` 自动列出 | Codegen 自动生成组件列表 |
|
|
1122
|
+
| C++ | Props 序列化 | `*JSIBinder.h` 中 `obj.setProperty(rt, "propName", value)` | 每个 Prop 从 JS 序列化到 C++ |
|
|
1123
|
+
| C++ | Props 桥接 | `*NapiBinder.h` 中 `setProperty(env, thisObj, "propName", value)` | C++ 侧 Prop 桥接到 ArkTS |
|
|
1124
|
+
| C++ | 事件处理 | `BaseReactNative*PackageEventEmitRequestHandler` 中 `handleEvent` | 自动生成事件分发 |
|
|
1125
|
+
| C++ | TurboModule | `BaseReactNative*PackageTurboModuleFactoryDelegate` 中 `createTurboModule` | 自动生成 TurboModule 工厂 |
|
|
1126
|
+
|
|
1127
|
+
### 5.4 OHOS ArkTS + C++ 组件实现特征(Legacy 架构)
|
|
1128
|
+
|
|
1129
|
+
| 层级 | 特征 | 代码模式 | 说明 |
|
|
1130
|
+
|------|------|----------|------|
|
|
1131
|
+
| ArkTS | 组件名注册 | 手动 `Descriptor<"ComponentName", ...>` 类型 + C++ `ComponentDescriptorProvider` 或 ComponentFactory 路由 | 通过手动 Descriptor 或 C++ 注册 |
|
|
1132
|
+
| ArkTS | Props 类型 | 手动 `*RawProps extends ViewRawProps` 接口 | 手动定义,无自动默认值 |
|
|
1133
|
+
| ArkTS | Props 读取 | `ctx.descriptorRegistry.getDescriptor<Tag>(this.tag).rawProps.xxx` | 通过 descriptorRegistry 获取 |
|
|
1134
|
+
| ArkTS | Commands 注册 | `ctx.componentCommandReceiver.registerCommandCallback(tag, (command, args) => { if/switch })` | 直接注册 + 分发 |
|
|
1135
|
+
| ArkTS | 事件发送 | `ctx.rnInstance.emitComponentEvent(tag, eventName, payload)` | 直接调用 rnInstance |
|
|
1136
|
+
| ArkTS | 多组件路由 | `ComponentFactory.ets` 的 `build()` 中 if-else 分发 | 多组件库使用工厂模式路由 |
|
|
1137
|
+
| ArkTS | 视图渲染 | `build() { MapComponent(...).xxx(...) }` | ArkUI 声明式渲染 |
|
|
1138
|
+
| C++ | Package 模式 | Hand-Written `class XxxPackage : public Package` | 手动实现所有注册方法 |
|
|
1139
|
+
| C++ | 组件注册 | `createComponentDescriptorProviders()` 手动列出每个组件 | 手动维护组件列表 |
|
|
1140
|
+
| C++ | Props 序列化 | 每个 `*JSIBinder.h` 中 `obj.setProperty(rt, "propName", value)` 手动列出 | 手动定义 Props 序列化 |
|
|
1141
|
+
| C++ | Props 桥接 | 每个 `*NapiBinder.h` 中 `setProperty(env, thisObj, "propName", value)` 手动列出 | 手动定义 C++→ArkTS 桥接 |
|
|
1142
|
+
| C++ | TurboModule | `TurboModuleFactoryDelegate` 中 `createTurboModule` 手动列出 | 手动定义 TurboModule 工厂 |
|
|
1143
|
+
| C++ | 组件实例 | `ComponentInstanceFactoryDelegate::createComponentInstance` 中 if-else 分发(如 react-native-svg) | 需 C++ 原生视图的组件 |
|
|
1144
|
+
|
|
1145
|
+
---
|
|
1146
|
+
|
|
1147
|
+
## 6. 特殊场景与注意事项
|
|
1148
|
+
|
|
1149
|
+
### 6.1 多组件库
|
|
1150
|
+
|
|
1151
|
+
若库包含多个原生组件(如 react-native-maps 有 AIRMap + AIRMapMarker + AIRMapPolyline + AIRMapPolygon + AIRMapCircle 等;react-native-screens 有 11 个组件),需对每个组件独立执行定位流程,并在 4.2-4.4 中分别对比。
|
|
1152
|
+
|
|
1153
|
+
### 6.2 仅 Props 无 Commands 的组件
|
|
1154
|
+
|
|
1155
|
+
部分组件仅定义 Props 而无 Commands(如简单的进度条组件、react-native-video 的 RNCVideo `CommandArgvByName` 为空接口 `{}`)。此时 Commands 对比表标注"⚠️ 无 Commands 定义"即可,不扣分。
|
|
1156
|
+
|
|
1157
|
+
### 6.3 Codegen 生成的类型文件
|
|
1158
|
+
|
|
1159
|
+
OHOS 鸿蒙化代码中 `generated/` 目录存放 Codegen 自动生成的类型定义文件。关键结构:
|
|
1160
|
+
|
|
1161
|
+
```
|
|
1162
|
+
generated/
|
|
1163
|
+
components/
|
|
1164
|
+
ComponentName.ts ← 原生组件的完整类型(NAME, RawProps, PropsSelector, DescriptorWrapper, EventEmitter, CommandReceiver)
|
|
1165
|
+
ts.ts ← 组件命名空间导出汇总
|
|
1166
|
+
turboModules/
|
|
1167
|
+
TurboModuleName.ts ← TurboModule 的类型定义
|
|
1168
|
+
ts.ts ← TurboModule 导出汇总
|
|
1169
|
+
index.ets ← 全量导出
|
|
1170
|
+
ts.ts ← RNC + TM 命名空间导出
|
|
1171
|
+
```
|
|
1172
|
+
|
|
1173
|
+
这些文件中的 DirectRawProps、PropsSelector、EventPayloadByName、CommandArgvByName 定义应与上游 RN 保持一致;若不一致,说明鸿蒙化方手动修改了 Codegen 产出,需重点关注差异。
|
|
1174
|
+
|
|
1175
|
+
若 `generated/components/ts.ts` 仅导出空对象(`export {}`),说明该库的组件未通过 Codegen generated 机制注册,需检查是否通过 Legacy/Descriptor 模式或其他方式注册。
|
|
1176
|
+
|
|
1177
|
+
### 6.4 Fragment 组件
|
|
1178
|
+
|
|
1179
|
+
部分组件(如 ReactFragment)不以 `@Component export struct` 形式实现,而是以普通 ArkTS class 实现。搜索 5e 时需同时搜索 `export class 组件名` 模式。
|
|
1180
|
+
|
|
1181
|
+
### 6.5 库含原生组件但 OHOS 未实现
|
|
1182
|
+
|
|
1183
|
+
若 5a 找到 `codegenNativeComponent` 或 `requireNativeComponent` 但 5c/5e 未找到对应 OHOS Package 注册和组件实现,说明原生组件未鸿蒙化。判定为"⛔ 原生组件缺失",每个缺失组件扣 15 分(致命)。
|
|
1184
|
+
|
|
1185
|
+
### 6.6 Package 基类选择
|
|
1186
|
+
|
|
1187
|
+
| 基类 | TurboModule Factory 方法 | 适用场景 | 典型库 |
|
|
1188
|
+
|------|--------------------------|---------|--------|
|
|
1189
|
+
| `RNOHPackage` | `createAnyThreadTurboModuleFactory()` → `AnyThreadTurboModuleFactory` | 较新的鸿蒙化实现 | react-native-webview |
|
|
1190
|
+
| `RNPackage` | `createTurboModulesFactory()` → `TurboModulesFactory` | 常见的鸿蒙化实现 | react-native-video, react-native-maps, react-native-svg, react-native-picker |
|
|
1191
|
+
|
|
1192
|
+
两者在组件注册方式上相同(都通过 `createDescriptorWrapperFactoryByDescriptorType`),仅在 TurboModule 注册 API 上有区别。检视时不因基类不同而扣分,但需正确识别以提取 TurboModule 名。
|
|
1193
|
+
|
|
1194
|
+
### 6.7 JS 层无组件注册宏的库
|
|
1195
|
+
|
|
1196
|
+
部分库(如 react-native-svg)在 JS 层不使用 `codegenNativeComponent` 或 `requireNativeComponent`,但 OHOS 层有大量 `@Component struct` 实现。此时判定流程需调整:
|
|
1197
|
+
|
|
1198
|
+
```
|
|
1199
|
+
1. JS 层无 codegenNativeComponent 或 requireNativeComponent
|
|
1200
|
+
2. 但 harmony/ 目录中存在 @Component struct 实现
|
|
1201
|
+
3. → 判定为 Legacy 架构,从 OHOS 层直接开始定位
|
|
1202
|
+
```
|
|
1203
|
+
|
|
1204
|
+
### 6.8 requireNativeComponent 的动态组件名
|
|
1205
|
+
|
|
1206
|
+
`requireNativeComponent` 的组件名可能是动态拼接的(如 react-native-maps 的 `AIRMap` vs `AIRGoogleMap`,根据 provider 属性决定)。检视时需追踪完整的命名逻辑,提取所有可能的组件名变体。
|
|
1207
|
+
|
|
1208
|
+
### 6.9 Harmony 目录位置不固定
|
|
1209
|
+
|
|
1210
|
+
| 库 | harmony 目录位置 | 模块子目录名 |
|
|
1211
|
+
|----|-----------------|-------------|
|
|
1212
|
+
| react-native-webview | `harmony/rn_webview/` | rn_webview |
|
|
1213
|
+
| react-native-video | `harmony/rn_video/` | rn_video |
|
|
1214
|
+
| react-native-maps | `harmony/maps/` | maps |
|
|
1215
|
+
| react-native-svg | `harmony/svg/` | svg |
|
|
1216
|
+
| react-native-picker | `harmony/picker/` | picker |
|
|
1217
|
+
| react-native-screens | `react-native-harmony-screens/harmony/screens/` | screens |
|
|
1218
|
+
| react-native-linear-gradient | `harmony/linear_gradient/`(待确认) | linear_gradient |
|
|
1219
|
+
|
|
1220
|
+
> ⚠️ 模块子目录名不可按库名硬推。必须通过实际目录探索确定。
|
|
1221
|
+
|
|
1222
|
+
### 6.10 TurboModule 充当 ViewManager 的特殊情况
|
|
1223
|
+
|
|
1224
|
+
某些库(如 react-native-picker)在 JS 层使用 `TurboModuleRegistry.get("RNCPickerView")` 注册,但在 OHOS 层的 Package 中将其实现为 TurboModule。如果该 TurboModule 负责创建/管理 UI 视图(而非仅提供方法调用),则应同时按 TurboModule 和原生组件两个维度检视。
|
|
1225
|
+
|
|
1226
|
+
---
|
|
1227
|
+
|
|
1228
|
+
## 7. C++ ↔ OHOS 特征提取与跨层验证方法
|
|
1229
|
+
|
|
1230
|
+
C++ Package 层是 RN 原生桥接的核心层——它将 JS 层的 Props/Commands/Events 定义序列化为 C++ 数据结构,再通过 NapiBinder 桥接到 ArkTS 组件。检视时必须验证 C++ ↔ ArkTS 层的特征一致性。
|
|
1231
|
+
|
|
1232
|
+
### 7.1 C++ ↔ ArkTS Props 映射验证
|
|
1233
|
+
|
|
1234
|
+
**验证链路**:`JS NativeProps → C++ JSIBinder Props → C++ NapiBinder Props → ArkTS DirectRawProps/手动 RawProps → ArkTS rawProps 读取`
|
|
1235
|
+
|
|
1236
|
+
```markdown
|
|
1237
|
+
| # | Prop 名 | JS NativeProps 类型 | C++ JSIBinder 默认值 | C++ NapiBinder 桥接 | OHOS DirectRawProps/RawProps | OHOS PropsSelector 默认值 | ArkTS rawProps 使用 | 状态 | 扣分 |
|
|
1238
|
+
|---|---------|---------------------|---------------------|---------------------|---------------------------|-------------------------|-------------------------|------|------|
|
|
1239
|
+
| 1 | `javaScriptEnabled` | `WithDefault<boolean, true>` | `true` (JSIBinder) | ✅ (NapiBinder) | `boolean?` + `?? true` | `?? true` | `this.descriptor.rawProps.javaScriptEnabled` | ✅ 全链路一致 | 0 |
|
|
1240
|
+
| 2 | `cacheMode` | `WithDefault<CacheModeEnum, 'DEFAULT'>` | `"LOAD_DEFAULT"` (JSIBinder) | ✅ (NapiBinder) | `'LOAD_DEFAULT'|...` + `?? 'LOAD_DEFAULT'` | `?? 'LOAD_DEFAULT'` | `this.descriptor.rawProps.cacheMode as CACHE_MODE` | ⚠️ 类型映射需验证 | -3 |
|
|
1241
|
+
| 3 | `injectedJavaScript` | `string?` | 无默认值 (JSIBinder) | ⛔ 未桥接 (NapiBinder) | `string?` (DirectRawProps) | — | ⛔ 未读取 | ❌ C++ 层已断桥 | -8 |
|
|
1242
|
+
```
|
|
1243
|
+
|
|
1244
|
+
**跨层断桥的识别方式**:
|
|
1245
|
+
|
|
1246
|
+
| 断桥位置 | 识别方式 | 说明 |
|
|
1247
|
+
|---------|----------|------|
|
|
1248
|
+
| JS → C++ 断桥 | C++ JSIBinder 中无该 Prop 的 `obj.setProperty` | Prop 未在 C++ 层注册,JS 侧传入的值会被丢弃 |
|
|
1249
|
+
| C++ → ArkTS 断桥 | C++ NapiBinder 中无该 Prop 的 `setProperty` | C++ 层有该值但未传递给 ArkTS 组件 |
|
|
1250
|
+
| ArkTS 未使用 | ArkTS 组件中无 `rawProps.xxx` 读取 | Prop 已传入但组件未使用 |
|
|
1251
|
+
|
|
1252
|
+
> ⚠️ **关键**:C++ JSIBinder 是 RN 新架构(Fabric)的核心 Props 序列化层。即使 ArkTS `DirectRawProps` 中定义了某个 Prop,如果 C++ JSIBinder 中未包含该 Prop,JS 侧传入的值将无法传递到组件。因此 JSIBinder 是 Props 完整性的最终判定标准。
|
|
1253
|
+
|
|
1254
|
+
### 7.2 C++ ↔ ArkTS Commands 映射验证
|
|
1255
|
+
|
|
1256
|
+
**验证链路**:`JS NativeCommands → C++ CommandDescriptor(如 Fabric CommandDescriptor)→ ArkTS CommandReceiver/CommandCallback`
|
|
1257
|
+
|
|
1258
|
+
```markdown
|
|
1259
|
+
| # | Command 名 | JS NativeCommands 签名 | C++ Command 处理 | ArkTS CommandReceiver/registerCommandCallback | OHOS 实现文件:行号 | 状态 | 扣分 |
|
|
1260
|
+
|---|-----------|----------------------|------------------|---------------------------------------------|----------------------|------|------|
|
|
1261
|
+
| 1 | `goBack` | `goBack(viewRef): void` | ✅ C++ CommandDescriptor | ✅ CommandReceiver.subscribe | `WebViewBaseOperate.ets:361` | ✅ 全链路一致 | 0 |
|
|
1262
|
+
| 2 | `clearFormData` | `clearFormData(viewRef): void` | ⛔ 无 C++ CommandDescriptor | ⛔ 无 CommandArgvByName | — | ❌ C++ 层未注册 | -8 |
|
|
1263
|
+
```
|
|
1264
|
+
|
|
1265
|
+
> ⚠️ **Codegen 架构的 Commands 在 C++ 中通过 `CommandArgvByName` 接口自动生成**;Legacy 架构的 Commands 通过 C++ TurboModule 方法暴露(如 `AIRMapManager.animateToRegion()`),不走 CommandDescriptor 路径。
|
|
1266
|
+
|
|
1267
|
+
### 7.3 C++ ↔ ArkTS Events 映射验证
|
|
1268
|
+
|
|
1269
|
+
**验证链路**:`JS onXxx Props → C++ EventEmitRequestHandler → ArkTS EventEmitter.emit / rnInstance.emitComponentEvent`
|
|
1270
|
+
|
|
1271
|
+
```markdown
|
|
1272
|
+
| # | 事件名 | JS onXxx Prop | C++ EventEmitRequestHandler | ArkTS 发送方式 | OHOS 文件:行号 | 状态 | 扣分 |
|
|
1273
|
+
|---|--------|-------------|----------------------------|---------------|---------------|------|------|
|
|
1274
|
+
| 1 | `onNavigationStateChange` | `onNavigationStateChange?: DirectEventHandler<...>` | ✅ handled in EventEmitRequestHandler | ✅ EventEmitter.emit | `RNCWebView.ets:156` | ✅ 全链路一致 | 0 |
|
|
1275
|
+
| 2 | `onMessage` | `onMessage?: DirectEventHandler<...>` | ⛔ 未在 handler 中注册 | ⛔ 未 emit | — | ❌ C++ 层未注册 | -5 |
|
|
1276
|
+
```
|
|
1277
|
+
|
|
1278
|
+
**C++ EventEmitRequestHandler 的两种模式**:
|
|
1279
|
+
|
|
1280
|
+
| 模式 | 代码特征 | 适用场景 |
|
|
1281
|
+
|------|----------|---------|
|
|
1282
|
+
| Codegen 自动生成 | `BaseReactNative*PackageEventEmitRequestHandler` 中自动列出所有事件 | Codegen 架构 |
|
|
1283
|
+
| Hand-Written | 手写 `handleEvent()` 方法中 if-else 分发 | Legacy 架构 |
|
|
1284
|
+
|
|
1285
|
+
### 7.4 C++ ↔ ArkTS TurboModule 映射验证
|
|
1286
|
+
|
|
1287
|
+
**验证链路**:`JS TurboModuleRegistry.get('XXX') → C++ TurboModuleFactoryDelegate → ArkTS TurboModule 实现`
|
|
1288
|
+
|
|
1289
|
+
```markdown
|
|
1290
|
+
| # | TurboModule 名 | JS Spec 定义 | C++ TurboModuleFactoryDelegate | ArkTS TurboModule 实现 | OHOS 文件:行号 | 状态 |
|
|
1291
|
+
|---|--------------|------------|----------------------------|---------------------|---------------|------|
|
|
1292
|
+
| 1 | `RNCWebViewModule` | ✅ NativeRNCWebViewModule.ts | ✅ BaseReactNativeWebViewPackageTurboModuleFactoryDelegate | ✅ WebViewTurboModule | `WebViewTurboModule.ets` | ✅ 一致 |
|
|
1293
|
+
| 2 | `AIRMapManager` | ✅ NativeModules.AIRMapManager | ✅ MapsTurboModuleFactoryDelegate | ✅ AIRMapManager | `AIRMaps/AIRMapManager.ts` | ✅ 一致 |
|
|
1294
|
+
```
|
|
1295
|
+
|
|
1296
|
+
### 7.5 C++ Package 模式判定快速指南
|
|
1297
|
+
|
|
1298
|
+
```
|
|
1299
|
+
1. 检查 harmony/<module>/src/main/cpp/ 目录是否存在
|
|
1300
|
+
→ 不存在 → ⚠️ 无 C++ 层(组件注册完全在 ArkTS 层)
|
|
1301
|
+
→ 存在 → 继续判定
|
|
1302
|
+
|
|
1303
|
+
2. 检查 *Package.h 文件内容
|
|
1304
|
+
→ 类继承 BaseReactNative*Package → Thin Wrapper 模式(Codegen)
|
|
1305
|
+
→ 所有注册信息在 generated/RNOH/generated/BaseReactNative*Package.h 中
|
|
1306
|
+
→ 需读取该 generated 文件提取组件名、JSIBinder 映射、事件名、TurboModule 名
|
|
1307
|
+
→ 类直接继承 Package → Hand-Written 模式(Legacy)
|
|
1308
|
+
→ 所有注册信息在 *Package.h/cpp 中直接定义
|
|
1309
|
+
→ 需逐方法读取提取
|
|
1310
|
+
|
|
1311
|
+
3. 检查 generated/RNOH/generated/ 目录
|
|
1312
|
+
→ 存在 → Codegen 架构确认
|
|
1313
|
+
→ 不存在 → Legacy 架构确认
|
|
1314
|
+
|
|
1315
|
+
4. 检查 *JSIBinder.h 文件
|
|
1316
|
+
→ 在 generated/components/ → 自动生成的 JSIBinder(Codegen)
|
|
1317
|
+
→ 在 cpp/ 根目录或子目录 → 手写的 JSIBinder(Legacy)
|
|
1318
|
+
|
|
1319
|
+
5. 检查 ComponentInstanceFactoryDelegate
|
|
1320
|
+
→ 存在 → 该库有 C++ 原生视图实例创建(如 react-native-svg)
|
|
1321
|
+
→ 不存在 → 该库的视图完全由 ArkTS 渲染
|
|
1322
|
+
```
|
|
1323
|
+
|
|
1324
|
+
### 7.6 C++ 层特征提取操作指令
|
|
1325
|
+
|
|
1326
|
+
**提取 JSIBinder Props 的操作流程**:
|
|
1327
|
+
|
|
1328
|
+
```
|
|
1329
|
+
1. 定位 JSIBinder 文件:
|
|
1330
|
+
- Codegen: harmony/<module>/src/main/cpp/generated/RNOH/generated/components/ComponentNameJSIBinder.h
|
|
1331
|
+
- Legacy: harmony/<module>/src/main/cpp/*JSIBinder.h
|
|
1332
|
+
|
|
1333
|
+
2. 在 JSIBinder 文件中搜索 createJSIBinder 方法
|
|
1334
|
+
3. 提取所有 obj.setProperty(rt, "propName", createValue(rt, propName_)) 行
|
|
1335
|
+
4. 提取所有 propName_ 成员变量的默认值
|
|
1336
|
+
5. 对比 propName 列表与 JS NativeProps 接口中的 Prop 名列表
|
|
1337
|
+
6. 对比 propName 列表与 OHOS DirectRawProps/RawProps 接口中的 Prop 名列表
|
|
1338
|
+
7. 标注任何 JS 中存在但 C++ JSIBinder 中缺失的 Prop(→ JS→C++ 断桥)
|
|
1339
|
+
8. 标注任何 C++ JSIBinder 中存在但 OHOS RawProps 中缺失的 Prop(→ C++→ArkTS 断桥)
|
|
1340
|
+
```
|
|
1341
|
+
|
|
1342
|
+
**提取 TurboModule 名的操作流程**:
|
|
1343
|
+
|
|
1344
|
+
```
|
|
1345
|
+
1. 定位 TurboModuleFactoryDelegate 文件:
|
|
1346
|
+
- Codegen: harmony/<module>/src/main/cpp/generated/RNOH/generated/BaseReactNative*Package.h
|
|
1347
|
+
- Legacy: harmony/<module>/src/main/cpp/*Package.h 或 *TurboModuleFactoryDelegate.h
|
|
1348
|
+
|
|
1349
|
+
2. 在 TurboModuleFactoryDelegate 的 createTurboModule 方法中提取所有 turboModuleName 条件
|
|
1350
|
+
3. 对比提取的 TurboModule 名与 JS 层 TurboModuleRegistry/NativeModules 注册名
|
|
1351
|
+
4. 对比提取的 TurboModule 名与 ArkTS TurboModule 实现类名
|
|
1352
|
+
```
|
|
1353
|
+
|
|
1354
|
+
**提取 EventEmitRequestHandler 事件名的操作流程**:
|
|
1355
|
+
|
|
1356
|
+
```
|
|
1357
|
+
1. 定位 EventEmitRequestHandler 文件:
|
|
1358
|
+
- Codegen: harmony/<module>/src/main/cpp/generated/RNOH/generated/BaseReactNative*Package.h
|
|
1359
|
+
- Legacy: 在 *Package.h/cpp 中搜索 EventEmitRequestHandler
|
|
1360
|
+
|
|
1361
|
+
2. 在 handleEvent 方法中提取所有 eventName 条件
|
|
1362
|
+
3. 对比提取的事件名与 JS 层 onXxx Props 列表
|
|
1363
|
+
4. 对比提取的事件名与 OHOS EventEmitter/emitComponentEvent 发送的事件名
|
|
1364
|
+
```
|
|
1365
|
+
|
|
1366
|
+
**提取 ComponentInstanceFactoryDelegate 组件名的操作流程**:
|
|
1367
|
+
|
|
1368
|
+
```
|
|
1369
|
+
1. 在 *Package.h 中搜索 ComponentInstanceFactoryDelegate
|
|
1370
|
+
2. 在 createComponentInstance 方法中提取所有 ctx.componentName 条件
|
|
1371
|
+
3. 这些组件名即为需要 C++ 原生视图实例的组件
|
|
1372
|
+
4. 对比这些组件名与 ArkTS @Component struct 组件名列表
|
|
1373
|
+
```
|