android2harmony 0.1.5 → 0.1.6

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.
@@ -42,7 +42,20 @@ node ./scripts/a2h_resource_convert.js \
42
42
  --ui-module <ui_module> \
43
43
  --records <work_dir>/records.json
44
44
 
45
- # 2. Code-defined vector icons REQUIRED for any Jetpack Compose app (see Step 4.1.3)
45
+ # 2. App identity: launcher icon + app name AppScope/app.json5 + abilities[0]
46
+ # Step 1 converts the icon *assets* and the app-name string, but writes them into
47
+ # <ui_module>/…/resources — while the desktop icon and app name are decided by
48
+ # AppScope/app.json5, whose $media:/$string: domain is AppScope/resources. Nothing
49
+ # else reads AndroidManifest's android:icon / android:label either, so without this
50
+ # step the DevEco template defaults survive: default icon and the name "label".
51
+ # Runs after step 1 because it reuses the layered-image JSON that step produces.
52
+ node ./scripts/app_identity.js \
53
+ --manifest <decoded_output_path>/AndroidManifest.xml \
54
+ --res <decoded_output_path>/res \
55
+ --harmony <harmony_project_dir> --ui-module <ui_module> \
56
+ --json <work_dir>/app_identity.json
57
+
58
+ # 3. Code-defined vector icons — REQUIRED for any Jetpack Compose app (see Step 4.1.3)
46
59
  # --fetch pulls artwork from a pinned upstream commit, never a moving branch.
47
60
  # Requires network access to raw.githubusercontent.com.
48
61
  # Prefer a *minified* (release) APK's decoded dir. On a debug APK the icon library
@@ -54,23 +67,24 @@ node ./scripts/code_vector_icons.js \
54
67
  --out <harmony_project_dir>/<ui_module>/src/main/resources/base/media \
55
68
  --fetch --json <work_dir>/icons.json
56
69
 
57
- # 3. Vector fidelity gate — any error blocks completion
70
+ # 4. Vector fidelity gate — any error blocks completion
58
71
  node ./scripts/svg_fidelity_check.js \
59
72
  --android-res <decoded_output_path>/res \
60
73
  --harmony-media <harmony_project_dir>/<ui_module>/src/main/resources/base/media \
61
74
  --json <work_dir>/fidelity.json
62
75
 
63
- # 4. Documents, rebuilt from the records of step 1 plus the results of steps 2-3
76
+ # 5. Documents, rebuilt from the records of step 1 plus the results of steps 3-4
64
77
  node ./scripts/a2h_resource_convert.js --docs-only \
65
78
  --records <work_dir>/records.json \
66
79
  --icons-json <work_dir>/icons.json --fidelity-json <work_dir>/fidelity.json \
80
+ --app-identity-json <work_dir>/app_identity.json \
67
81
  --report <work_dir>/resource_conversion_report.md \
68
82
  --mapping <resource_mapping_path> \
69
83
  --apk <apk_path> --android-commit <commit> --app-module <app_module> \
70
84
  --harmony <harmony_project_dir>
71
85
  ```
72
86
 
73
- Step 4 is separate because the documents need the fidelity and icon results, which in turn need the artifacts step 1 produces. It re-reads `records.json` rather than re-running the conversion.
87
+ Step 5 is separate because the documents need the fidelity and icon results, which in turn need the artifacts step 1 produces. It re-reads `records.json` rather than re-running the conversion.
74
88
 
75
89
  **What remains your job:**
76
90
 
@@ -606,7 +620,7 @@ After resolution, scan all converted resources for any remaining unresolved refe
606
620
 
607
621
  ### Step 6: Verify Completeness
608
622
 
609
- Items 1-9 and 11 below are performed by `scripts/a2h_resource_convert.js` and reported in `records.json`; items 10 and 12 are the two separate gates (`svg_fidelity_check.js` and `code_vector_icons.js`). Your job is to confirm each one actually ran and to act on what it found — a gate whose output nobody read is not a gate.
623
+ Items 1-9 and 11 below are performed by `scripts/a2h_resource_convert.js` and reported in `records.json`; items 10, 12 and 13 are the three separate gates (`svg_fidelity_check.js`, `code_vector_icons.js` and `app_identity.js`). Your job is to confirm each one actually ran and to act on what it found — a gate whose output nobody read is not a gate.
610
624
 
611
625
  The checks are:
612
626
 
@@ -644,6 +658,15 @@ The checks are:
644
658
  c. The pinned snapshot ref used for artwork is recorded in the report and in the mapping document metadata. A run whose artwork came from a moving branch is not reproducible and must be re-run against a pinned ref.
645
659
 
646
660
  Unlike item 10, a failure here does not block completion — an unresolved icon is a recorded gap, not a corrupt asset. But an *unrecorded* icon does block: it reproduces exactly the defect this step exists to catch.
661
+ 13. **App identity (launcher icon + app name), blocking**: items 1-12 all reason about the `<ui_module>` resource tree. The desktop icon and app name live somewhere else — `AppScope/app.json5`, whose `$media:`/`$string:` domain is `AppScope/resources` — and no other item touches them. Run Toolchain step 2's gate:
662
+
663
+ ```
664
+ node ./scripts/app_identity.js --check --json <work_dir>/app_identity.json
665
+ ```
666
+
667
+ It re-reads both `json5` files and requires that `AppScope/app.json5`'s `icon`/`label` and `abilities[0]`'s `icon`/`label`/`startWindowIcon` still hold the values resolved from `AndroidManifest.xml`, and that each reference resolves to a file that exists in the *right* resource root. **`GATE: FAIL` blocks completion** — this is a user-visible wrong product (default icon, app named "label"), not a recorded gap.
668
+
669
+ It compares against the recorded values rather than against "not equal to the template default" on purpose: template defaults change between DevEco versions, so a default-value check misses. Note this is the one item existing checks structurally cannot catch — the template's `$media:layered_image` points at a template-supplied file that really exists, so every existence and reference check upstream passes while the icon is still wrong.
647
670
 
648
671
  **Placeholder SVG template** (for missing media resources):
649
672
  ```svg
@@ -656,7 +679,7 @@ Replace `RESOURCE_NAME` with the actual resource name (truncated if too long).
656
679
 
657
680
  ### Step 7: Generate Report
658
681
 
659
- The report is written by Toolchain step 4 (`--docs-only --report`). It is deliberately **aggregated** so a human can read it end to end: counts by type, qualifier mappings, the full reference-resolution table, unmappable reasons grouped by cause, fidelity findings, code-defined icons, and warnings grouped by kind with a per-kind sample. The exhaustive per-resource listing belongs in the mapping document (Step 8), not here.
682
+ The report is written by Toolchain step 5 (`--docs-only --report`). It is deliberately **aggregated** so a human can read it end to end: counts by type, qualifier mappings, the full reference-resolution table, unmappable reasons grouped by cause, fidelity findings, code-defined icons, and warnings grouped by kind with a per-kind sample. The exhaustive per-resource listing belongs in the mapping document (Step 8), not here.
660
683
 
661
684
  Your job is to read it and act on what it says — an unresolved reference, a fidelity error, or a target collision is a finding, not a formatting detail.
662
685
 
@@ -704,6 +727,12 @@ Libraries declared in the project's build.gradle that may provide resources:
704
727
  - Code-defined icon media files written: <count>
705
728
  - Code-defined icons screen-attributed / Unknown: <count> / <count>
706
729
  - Material Icons snapshot ref: <pinned commit or vendored snapshot path>
730
+ - App icon: <AndroidManifest android:icon> → <AppScope/app.json5 icon value> | "未改写(原因)"
731
+ - App name: <AndroidManifest android:label> → <app.json5 label value> = "<resolved text>" | "未改写(原因)"
732
+ - App name locales written to AppScope: <qualifier dirs, e.g. base, zh_CN>
733
+ - App identity gate: <PASS | FAIL(n 项)>
734
+
735
+ Take these five lines from `app_identity.json` (Toolchain step 2). `a2h-ui-transfer` greps them as its App-identity gate, so keep the labels verbatim.
707
736
 
708
737
  ## Conversion Details
709
738
 
@@ -836,7 +865,7 @@ Media resources referenced in `.ets` UI code but not found in converted resource
836
865
 
837
866
  ### Step 8: Generate Resource Mapping Document
838
867
 
839
- The second document, at `resource_mapping_path`, is written by the same Toolchain step 4 invocation (`--mapping`). It is the audit surface: **every** observed Android resource appears as its own row, `values` at entry granularity. It does not sample, summarise, or aggregate — those are the report's job. Expect it to be large (measured range: 4 MB to 22 MB); that size is the cost of the no-omission requirement, and the dataset tracks these files with Git LFS for exactly that reason.
868
+ The second document, at `resource_mapping_path`, is written by the same Toolchain step 5 invocation (`--mapping`). It is the audit surface: **every** observed Android resource appears as its own row, `values` at entry granularity. It does not sample, summarise, or aggregate — those are the report's job. Expect it to be large (measured range: 4 MB to 22 MB); that size is the cost of the no-omission requirement, and the dataset tracks these files with Git LFS for exactly that reason.
840
869
 
841
870
  Do not hand-write or hand-trim this document. If it looks too large, that is not a reason to sample it.
842
871
 
@@ -1832,6 +1832,25 @@ class DocWriter {
1832
1832
  } else {
1833
1833
  p('- Code-defined vector icons: not analysed (run scripts/code_vector_icons.js)');
1834
1834
  }
1835
+ // 应用图标 / 应用名。这几行 a2h-ui-transfer 会 grep 作为 App-identity gate,
1836
+ // 标签文字不要改。
1837
+ const idn = this.ctx.appIdentity;
1838
+ if (idn) {
1839
+ const r = idn.resolved ?? {};
1840
+ // 原因要按字段挑,不能一律取 warnings[0]:图标的告警贴到应用名那行上,
1841
+ // 读者会照着错的原因去排查。
1842
+ const why = (re) => {
1843
+ const hit = (idn.warnings ?? []).find((w) => re.test(w));
1844
+ return hit ? `未改写(${hit})` : '未改写';
1845
+ };
1846
+ p(`- App icon: ${idn.android?.icon || '(none)'} → ${r.appIcon ?? why(/图标/)}`);
1847
+ p(`- App name: ${idn.android?.label || '(none)'} → ${r.appLabel ?? why(/应用名|label/)}`
1848
+ + (r.labelValue != null ? ` = "${r.labelValue}"` : ''));
1849
+ p(`- App name locales written to AppScope: ${(r.labelQualifiers ?? []).join(', ') || '(none)'}`);
1850
+ p(`- App identity gate: ${r.appIcon && r.appLabel ? 'PASS' : 'FAIL(应用图标或应用名未落地)'}`);
1851
+ } else {
1852
+ p('- App identity (launcher icon + app name): not run (run scripts/app_identity.js)');
1853
+ }
1835
1854
  p();
1836
1855
 
1837
1856
  p('## Conversion Details');
@@ -2154,6 +2173,7 @@ function emitDocs(
2154
2173
  buildResult: typeof args['build-result'] === 'string' ? args['build-result'] : '(not run by this script)',
2155
2174
  icons: readJson('icons-json'),
2156
2175
  fidelity: readJson('fidelity-json'),
2176
+ appIdentity: readJson('app-identity-json'),
2157
2177
  });
2158
2178
  if (typeof args.report === 'string') fs.writeFileSync(args.report, `${doc.report()}
2159
2179
  `, 'utf8');