android2harmony 0.1.4 → 0.1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (104) hide show
  1. package/README.md +1 -407
  2. package/agents/self-tester.md +376 -376
  3. package/dist/index.js +134 -116
  4. package/dist/index.js.map +3 -3
  5. package/package.json +36 -32
  6. package/skills/a2h-resource-convert/SKILL.md +902 -0
  7. package/skills/a2h-resource-convert/references/code-vector-icon-rules.md +335 -0
  8. package/skills/{hmos-resources-convert → a2h-resource-convert}/references/conversion-rules.md +15 -2
  9. package/skills/{hmos-resources-convert → a2h-resource-convert}/references/dependency-analysis-rules.md +24 -2
  10. package/skills/a2h-resource-convert/references/lottie-conversion-rules.md +219 -0
  11. package/skills/{hmos-resources-convert → a2h-resource-convert}/references/resource-mapping-rules.md +27 -2
  12. package/skills/{hmos-resources-convert → a2h-resource-convert}/references/xml-drawable-to-svg-rules.md +118 -1
  13. package/skills/a2h-resource-convert/scripts/a2h_resource_convert.js +2166 -0
  14. package/skills/a2h-resource-convert/scripts/code_vector_icons.js +607 -0
  15. package/skills/a2h-resource-convert/scripts/package.json +3 -0
  16. package/skills/a2h-resource-convert/scripts/svg_fidelity_check.js +632 -0
  17. package/skills/a2h-ui-transfer/SKILL.md +420 -0
  18. package/skills/a2h-ui-transfer/references/conversion-procedure.md +572 -0
  19. package/skills/{hmos-batch-ui-align → a2h-ui-transfer}/references/mvvm-v2/_/350/214/203/345/274/217/351/200/211/346/213/251/350/257/264/346/230/216.md +1 -1
  20. package/skills/a2h-ui-transfer/references/mvvm-v2/_/350/243/205/351/245/260/345/231/250/351/200/237/346/237/245.md +133 -0
  21. package/skills/{hmos-batch-ui-align/scripts/android_parse_fast.ts → a2h-ui-transfer/scripts/android_parse_fast.js} +397 -283
  22. package/skills/a2h-ui-transfer/scripts/arkts_static_check.js +1624 -0
  23. package/skills/a2h-ui-transfer/scripts/measure_pack.js +1005 -0
  24. package/skills/a2h-ui-transfer/scripts/package.json +3 -0
  25. package/skills/hmos-incremental-ui-align/README.md +251 -251
  26. package/skills/hmos-incremental-ui-align/SKILL.md +364 -364
  27. package/skills/hmos-incremental-ui-align/references/State_Model_Template.md +2 -2
  28. package/skills/hmos-incremental-ui-align/scripts/app_feature_verify.js +790 -0
  29. package/skills/hmos-incremental-ui-align/scripts/extract_checklist.js +285 -0
  30. package/skills/hmos-incremental-ui-align/scripts/navigation-capure.md +76 -76
  31. package/skills/hmos-incremental-ui-align/scripts/page_capture.js +756 -0
  32. package/skills/hmos-incremental-ui-align/scripts/page_capture_burst.js +155 -0
  33. package/skills/hmos-batch-ui-align/SKILL.md +0 -141
  34. package/skills/hmos-batch-ui-align/references/conversion-procedure.md +0 -217
  35. package/skills/hmos-incremental-ui-align/scripts/app_feature_verify.ts +0 -999
  36. package/skills/hmos-incremental-ui-align/scripts/extract_checklist.ts +0 -343
  37. package/skills/hmos-incremental-ui-align/scripts/page_capture.ts +0 -977
  38. package/skills/hmos-incremental-ui-align/scripts/page_capture_burst.ts +0 -188
  39. package/skills/hmos-resources-convert/SKILL.md +0 -654
  40. package/skills/hmos-resources-convert/template/AppScope/app.json5 +0 -10
  41. package/skills/hmos-resources-convert/template/AppScope/resources/base/element/string.json +0 -8
  42. package/skills/hmos-resources-convert/template/AppScope/resources/base/media/background.png +0 -0
  43. package/skills/hmos-resources-convert/template/AppScope/resources/base/media/foreground.png +0 -0
  44. package/skills/hmos-resources-convert/template/AppScope/resources/base/media/layered_image.json +0 -7
  45. package/skills/hmos-resources-convert/template/build-profile.json5 +0 -42
  46. package/skills/hmos-resources-convert/template/code-linter.json5 +0 -32
  47. package/skills/hmos-resources-convert/template/entry/build-profile.json5 +0 -33
  48. package/skills/hmos-resources-convert/template/entry/hvigorfile.ts +0 -6
  49. package/skills/hmos-resources-convert/template/entry/obfuscation-rules.txt +0 -23
  50. package/skills/hmos-resources-convert/template/entry/oh-package.json5 +0 -10
  51. package/skills/hmos-resources-convert/template/entry/src/main/ets/entryability/EntryAbility.ets +0 -48
  52. package/skills/hmos-resources-convert/template/entry/src/main/ets/entrybackupability/EntryBackupAbility.ets +0 -16
  53. package/skills/hmos-resources-convert/template/entry/src/main/ets/pages/Index.ets +0 -23
  54. package/skills/hmos-resources-convert/template/entry/src/main/module.json5 +0 -55
  55. package/skills/hmos-resources-convert/template/entry/src/main/resources/base/element/color.json +0 -8
  56. package/skills/hmos-resources-convert/template/entry/src/main/resources/base/element/float.json +0 -8
  57. package/skills/hmos-resources-convert/template/entry/src/main/resources/base/element/string.json +0 -16
  58. package/skills/hmos-resources-convert/template/entry/src/main/resources/base/media/background.png +0 -0
  59. package/skills/hmos-resources-convert/template/entry/src/main/resources/base/media/foreground.png +0 -0
  60. package/skills/hmos-resources-convert/template/entry/src/main/resources/base/media/layered_image.json +0 -7
  61. package/skills/hmos-resources-convert/template/entry/src/main/resources/base/media/startIcon.png +0 -0
  62. package/skills/hmos-resources-convert/template/entry/src/main/resources/base/profile/backup_config.json +0 -3
  63. package/skills/hmos-resources-convert/template/entry/src/main/resources/base/profile/main_pages.json +0 -5
  64. package/skills/hmos-resources-convert/template/entry/src/main/resources/dark/element/color.json +0 -8
  65. package/skills/hmos-resources-convert/template/entry/src/mock/mock-config.json5 +0 -2
  66. package/skills/hmos-resources-convert/template/entry/src/ohosTest/ets/test/Ability.test.ets +0 -35
  67. package/skills/hmos-resources-convert/template/entry/src/ohosTest/ets/test/List.test.ets +0 -5
  68. package/skills/hmos-resources-convert/template/entry/src/ohosTest/module.json5 +0 -16
  69. package/skills/hmos-resources-convert/template/entry/src/test/List.test.ets +0 -5
  70. package/skills/hmos-resources-convert/template/entry/src/test/LocalUnit.test.ets +0 -33
  71. package/skills/hmos-resources-convert/template/hvigor/hvigor-config.json5 +0 -23
  72. package/skills/hmos-resources-convert/template/hvigorfile.ts +0 -6
  73. package/skills/hmos-resources-convert/template/oh-package-lock.json5 +0 -28
  74. package/skills/hmos-resources-convert/template/oh-package.json5 +0 -10
  75. /package/skills/{hmos-batch-ui-align → a2h-ui-transfer}/references/mappings/android-to-harmonyOS-ui-atomic-component-mapping-reference.md +0 -0
  76. /package/skills/{hmos-batch-ui-align → a2h-ui-transfer}/references/mappings/android-to-harmonyOS-ui-interaction-mapping-reference.md +0 -0
  77. /package/skills/{hmos-batch-ui-align → a2h-ui-transfer}/references/mappings/android-to-harmonyOS-ui-layout-mapping-reference.md +0 -0
  78. /package/skills/{hmos-batch-ui-align → a2h-ui-transfer}/references/mvvm/@Link/350/243/205/351/245/260/345/231/250/357/274/232/347/210/266/345/255/220/345/217/214/345/220/221/345/220/214/346/255/245.md" +0 -0
  79. /package/skills/{hmos-batch-ui-align → a2h-ui-transfer}/references/mvvm/@Observed/350/243/205/351/245/260/345/231/250/345/222/214@ObjectLink/350/243/205/351/245/260/345/231/250/357/274/232/345/265/214/345/245/227/347/261/273/345/257/271/350/261/241/345/261/236/346/200/247/345/217/230/345/214/226.md" +0 -0
  80. /package/skills/{hmos-batch-ui-align → a2h-ui-transfer}/references/mvvm/@Prop/350/243/205/351/245/260/345/231/250/357/274/232/347/210/266/345/255/220/345/215/225/345/220/221/345/220/214/346/255/245.md" +0 -0
  81. /package/skills/{hmos-batch-ui-align → a2h-ui-transfer}/references/mvvm/@Provide/350/243/205/351/245/260/345/231/250/345/222/214@Consume/350/243/205/351/245/260/345/231/250/357/274/232/344/270/216/345/220/216/344/273/243/347/273/204/344/273/266/345/217/214/345/220/221/345/220/214/346/255/245.md" +0 -0
  82. /package/skills/{hmos-batch-ui-align → a2h-ui-transfer}/references/mvvm/@State/350/243/205/351/245/260/345/231/250/357/274/232/347/273/204/344/273/266/345/206/205/347/212/266/346/200/201.md" +0 -0
  83. /package/skills/{hmos-batch-ui-align → a2h-ui-transfer}/references/mvvm/@Track/350/243/205/351/245/260/345/231/250/357/274/232class/345/257/271/350/261/241/345/261/236/346/200/247/347/272/247/346/233/264/346/226/260.md" +0 -0
  84. /package/skills/{hmos-batch-ui-align → a2h-ui-transfer}/references/mvvm/@Watch/350/243/205/351/245/260/345/231/250/357/274/232/347/212/266/346/200/201/345/217/230/351/207/217/346/233/264/346/224/271/351/200/232/347/237/245.md" +0 -0
  85. /package/skills/{hmos-batch-ui-align → a2h-ui-transfer}/references/mvvm/AppStorage/357/274/232/345/272/224/347/224/250/345/205/250/345/261/200/347/232/204UI/347/212/266/346/200/201/345/255/230/345/202/250.md" +0 -0
  86. /package/skills/{hmos-batch-ui-align → a2h-ui-transfer}/references/mvvm/Environment/357/274/232/350/256/276/345/244/207/347/216/257/345/242/203/346/237/245/350/257/242.md" +0 -0
  87. /package/skills/{hmos-batch-ui-align → a2h-ui-transfer}/references/mvvm/LocalStorage/357/274/232/351/241/265/351/235/242/347/272/247UI/347/212/266/346/200/201/345/255/230/345/202/250.md" +0 -0
  88. /package/skills/{hmos-batch-ui-align → a2h-ui-transfer}/references/mvvm/MVVM/346/250/241/345/274/217/357/274/210V1/357/274/211.md" +0 -0
  89. /package/skills/{hmos-batch-ui-align → a2h-ui-transfer}/references/mvvm/PersistentStorage/357/274/232/346/214/201/344/271/205/345/214/226/345/255/230/345/202/250UI/347/212/266/346/200/201.md" +0 -0
  90. /package/skills/{hmos-batch-ui-align → a2h-ui-transfer}/references/mvvm//347/256/241/347/220/206/345/272/224/347/224/250/346/213/245/346/234/211/347/232/204/347/212/266/346/200/201/346/246/202/350/277/260.md" +0 -0
  91. /package/skills/{hmos-batch-ui-align → a2h-ui-transfer}/references/mvvm-v2/!!/350/257/255/346/263/225/357/274/232/345/217/214/345/220/221/347/273/221/345/256/232.md" +0 -0
  92. /package/skills/{hmos-batch-ui-align → a2h-ui-transfer}/references/mvvm-v2/@Computed/350/243/205/351/245/260/345/231/250/357/274/232/350/256/241/347/256/227/345/261/236/346/200/247.md" +0 -0
  93. /package/skills/{hmos-batch-ui-align → a2h-ui-transfer}/references/mvvm-v2/@Event/350/243/205/351/245/260/345/231/250/357/274/232/350/247/204/350/214/203/347/273/204/344/273/266/350/276/223/345/207/272.md" +0 -0
  94. /package/skills/{hmos-batch-ui-align → a2h-ui-transfer}/references/mvvm-v2/@Local/350/243/205/351/245/260/345/231/250/357/274/232/347/273/204/344/273/266/345/206/205/351/203/250/347/212/266/346/200/201.md" +0 -0
  95. /package/skills/{hmos-batch-ui-align → a2h-ui-transfer}/references/mvvm-v2/@Monitor/350/243/205/351/245/260/345/231/250/357/274/232/347/212/266/346/200/201/345/217/230/351/207/217/344/277/256/346/224/271/345/274/202/346/255/245/347/233/221/345/220/254.md" +0 -0
  96. /package/skills/{hmos-batch-ui-align → a2h-ui-transfer}/references/mvvm-v2/@ObservedV2/350/243/205/351/245/260/345/231/250/345/222/214@Trace/350/243/205/351/245/260/345/231/250/357/274/232/347/261/273/345/261/236/346/200/247/345/217/230/345/214/226/350/247/202/346/265/213.md" +0 -0
  97. /package/skills/{hmos-batch-ui-align → a2h-ui-transfer}/references/mvvm-v2/@Once/350/243/205/351/245/260/345/231/250/357/274/232/345/210/235/345/247/213/345/214/226/345/220/214/346/255/245/344/270/200/346/254/241.md" +0 -0
  98. /package/skills/{hmos-batch-ui-align → a2h-ui-transfer}/references/mvvm-v2/@Param/350/243/205/351/245/260/345/231/250/357/274/232/347/273/204/344/273/266/345/244/226/351/203/250/350/276/223/345/205/245.md" +0 -0
  99. /package/skills/{hmos-batch-ui-align → a2h-ui-transfer}/references/mvvm-v2/@Provider/350/243/205/351/245/260/345/231/250/345/222/214@Consumer/350/243/205/351/245/260/345/231/250/357/274/232/350/267/250/347/273/204/344/273/266/345/261/202/347/272/247/345/217/214/345/220/221/345/220/214/346/255/245.md" +0 -0
  100. /package/skills/{hmos-batch-ui-align → a2h-ui-transfer}/references/mvvm-v2/@Type/350/243/205/351/245/260/345/231/250/357/274/232/346/240/207/350/256/260/347/261/273/345/261/236/346/200/247/347/232/204/347/261/273/345/236/213.md" +0 -0
  101. /package/skills/{hmos-batch-ui-align → a2h-ui-transfer}/references/mvvm-v2/AppStorageV2/357/274/232/345/272/224/347/224/250/345/205/250/345/261/200UI/347/212/266/346/200/201/345/255/230/345/202/250.md" +0 -0
  102. /package/skills/{hmos-batch-ui-align → a2h-ui-transfer}/references/mvvm-v2/MVVM/346/250/241/345/274/217/357/274/210V2/357/274/211.md" +0 -0
  103. /package/skills/{hmos-batch-ui-align → a2h-ui-transfer}/references/mvvm-v2/PersistenceV2/357/274/232/346/214/201/344/271/205/345/214/226/345/255/230/345/202/250UI/347/212/266/346/200/201.md" +0 -0
  104. /package/skills/{hmos-batch-ui-align → a2h-ui-transfer}/references/mvvm-v2//347/212/266/346/200/201/347/256/241/347/220/206V1/345/220/221V2/350/277/201/347/247/273/344/270/216/346/267/267/347/224/250/346/214/207/345/257/274.md" +0 -0
@@ -1,654 +0,0 @@
1
- ---
2
- name: hmos-resources-convert
3
- description: Convert Android project resources to HarmonyOS project resources. Use this skill when the user wants to migrate, convert, or transfer resource files (strings, colors, dimensions, images, drawables, icons, etc.) from an Android project to a HarmonyOS project. Also trigger when the user mentions Android-to-HarmonyOS migration involving resource files, qualifier directories (like drawable-hdpi, values-zh), or resource format conversion (XML to JSON). Even partial mentions of "Android resources to HarmonyOS" or "migrate Android res" should trigger this skill.
4
- ---
5
-
6
- # Android to HarmonyOS Resource Converter
7
-
8
- This skill converts resource files from an Android project into the resource format used by HarmonyOS projects. It attempts to build the Android APK and decode it with the `a2h-resource` npm package (a pure-Node.js resource decoder) to get the complete merged resource set (including all library dependencies). If the build fails or no APK is available, it falls back to converting directly from the project's source `res/` directory — which may be missing library-provided resources, but still produces a useful conversion with clear reporting of what's missing and why. In addition to the standard conversion report, it also produces a dedicated Android resources ↔ HarmonyOS resources mapping markdown document at the user-provided `resource_mapping_path`.
9
-
10
- ## Inputs
11
-
12
- Declare all inputs up front as explicit `snake_case` variables — do not rely on semantically guessing natural-language phrases:
13
-
14
- | Variable | Required | Meaning | Typical Phrases |
15
- |---|---|---|---|
16
- | `android_project_dir` | yes | Root directory of the Android project (contains `build.gradle` or `build.gradle.kts`) | "Android project path", "安卓项目", "source project" |
17
- | `harmony_project_dir` | yes | HarmonyOS project output path — where the new HarmonyOS project will be created, or an existing HarmonyOS project to convert into | "HarmonyOS project output path", "鸿蒙项目", "output project" |
18
- | `resource_mapping_path` | yes | Full output path of the markdown file that records the Android resource inventory and the Android ↔ HarmonyOS mapping details. Write this file in 中文. | "resource mapping path", "资源映射文档" |
19
- | `apk_path` | no | Full path of the APK corresponding to `android_project_dir`. When provided, skip the Gradle build and start the workflow from Step 3 (decode this APK directly). | "APK path", "apk文件", "安卓apk" |
20
-
21
- If any required input cannot be determined from the invocation, ask the user — do not guess.
22
-
23
- ## Workflow
24
-
25
- ### Step 1: Initialize HarmonyOS Project
26
-
27
- **Skip condition**: Before copying, check if `harmony_project_dir` already exists and is non-empty (i.e., it contains files or directories such as `AppScope/`, `entry/`, `build-profile.json5`, etc.). If it does, this is an existing HarmonyOS project — skip template initialization entirely and proceed directly to Step 2. Only copy the template when `harmony_project_dir` doesn't exist or is empty.
28
-
29
- When initialization is needed, copy the bundled HarmonyOS project template to `harmony_project_dir`:
30
-
31
- ```
32
- Template source: <skill_dir>/template/
33
- ```
34
-
35
- - Copy the entire template directory to the target path
36
- - Preserve the template's directory structure (AppScope, entry, hvigor, etc.)
37
- - The main resource target directory is: `<harmony_project_dir>/entry/src/main/resources/`
38
-
39
- ### Step 2: Attempt to Build the Android APK
40
-
41
- Try to build the Android project to produce an APK containing all merged resources (source + library dependencies + generated resources). The decoded APK is the ideal source because it contains everything — but building is not always possible.
42
-
43
- 1. Ask the user which Gradle build variant to use (e.g., `assembleDebug`, `assembleRelease`, `assembleFossDebug`). Default to `assembleDebug` if the user has no preference — debug builds include all resources without optimization.
44
-
45
- 2. Run the build:
46
- ```bash
47
- cd <android_project_dir>
48
- ./gradlew <variant>
49
- ```
50
-
51
- 3. **If the build succeeds**: locate the APK in `<android_project_dir>/app/build/outputs/apk/`. If multiple APKs exist, prefer the debug variant. Record `build_status = "success"` and proceed to Step 3 (decode).
52
-
53
- 4. **If the build fails**: record the build error output and `build_status = "failed"`. Also check if a previously-built APK already exists at `<android_project_dir>/app/build/outputs/apk/`. If an existing APK is found, use it and record `build_status = "failed_using_cached_apk"`. If no APK exists at all, skip Step 3 entirely and proceed to Step 4 using the source `res/` directory. Set `resource_source = "source_res"`.
54
-
55
- The reason we prefer the decoded APK: it contains all merged resources from source code AND library dependencies (AARs, Maven artifacts). When falling back to source `res/`, library resources are missing, which means some resource references may be unresolvable. The conversion report will clearly flag this.
56
-
57
- ### Step 3: Decode the APK's resources (skip if no APK)
58
-
59
- If an APK is available (from a successful build or a cached previous build), decode its resources into `<decoded_output_path>` with the `a2h-resource` decoder.
60
-
61
- First make sure the `a2h-resource` CLI is installed (published to npm). Install it once, globally:
62
-
63
- ```bash
64
- npm install -g a2h-resource
65
- ```
66
-
67
- Then run it directly:
68
-
69
- ```bash
70
- a2h-resource <apk_path> -o <decoded_output_path>
71
- ```
72
-
73
- Alternatively, if you prefer not to install globally, run it on-demand with `npx` (which fetches the package automatically):
74
-
75
- ```bash
76
- npx --yes a2h-resource <apk_path> -o <decoded_output_path>
77
- ```
78
-
79
- `a2h-resource` is a pure-Node.js resource decoder distributed as an npm package and requires only Node.js `>= 20`. It reads the APK's `resources.arsc` — the fully-merged resource table produced at build time — so its output at `<decoded_output_path>/res/` is the **complete merged resource set** (source + all library/AAR resources merged in at build time). It produces:
80
-
81
- - `<decoded_output_path>/AndroidManifest.xml` — decoded, id references resolved (`@id/…`, `@string/…`, `@android:…`).
82
- - `<decoded_output_path>/res/` — qualifier directories with **real resource names** and decoded content:
83
- - `values*/`: `strings`, `colors`, `dimens`, `bools`, `integers`, `ids`, `<string-array>`/`<integer-array>`/`<array>`, `plurals` (plus `styles`/`attrs`, which this skill logs as unmappable).
84
- - `drawable*/`, `mipmap*/`, `layout*/`, `menu/`, `xml/`, `color/`: binary XML decoded to text — `<vector>`, `<shape>`, `<selector>`, `<layer-list>`, `<adaptive-icon>`, layouts, menus — ready for the Step 4 conversions.
85
- - `.9.png`: restored to **source form** (1-px border with stretch/padding markers).
86
- - `raw/`, `font/`, and other file resources placed under their qualifier dirs.
87
- - passthrough directories (`assets/`, `lib/`, `classes.dex`, …) copied as-is.
88
- - `<decoded_output_path>/svg/` — VectorDrawables pre-converted to SVG. **This skill runs its own SVG conversion** per `references/xml-drawable-to-svg-rules.md`, so this directory is supplementary; ignore it and use the decoded XML under `res/drawable*/` as the conversion source.
89
-
90
- On success, set `resource_source = "decoded_apk"` and use `<decoded_output_path>/res/` as the conversion source.
91
-
92
- **If decoding fails** (the command errors out — e.g. a rare APK `a2h-resource` cannot parse, or a multi-package/split APK where only the first package is decoded): record the error, then fall back to the project's source `res/` directory just as in the no-APK case below. Set `resource_source = "source_res"` and note in the report that decoding failed so the developer knows library-merged resources may be missing.
93
-
94
- If no APK is available, skip this step. The conversion source will be the project's source `res/` directory (typically `<android_project_dir>/app/src/main/res/`). Set `resource_source = "source_res"`.
95
-
96
- ### Step 4: Convert Resources
97
-
98
- Read the detailed conversion rules from `references/conversion-rules.md` before performing conversions. Convert all resources found in the resource source directory (either decoded `res/` or source `res/`). Read `references/resource-mapping-rules.md` before conversion as well — every conversion, skip, fallback, and unmappable case must also append structured mapping metadata for the final markdown written to `resource_mapping_path`.
99
-
100
- **Determining the source `res/` directory when using source fallback:**
101
- - Check `<android_project_dir>/app/src/main/res/`
102
- - If multi-module, also check other module directories
103
- - If the project uses flavor source sets, include those too (e.g., `app/src/debug/res/`, `app/src/flavor/res/`)
104
-
105
- #### 4.1 Resource Type Mapping
106
-
107
- | Android Resource Dir | HarmonyOS Target | Notes |
108
- |---|---|---|
109
- | `drawable/` (images: png, jpg, webp, gif) | `base/media/` | Direct file copy |
110
- | `drawable/` (nine-patch: `*.9.png`) | `base/media/` as `*_9.png` | Rename `.9.png` → `_9.png`; HarmonyOS does not allow `.` in resource filenames except for the final extension separator. Nine-patch stretching behavior is lost — log in report. |
111
- | `drawable/` (Android vector drawables: `<vector>`) | `base/media/` as `.svg` | Convert VectorDrawable XML to SVG format |
112
- | `drawable/` (shape drawables: `<shape>`) | `base/media/` as `.svg` | Convert shape XML to SVG |
113
- | `drawable/` (layer-list drawables: `<layer-list>`) | `base/media/` as `.svg` | Convert layered drawable to SVG with nested elements |
114
- | `drawable/` (selector/state-list drawables) | `base/media/` (default state as `.svg`) | Extract default state item and convert to SVG; log state variants in report |
115
- | `drawable/` (ripple, animated-vector, transition) | No direct equivalent | Log as unmappable; note in report |
116
- | `mipmap/` (PNG/WEBP images) | `base/media/` | App launcher icons — direct copy; rename `.9.png` → `_9.png` if nine-patch |
117
- | `mipmap/` (adaptive-icon XML: `<adaptive-icon>`) | `base/media/` as `xxx_layered_image.json` | Convert to layered-image JSON (see below) |
118
- | `mipmap/` (vector XML: `<vector>`) | `base/media/` as `.svg` | Convert VectorDrawable to SVG |
119
- | `values/strings.xml` | `base/element/string.json` | XML → JSON conversion |
120
- | `values/colors.xml` | `base/element/color.json` | XML → JSON; fix color format |
121
- | `values/dimens.xml` | `base/element/float.json` | XML → JSON; convert units |
122
- | `values/integers.xml` | `base/element/integer.json` | XML → JSON |
123
- | `values/bools.xml` | `base/element/boolean.json` | XML → JSON |
124
- | `values/arrays.xml` (string-array) | `base/element/strarray.json` | XML → JSON |
125
- | `values/arrays.xml` (integer-array) | `base/element/intarray.json` | XML → JSON |
126
- | `values/plurals.xml` | `base/element/plural.json` | XML → JSON |
127
- | `values/styles.xml` | No direct equivalent | Log in report |
128
- | `values/attrs.xml` | No direct equivalent | Log in report |
129
- | `raw/` | `rawfile/` | Direct file copy |
130
- | `font/` | `rawfile/fonts/` | Copy fonts to rawfile |
131
- | `xml/` | `base/profile/` | Only config-like XML; rename to .json if possible |
132
- | `anim/`, `animator/` | No direct equivalent | Log in report |
133
- | `layout/` | No direct equivalent | ArkUI uses declarative UI; log in report |
134
- | `menu/` | No direct equivalent | Log in report |
135
- | `color/` (color state lists) | No direct equivalent | Log in report |
136
-
137
- #### 4.1.1 Adaptive Icon → Layered-Image JSON Conversion
138
-
139
- Android adaptive-icon XML files (root element `<adaptive-icon>`, commonly found in `mipmap-anydpi-v26/`) are converted to HarmonyOS layered-image JSON files.
140
-
141
- **Conversion rules:**
142
- 1. Parse the `<adaptive-icon>` XML and extract the `<background>` and `<foreground>` elements
143
- 2. Only `background` and `foreground` are valid keys in the output JSON. Skip `monochrome` (and any other elements) **from the JSON output** — HarmonyOS has no layered-image equivalent. However, the resource *referenced* by `monochrome` (e.g., `@drawable/ic_launcher_monochrome`) is a real asset that should still be converted as a normal drawable.
144
- 3. Convert Android resource references to HarmonyOS format:
145
- - `@drawable/xxx` → `$media:xxx`
146
- - `@mipmap/xxx` → `$media:xxx`
147
- - `@color/xxx` → **generate a solid color PNG** (see rule 4 below)
148
- 4. **Critical — color background handling**: HarmonyOS `layered-image` only accepts `$media:xxx` references. It does NOT support `$color:xxx`. When the `background` (or `foreground`) references a color (`@color/xxx`):
149
- a. Look up the **resolved hex value** of `@color/xxx` from the resource source's `res/values*/colors.xml`. Follow reference chains if the color itself references another color — keep resolving until you reach a concrete hex value.
150
- b. Generate a solid-color PNG filled entirely with that hex color. A minimal valid PNG of any small size (e.g., 1×1 or 108×108 pixels) is sufficient.
151
- c. Name the PNG `<color_name>_bg.png` (e.g., `md_orange_700_bg.png`) and place it in `base/media/`.
152
- d. Reference it as `$media:<color_name>_bg` in the layered-image JSON.
153
- e. **If the color cannot be resolved** (e.g., it comes from a library and we're using source `res/`), log it as an unsatisfied dependency in the report and use a placeholder reference.
154
- 5. Output filename: `<original_name>_layered_image.json` (e.g., `ic_launcher.xml` → `ic_launcher_layered_image.json`)
155
- 6. Store in the target `media/` directory (typically `base/media/`)
156
-
157
- **Example:**
158
- ```xml
159
- <!-- mipmap-anydpi-v26/ic_launcher.xml -->
160
- <adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
161
- <background android:drawable="@color/md_orange_700" />
162
- <foreground android:drawable="@mipmap/ic_launcher_foreground" />
163
- <monochrome android:drawable="@drawable/ic_launcher_monochrome" />
164
- </adaptive-icon>
165
- ```
166
-
167
- Suppose `@color/md_orange_700` resolves to `#F57C00`. Generate `base/media/md_orange_700_bg.png` (a solid `#F57C00` filled PNG). Then convert to `base/media/ic_launcher_layered_image.json`:
168
- ```json
169
- {
170
- "layered-image": {
171
- "background": "$media:md_orange_700_bg",
172
- "foreground": "$media:ic_launcher_foreground"
173
- }
174
- }
175
- ```
176
-
177
- #### 4.2 Qualifier Directory Mapping
178
-
179
- Android uses qualifiers as directory suffixes (e.g., `drawable-hdpi`, `values-ar`). HarmonyOS uses a different qualifier directory naming convention. Convert as follows:
180
-
181
- **Screen density mapping** (Android DPI names differ from HarmonyOS):
182
-
183
- | Android Qualifier | Android DPI | HarmonyOS Qualifier | HarmonyOS DPI Range |
184
- |---|---|---|---|
185
- | `ldpi` | ~120 | `sdpi` | (0, 120] |
186
- | `mdpi` | ~160 | `mdpi` | (120, 160] |
187
- | `hdpi` | ~240 | `ldpi` | (160, 240] |
188
- | `xhdpi` | ~320 | `xldpi` | (240, 320] |
189
- | `xxhdpi` | ~480 | `xxldpi` | (320, 480] |
190
- | `xxxhdpi` | ~640 | `xxxldpi` | (480, 640] |
191
- | `nodpi` | N/A | `base` | No density qualifier; use base |
192
- | `anydpi` | N/A | `base` | No density qualifier; use base |
193
-
194
- **Language/region mapping**:
195
- - `values-ar` → `ar/element/`
196
- - `values-zh-rCN` or `values-zh` → `zh_CN/element/` or `zh/element/`
197
- - `values-en-rUS` → `en_US/element/`
198
- - `drawable-ar` → `ar/media/`
199
-
200
- The pattern: strip the base type prefix (e.g., `values-`, `drawable-`), convert the qualifier to HarmonyOS format, then place resources under the appropriate resource group directory (`element/`, `media/`, or `profile/`).
201
-
202
- **Multi-qualifier directories**: Android directories can combine multiple qualifiers with hyphens (e.g., `mipmap-anydpi-v26`, `drawable-night-v21`). Parse ALL qualifiers individually, map each one, strip unsupported ones, and use whatever valid qualifiers remain. Never reject a directory just because one of its qualifiers is unsupported — strip it and keep going. If all qualifiers are stripped, use `base/`.
203
-
204
- **Qualifiers to strip** (only these are silently removed):
205
- - API level `v<N>` (e.g., `v26`, `v21`)
206
-
207
- **Qualifiers without a HarmonyOS equivalent** (skip entirely):
208
- - Smallest width `sw<N>dp` (e.g., `sw600dp`)
209
- - Available width `w<N>dp` (e.g., `w480dp`)
210
- - Available height `h<N>dp`
211
- - Screen size (`small`, `normal`, `large`, `xlarge`)
212
-
213
- These qualifiers have no HarmonyOS mapping. When a directory's only remaining qualifiers (after stripping API level etc.) are from this list, **skip all resources in that directory** and mark them as "unmapped" in the conversion report with reason "Unsupported qualifier: no HarmonyOS equivalent". Do NOT convert them to `base/` or preserve the qualifier as-is — skipping ensures correct conversion output.
214
-
215
- **Common example**: `mipmap-anydpi-v26` → qualifiers: `anydpi` (→ `base`) + `v26` (→ strip) → target: `base/media/`. The files inside (typically `<adaptive-icon>` XML) should be processed normally by reading their XML content to determine the type — adaptive-icon XML gets converted to layered-image JSON.
216
-
217
- **HarmonyOS qualifier directory naming rules**:
218
- - Language and region are joined by underscore: `zh_CN`, `en_US`
219
- - Multiple qualifier types are separated by hyphens: `zh_CN-dark-ldpi`
220
- - Order: MCC_MNC-language_script_country/region-orientation-device-colormode-density
221
-
222
- **Orientation mapping**:
223
- - `land` → `horizontal`
224
- - `port` → `vertical`
225
-
226
- **Night mode mapping**:
227
- - `night` → `dark`
228
- - `notnight` → `light`
229
-
230
- **Handling values with non-mappable qualifiers** (e.g., `values-sw600dp`, `values-w480dp`, `values-w600dp`):
231
- These directories contain value resources qualified by screen-size constraints that HarmonyOS does not support. **Skip all resources in these directories** and mark them as "unmapped" in the conversion report with reason "Unsupported qualifier: `sw600dp` / `w480dp` / etc. — no HarmonyOS equivalent". Do NOT convert them to `base/element/` or preserve the qualifier as-is.
232
-
233
- #### 4.2.1 Record Resource Mapping Metadata
234
-
235
- As each Android resource is processed, maintain two parallel data sets for the final mapping document:
236
-
237
- 1. **Android resource inventory records** — one record per Android resource item
238
- 2. **Android ↔ HarmonyOS mapping records** — one record per conversion or non-conversion outcome
239
-
240
- Use the rules in `references/resource-mapping-rules.md`.
241
-
242
- **Minimum fields for each Android resource inventory record:**
243
- - Android resource path
244
- - Android resource name
245
- - Function description
246
- - Screen(s)
247
- - Source category
248
- - Type category
249
- - Status
250
- - Notes / evidence
251
-
252
- **Minimum fields for each mapping record:**
253
- - Android resource path
254
- - Android screen(s)
255
- - Android source category
256
- - Android type category
257
- - HarmonyOS target path (or `N/A`)
258
- - Mapping kind
259
- - Notes
260
-
261
- **Recording granularity:**
262
- - File resources (`drawable`, `mipmap`, `xml`, `font`, `raw`) → record at file level
263
- - `values/*.xml` resources → record at entry level using `file_path#tag/name` notation, e.g. `app/src/main/res/values/strings.xml#string/app_name`
264
- - One-to-many conversions (for example adaptive icon XML producing layered-image JSON plus generated PNG assets) → record each target as its own mapping row
265
- - Many-to-one conversions (for example multiple Android value entries ending up in one HarmonyOS JSON file) → still record each Android source entry separately
266
- - Unmappable resources, system resources, third-party-library-only resources, and runtime remote resources must also be recorded; never silently omit them from the mapping metadata
267
- #### 4.3 Value Format Conversions
268
-
269
- When converting `values/*.xml` to HarmonyOS JSON format:
270
-
271
- **Colors**:
272
- - Android `#RRGGBB` → HarmonyOS `#ffRRGGBB` (prepend `ff` for full opacity)
273
- - Android `#AARRGGBB` → HarmonyOS `#AARRGGBB` (already in correct format, HarmonyOS uses same order)
274
- - Android `#RGB` → expand to `#ffRRGGBB`
275
- - Android `#ARGB` → expand to `#AARRGGBB`
276
-
277
- **Dimensions** (for `dimens.xml` → `float.json`):
278
- - `dp` → `vp` (virtual pixels, similar concept)
279
- - `sp` → `fp` (font pixels)
280
- - `px` → keep as `px`
281
- - Plain numbers → append `vp`
282
-
283
- **Strings**:
284
- - XML entities (`&amp;`, `&lt;`, `&gt;`, `&quot;`, `&apos;`) → decoded characters
285
- - `\n`, `\t` → preserved
286
- - CDATA sections → extract text content
287
- - String format placeholders (`%1$s`, `%2$d`) → preserved (HarmonyOS uses same format)
288
-
289
- **Booleans**:
290
- - `"true"` / `"false"` → `true` / `false` (as JSON booleans)
291
-
292
- **Integers**:
293
- - Integer values from `integers.xml` MUST be stored as JSON number type, NOT as JSON strings
294
- - `<integer name="max_lines">3</integer>` → `{"name": "max_lines", "value": 3}` (JSON number `3`, NOT string `"3"`)
295
- - Integer-array item values must also be JSON numbers: `{"value": 100}` not `{"value": "100"}`
296
- - If the source value contains non-numeric content (e.g., a resource reference), resolve the reference first, then convert the resolved value to a JSON number
297
- - If a value cannot be parsed as a number after resolution, log a warning and use `0` as a fallback
298
-
299
- **Plurals**:
300
- - Android quantities: `zero`, `one`, `two`, `few`, `many`, `other`
301
- - HarmonyOS quantities: `zero`, `one`, `two`, `few`, `many`, `other` (same set)
302
-
303
- ### Step 5: Analyze and Resolve Resource Dependencies
304
-
305
- Android resources often reference other resources using `@type/name` syntax (e.g., `@color/primary`, `@drawable/icon`). Dependency analysis runs regardless of whether resources came from a decoded APK or source `res/` — the difference is that source-based conversion may have more unresolvable references because library resources are absent.
306
-
307
- Read `references/dependency-analysis-rules.md` for the complete dependency extraction patterns. Also use `references/resource-mapping-rules.md` during this step to infer resource function, screen ownership, source category, and type category for the mapping document.
308
-
309
- #### 5.1 Build a Resource Value Lookup Table
310
-
311
- Before resolving references, build a complete lookup table from whichever resource source is being used. This table maps every resource name to its concrete value:
312
-
313
- - **Value resources** (`colors.xml`, `dimens.xml`, `strings.xml`, etc.): parse all `values*/*.xml` files and build `type → name → value` mappings across all qualifier directories
314
- - **File resources** (`drawable/`, `mipmap/`): record `type → name → file_path` for each image or XML drawable
315
- - **Mapping support metadata**: build and maintain side tables for Android screen candidates, resource usage sites, module ownership, and likely library provenance so these can be attached to inventory and mapping rows later
316
-
317
- When working from source `res/`, this table will be **incomplete** — it won't contain resources defined in library dependencies. That's expected. The dependency analysis in Step 5.3 will identify these gaps.
318
-
319
- #### 5.2 Resolve References to True Values
320
-
321
- Scan all converted HarmonyOS resource files and replace resource references with their resolved concrete values:
322
-
323
- **In element JSON files** (`color.json`, `float.json`, `string.json`, etc.):
324
- - If a value field contains a HarmonyOS reference like `$color:name`, `$float:name`, `$string:name`, etc., look up the referenced resource in the lookup table
325
- - Replace the reference with the actual resolved value
326
- - Follow reference chains (resource A → resource B → concrete value) up to 5 levels deep to handle transitive references
327
- - If a reference cannot be resolved (e.g., it points to a library resource not in source `res/`, or to a theme attribute `?attr/name`), keep the reference as-is and log it in the report
328
-
329
- **Android system resource references** (`@android:color/*`, `@android:dimen/*`, `@android:string/*`, `@android:integer/*`):
330
-
331
- These reference Android framework built-in resources that do NOT exist in HarmonyOS. They MUST be resolved to concrete values — never leave `@android:` references in the output. Use the following built-in lookup table for `@android:color/*`:
332
-
333
- | Android System Color | Hex Value |
334
- |---|---|
335
- | `@android:color/white` | `#ffffffff` |
336
- | `@android:color/black` | `#ff000000` |
337
- | `@android:color/transparent` | `#00000000` |
338
- | `@android:color/background_dark` | `#ff000000` |
339
- | `@android:color/background_light` | `#ffffffff` |
340
- | `@android:color/darker_gray` | `#ffaaaaaa` |
341
- | `@android:color/holo_blue_bright` | `#ff00ddff` |
342
- | `@android:color/holo_blue_dark` | `#ff0099cc` |
343
- | `@android:color/holo_blue_light` | `#ff33b5e5` |
344
- | `@android:color/holo_green_dark` | `#ff669900` |
345
- | `@android:color/holo_green_light` | `#ff99cc00` |
346
- | `@android:color/holo_orange_dark` | `#ffff8800` |
347
- | `@android:color/holo_orange_light` | `#ffffbb33` |
348
- | `@android:color/holo_purple` | `#ffaa66cc` |
349
- | `@android:color/holo_red_dark` | `#ffcc0000` |
350
- | `@android:color/holo_red_light` | `#ffff4444` |
351
- | `@android:color/primary_text_dark` | `#ffffffff` |
352
- | `@android:color/primary_text_light` | `#de000000` |
353
- | `@android:color/secondary_text_dark` | `#b3ffffff` |
354
- | `@android:color/secondary_text_light` | `#8a000000` |
355
- | `@android:color/tab_indicator_text` | `#ff808080` |
356
- | `@android:color/tertiary_text_dark` | `#80ffffff` |
357
- | `@android:color/tertiary_text_light` | `#54000000` |
358
- | `@android:color/widget_edittext_dark` | `#ff000000` |
359
-
360
- For `@android:color/*` values not in this table: if converting from a decoded APK, look up the color in the decoded framework resources (`res/values/colors.xml` from the APK). Otherwise, log a warning and use `#ff000000` (black) as a safe fallback.
361
-
362
- For `@android:dimen/*` system dimensions: use the following common values:
363
-
364
- | Android System Dimen | Value |
365
- |---|---|
366
- | `@android:dimen/app_icon_size` | `48vp` |
367
- | `@android:dimen/thumbnail_width` | `96vp` |
368
- | `@android:dimen/thumbnail_height` | `96vp` |
369
- | `@android:dimen/dialog_min_width_major` | `65%` |
370
- | `@android:dimen/dialog_min_width_minor` | `95%` |
371
- | `@android:dimen/notification_large_icon_width` | `64vp` |
372
- | `@android:dimen/notification_large_icon_height` | `64vp` |
373
-
374
- For any other `@android:type/*` not covered by the tables above, log a warning in the report and substitute a reasonable default value for the type (colors → `#ff000000`, dimens → `0vp`, integers → `0`, strings → `""`).
375
-
376
- **Example — system color resolution:**
377
- ```json
378
- // Before resolution:
379
- {"name": "bg_default", "value": "@android:color/white"}
380
-
381
- // After resolution:
382
- {"name": "bg_default", "value": "#ffffffff"}
383
- ```
384
-
385
- **Example — color reference resolution:**
386
- ```json
387
- // Before resolution:
388
- {"name": "primary_light", "value": "$color:primary"}
389
-
390
- // After resolution (primary resolves to #ff6200EE):
391
- {"name": "primary_light", "value": "#ff6200EE"}
392
- ```
393
-
394
- **Example — dimension reference resolution:**
395
- ```json
396
- // Before resolution:
397
- {"name": "margin_double", "value": "$float:margin_base"}
398
-
399
- // After resolution (margin_base resolves to "16vp"):
400
- {"name": "margin_double", "value": "16vp"}
401
- ```
402
-
403
- **In SVG files** (converted XML drawables):
404
- - If a fill or stroke color was a resource reference, resolve it to the actual hex color during SVG generation
405
- - If a dimension was a resource reference, resolve it to the actual numeric value
406
-
407
- **In layered-image JSON files**:
408
- - `@drawable/xxx` and `@mipmap/xxx` references → keep as `$media:xxx` (these are file references, not value references — the files themselves are converted)
409
- - `@color/xxx` references → resolve to hex and generate solid-color PNG (as described in section 4.1.1)
410
-
411
- **Fallback strategy for unresolvable references in element JSON files:**
412
-
413
- After completing the reference resolution pass, scan all element JSON files for any remaining unresolved `$type:xxx` references. These MUST be replaced with concrete fallback values — leaving unresolved references in the output will cause HarmonyOS compilation errors.
414
-
415
- - When the resource source is a **decoded APK** (which contains the complete merged resource set), unresolved references indicate a bug in the resolution logic. Still apply fallbacks, but log prominently as errors.
416
- - When the resource source is **source `res/`**, unresolved references are expected for library resources. Apply fallbacks and log as warnings.
417
-
418
- **Fallback values by type:**
419
-
420
- | Reference Type | Fallback Value | Notes |
421
- |---|---|---|
422
- | `$color:xxx` | `#ff000000` (black) | Safe default for any missing color |
423
- | `$float:xxx` | `0vp` | Zero-dimension fallback |
424
- | `$string:xxx` | `""` (empty string) | Empty string fallback |
425
- | `$integer:xxx` | `0` | Zero integer fallback |
426
- | `$boolean:xxx` | `false` | False boolean fallback |
427
-
428
- **Resolution for cross-file references:**
429
- - When building the lookup table (Step 5.1), ensure ALL qualifier directories are scanned, not just `base/`. Color references may chain across qualifier variants (e.g., `base/` defines `primary`, `dark/` overrides it). Use the `base/` variant as the canonical value for resolution.
430
- - When a reference exists in a non-base qualifier but not in `base/`, include it in the lookup table with its qualifier noted.
431
-
432
- **Example — fallback applied:**
433
- ```json
434
- // Before fallback (unresolvable library color):
435
- {"name": "design_fab_stroke_top_outer_color", "value": "$color:design_fab_stroke_top_outer_color"}
436
-
437
- // After fallback:
438
- {"name": "design_fab_stroke_top_outer_color", "value": "#ff000000"}
439
- // Report logs: "WARNING: Unresolved $color:design_fab_stroke_top_outer_color — replaced with fallback #ff000000. Likely source: com.google.android.material:material"
440
- ```
441
-
442
- #### 5.3 Verify All Dependencies Are Satisfied
443
-
444
- After resolution, scan all converted resources for any remaining unresolved references:
445
-
446
- 1. **Converted resource dependencies**: check that every `$media:xxx`, `$color:xxx`, `$float:xxx`, etc. reference in converted files points to an existing resource in the HarmonyOS output
447
- 2. **Layout and menu file dependencies**: scan all `layout*/` and `menu/` files from the resource source for `@type/name` references. Even though layouts and menus won't be migrated as-is (ArkUI uses declarative UI), the resources they reference — strings, colors, drawables, dimensions — must exist in the converted output so the developer has everything needed when rebuilding the UI
448
- 3. Mark each dependency as **satisfied** or **unsatisfied**
449
- 4. **When using source `res/`**: unsatisfied dependencies are expected — they likely come from library resources. Parse `build.gradle` / `build.gradle.kts` to identify declared library dependencies (e.g., AndroidX, Material Components, third-party libraries). In the report, correlate unsatisfied references with likely library sources where possible (e.g., `@color/material_xxx` likely comes from Material Components library)
450
- 5. Use the dependency graph and reference locations to infer screen ownership for resources whenever possible. If a resource is referenced from multiple screens, record all of them or mark it `Common`; if it is app-wide (launcher icon, theme resource, app name), mark it `Global` or `Launcher` as appropriate.
451
-
452
- ### Step 6: Verify Completeness
453
-
454
- After conversion and dependency resolution, verify the output:
455
-
456
- 1. Build a list of all resource files found in the resource source directory
457
- 2. For each, check if it was converted or marked as unmappable
458
- 3. For converted resources, verify the target file exists in the HarmonyOS project
459
- 4. For `values/*.xml` entries, verify each individual resource entry (string, color, dimen, etc.) appears in the corresponding JSON file
460
- 5. Flag any resources that were missed
461
- 6. Verify all dependencies from converted resources are satisfied (all references resolved to true values)
462
- 7. Verify all dependencies from layout and menu files are satisfied — any missing resources should appear in the Unsatisfied Dependencies section of the report
463
- 8. **Cross-validate with existing HarmonyOS UI code**: If `harmony_project_dir` already contains `.ets` source files (i.e., it's an existing project with UI code already converted), scan ALL `.ets` files for `$r('app.media.xxx')` resource references and cross-check against the converted `media/` resources:
464
- a. For each `$r('app.media.xxx')` reference found in `.ets` files, verify that a corresponding file `xxx.*` (any extension: .png, .svg, .jpg, etc.) exists in the output `resources/base/media/` directory
465
- b. For any referenced but missing media resource, **create a placeholder SVG** file: a simple 24x24 SVG with a colored rectangle and the resource name as text, placed in `base/media/`. This ensures the project compiles.
466
- c. Log all placeholder-created resources prominently in the conversion report under a dedicated "Placeholder Resources Created" section, so the developer knows these need to be replaced with real assets
467
- d. Also scan for `$r('app.string.xxx')`, `$r('app.color.xxx')`, `$r('app.float.xxx')` references and verify those exist in the corresponding element JSON files
468
- 9. Before finishing verification, ensure every Android resource inventory row and every mapping row has the required metadata fields from `references/resource-mapping-rules.md`. If some fields cannot be proven, populate them with the rule-defined fallback labels (`Unknown`, `Common`, `Global`, `N/A`) rather than leaving them blank.
469
-
470
- **Placeholder SVG template** (for missing media resources):
471
- ```svg
472
- <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
473
- <rect width="24" height="24" fill="#CCCCCC"/>
474
- <text x="12" y="16" font-size="4" text-anchor="middle" fill="#666666">RESOURCE_NAME</text>
475
- </svg>
476
- ```
477
- Replace `RESOURCE_NAME` with the actual resource name (truncated if too long).
478
-
479
- ### Step 7: Generate Report
480
-
481
- Output the standard conversion report with these sections:
482
-
483
- ```
484
- # Android to HarmonyOS Resource Conversion Report
485
-
486
- ## Build Status
487
- - Build attempted: Yes/No
488
- - Build result: Success / Failed / Skipped
489
- - Build error (if failed): <error summary>
490
- - APK source: <"freshly built" / "cached previous build" / "none — using source res/">
491
- - Resource source: <"decoded APK (complete)" / "source res/ (may be missing library resources)">
492
- - Resource source path: <path>
493
-
494
- ⚠️ **Note** (if source res/ was used): Resources were converted from the project's source `res/` directory because no APK was available. Library-provided resources (from Maven dependencies, AARs) are NOT included. References to library resources will appear as unsatisfied dependencies below. To get a complete conversion with all library resources, fix the build and re-run.
495
-
496
- ## Library Dependencies (from build.gradle)
497
- Libraries declared in the project's build.gradle that may provide resources:
498
- | Library | Group:Artifact | Likely Resource Prefixes |
499
- |---|---|---|
500
- | Material Components | com.google.android.material:material | @color/material_*, @dimen/material_*, @style/Widget.Material* |
501
- | AndroidX AppCompat | androidx.appcompat:appcompat | @color/abc_*, @drawable/abc_* |
502
- | ... | ... | ... |
503
-
504
- (This section helps identify which unsatisfied dependencies come from which libraries.)
505
-
506
- ## Summary
507
- - Resource source: <decoded APK / source res/>
508
- - Total Android resource files found: <count>
509
- - Successfully converted: <count>
510
- - Unmappable (no HarmonyOS equivalent): <count>
511
- - Failed: <count>
512
- - Resource references resolved: <count>
513
- - Unresolved references (library resources missing): <count>
514
- - Unresolved references (other reasons): <count>
515
-
516
- ## Conversion Details
517
-
518
- ### Successfully Converted Resources
519
- | Android Source | HarmonyOS Target | Type | Notes |
520
- |---|---|---|---|
521
- | res/values/strings.xml | resources/base/element/string.json | values→element | 25 strings converted |
522
- | res/drawable/icon.png | resources/base/media/icon.png | media copy | Direct copy |
523
- | res/drawable-hdpi/bg.png | resources/ldpi/media/bg.png | qualified media | hdpi→ldpi |
524
- | ... | ... | ... | ... |
525
-
526
- ### Qualifier Mappings Applied
527
- | Android Qualifier Dir | HarmonyOS Qualifier Dir | Files Converted |
528
- |---|---|---|
529
- | drawable-hdpi | ldpi/media | 5 |
530
- | values-ar | ar/element | 3 |
531
- | ... | ... | ... |
532
-
533
- ### Resource Reference Resolution
534
- References in converted resources that were resolved to their actual values.
535
-
536
- | Resource File | Reference | Resolved Value | Resolution Chain |
537
- |---|---|---|---|
538
- | base/element/color.json → primary_light | $color:primary | #ff6200EE | @color/primary → @color/md_blue_500 → #6200EE |
539
- | base/element/float.json → margin_double | $float:margin_base | 16vp | @dimen/margin_base → 16dp → 16vp |
540
- | ... | ... | ... | ... |
541
-
542
- ### Layout & Menu Resource Dependencies
543
- Dependencies from layout/menu files (not converted to HarmonyOS, but needed when rebuilding the UI in ArkUI).
544
-
545
- | Source File (not converted) | Dependencies | All Satisfied? |
546
- |---|---|---|
547
- | layout/activity_main.xml | @string/app_name ✅, @drawable/bg_header ✅, @color/primary ✅ | Yes |
548
- | layout/fragment_settings.xml | @string/settings_title ✅, @drawable/ic_back ❌ (library) | No |
549
- | menu/main_menu.xml | @string/menu_share ✅, @drawable/ic_share ❌ (library) | No |
550
- | ... | ... | ... |
551
-
552
- ### Unmappable Resources
553
- | Android Source | Reason |
554
- |---|---|
555
- | res/layout/activity_main.xml | Layout XML has no HarmonyOS equivalent (use ArkUI) |
556
- | res/drawable/ripple_effect.xml | XML drawable not supported |
557
- | ... | ... |
558
-
559
- ### Unmapped Resources (Unsupported Qualifiers)
560
- | Android Source Dir | Qualifier | Reason |
561
- |---|---|---|
562
- | res/values-sw600dp/ | sw600dp | No HarmonyOS equivalent — skipped |
563
- | res/values-w480dp/ | w480dp | No HarmonyOS equivalent — skipped |
564
- | ... | ... | ... |
565
-
566
- ### Unresolved References (Fallback Applied)
567
- | Resource File | Original Reference | Fallback Value | Reason | Likely Source |
568
- |---|---|---|---|---|
569
- | drawable/bg_themed.xml | ?attr/colorSurface | N/A (kept as-is) | Theme attribute — cannot resolve statically | N/A |
570
- | element/color.json → material_blue | @color/design_default_color_primary | #ff000000 | Library resource not in source res/ | com.google.android.material:material |
571
- | ... | ... | ... | ... | ... |
572
-
573
- ### System Resources Resolved
574
- | Resource File | System Reference | Resolved Value |
575
- |---|---|---|
576
- | element/color.json → bg_white | @android:color/white | #ffffffff |
577
- | element/color.json → divider | @android:color/darker_gray | #ffaaaaaa |
578
- | ... | ... | ... |
579
-
580
- ### Nine-Patch Files Renamed
581
- | Original Name | Renamed To | Source Directory |
582
- |---|---|---|
583
- | abc_btn_default.9.png | abc_btn_default_9.png | drawable-mdpi |
584
- | ... | ... | ... |
585
-
586
- ### Placeholder Resources Created
587
- Media resources referenced in `.ets` UI code but not found in converted resources. Placeholder SVGs were created to allow compilation — these MUST be replaced with real assets.
588
- | Resource Name | Referenced In | Placeholder File |
589
- |---|---|---|
590
- | ic_tab_home | pages/MainPage.ets | base/media/ic_tab_home.svg |
591
- | ic_tab_profile | pages/MainPage.ets | base/media/ic_tab_profile.svg |
592
- | ... | ... | ... |
593
-
594
- ### Failed Conversions
595
- | Android Source | Error |
596
- |---|---|
597
- | ... | ... |
598
-
599
- ### Verification Results
600
- - All resources accounted for: Yes/No
601
- - Missing resources: <list if any>
602
- - All references resolved: Yes/No
603
- - Unresolved references: <count> (<count> due to missing library resources, <count> other)
604
- ```
605
-
606
- ### Step 8: Generate Resource Mapping Document
607
-
608
- After the standard conversion report is written, generate a second markdown document at `resource_mapping_path`.
609
-
610
- Read `references/resource-mapping-rules.md` and write the mapping markdown with these required sections:
611
-
612
- 1. **Metadata**
613
- - `android_project_dir`
614
- - `harmony_project_dir`
615
- - Resource source
616
- - Resource source path
617
- - Build result
618
- - Generation timestamp
619
-
620
- 2. **Android Resource Inventory**
621
- - One row per Android resource item
622
- - Required columns: Android Resource Path, Resource Name, Function, Screen(s), Source Category, Type Category, Status, Notes
623
-
624
- 3. **Android → HarmonyOS Mapping Details**
625
- - One row per mapping record
626
- - Required columns: Android Resource Path, Android Screen(s), Android Source Category, Android Type Category, HarmonyOS Target, Mapping Kind, Notes
627
-
628
- 4. **Unmapped / Unmappable / System / Remote Summary**
629
- - Explicitly list resources with no direct HarmonyOS target, Android framework resources, library-only resources inferred from the APK or dependency graph, and runtime remote resources
630
-
631
- 5. **Quick Findings**
632
- - Summarize important review findings such as launcher icons from `mipmap`, probable third-party library assets (`abc_*`, `mtrl_*`, `design_*`), and resources present only in the decoded APK but not in source `res/`
633
-
634
- **Hard requirements for the mapping markdown:**
635
- - Never omit an Android resource silently
636
- - For `values/*.xml`, inventory and mapping rows must be at entry granularity using `file_path#tag/name`
637
- - Every mapping row must include the Android-side Screen(s), Source Category, and Type Category columns
638
- - If one Android resource maps to multiple HarmonyOS outputs, emit multiple mapping rows
639
- - If no HarmonyOS target exists, write `N/A` in the HarmonyOS Target column and explain why in Notes
640
-
641
-
642
- ## Important Notes
643
-
644
- - Always read `references/conversion-rules.md` for the complete, detailed conversion rules before starting conversions. The tables above are summaries.
645
- - Always read `references/resource-mapping-rules.md` before producing `resource_mapping_path`. It defines the inventory schema, mapping schema, screen attribution rules, source categorization rules, type categorization rules, and markdown output format.
646
- - **Build is best-effort**: The APK build + decoding is attempted first because the decoded APK is the most complete resource source (it includes library dependencies). But if the build fails, conversion proceeds from source `res/` — a partial conversion with clear reporting is far more useful than no conversion at all.
647
- - **XML drawable conversion is critical**: Android XML drawables (`<vector>`, `<shape>`, `<layer-list>`, `<selector>`) must be converted to SVG format, not skipped. HarmonyOS supports SVG in `media/`. Read `references/xml-drawable-to-svg-rules.md` for the detailed conversion rules for each drawable type.
648
- - **Dependency analysis always runs**: Read `references/dependency-analysis-rules.md` for the complete dependency extraction patterns and reference formats. Even when converting from source `res/` with missing library resources, dependency analysis is essential — it tells the developer exactly which references are broken and why, so they can address them manually or fix the build.
649
- - **APK decoding**: The decoder is `a2h-resource`, a pure-Node.js resource decoder published to npm (requires Node.js `>= 20`; no other runtime). Install it with `npm install -g a2h-resource` and run `a2h-resource <apk> -o <out>`, or run it on-demand with `npx --yes a2h-resource <apk> -o <out>`. It covers resource extraction only — it does not disassemble `classes.dex` or repackage APKs, neither of which this skill needs. It decodes a single resource package (the app's); if it errors out or the APK is a rare multi-package/split APK, fall back to converting from the project's source `res/` directory (as in Step 3).
650
- - When parsing Android XML resource files, handle XML namespaces, comments, and attributes correctly.
651
- - For `values/` XML files, each `<resources>` element can contain multiple resource entries — extract ALL of them.
652
- - When multiple Android value files contribute to the same HarmonyOS JSON file (e.g., both `strings.xml` and custom `app_strings.xml` both contain `<string>` entries), merge them into a single JSON file.
653
- - Preserve resource names exactly as they appear in Android (they serve as identifiers).
654
- - If an element JSON file (like `string.json`) already exists from the template, merge new entries into it rather than overwriting — but template defaults can be replaced if they conflict.