SuperAPI AI Directory

harmony-empty-project

General & other

View repository

Updated 10-15 20:05

About this skill

HarmonyOS NEXT Empty Project Template

Applicable Scenarios

Use this skill when the user mentions the following requirements:

  • Create HarmonyOS NEXT empty project / empty project / minimal runnable project
  • Quickly generate a runnable shell project for examples (such as maps, SDK demos, etc.)
  • Create a standard HarmonyOS NEXT minimal project from scratch in the current repository

This skill guides the agent tocreate from scratcha standard minimal runnable project structure for HarmonyOS NEXT based on the Stage model + ArkTS.


Project Structure Reference (Minimal Runnable Project)

When creating a HarmonyOS NEXT empty project from scratch, it is recommended to use the following general structure (with {ProjectName} as a placeholder):

  • {ProjectName}/
    • oh-package.json5
    • build-profile.json5
    • hvigorfile.ts
    • hvigor/
      • hvigor-config.json5
    • AppScope/
      • app.json5
      • resources/...
    • entry/
      • oh-package.json5
      • build-profile.json5
      • hvigorfile.ts
      • src/main/module.json5
      • src/main/ets/entryability/EntryAbility.ets
      • src/main/ets/entrybackupability/EntryBackupAbility.ets(Optional)
      • src/main/ets/pages/Index.ets
      • src/main/resources/...

The above structure is the recommended layout for a minimal runnable HarmonyOS NEXT application project.


Quick Usage Process (Creating an Empty Project for the User)

When the user requests to "create a standard HarmonyOS empty project / HarmonyOS NEXT minimal project", follow the steps below.

Step 1: Confirm Target Information

Infer from the user context or confirm with the user (if necessary):

  • Target project directory name (for example:harmony-demo, harmony-map-demo)
  • Application bundle name (such as:com.example.demoapp)
  • Application display name (such as:DemoApp)

Project bundle name generation rules:

  • If the userexplicitly provides a bundle name(such as com.example.mapdemo), thenstrictly use the bundle name specified by the user, and do not automatically rewrite or append a suffix.
  • If the userdoes not specify a bundle name, thenprefer to automatically generate a bundle name based on the application theme / business scenario, for example:
    • When the theme is "Map Demo", you can generate com.example.mapdemo
    • When the theme is "Health Record", you can generate com.example.healthrecord
  • Only when a clear theme cannot be inferred from the context should you fall back to a generic placeholder bundle name (as shown below).

If the user does not explicitly specify, use reasonable defaults:

  • Directory name:harmony-demo
  • Bundle name: by default, generate a semantic bundle name based on the application theme; if the theme cannot be identified, use com.example.harmonydemo
  • Application name:Harmony Demo

Step 2: Create the Project Directory and Basic Files

  1. Create the project root directory under the current working directory, for example:
    • {ProjectName}/(such as harmony-demo/)
  2. Under {ProjectName}/ , create the following files and directories:
    • oh-package.json5: contains modelVersion、description、dependencies、devDependencies and other basic fields, for example:
      • modelVersion: "6.0.0"
      • devDependencies can include @ohos/hypium、@ohos/hamock to support testing
      • Dependency writing rules: Once a third-party or system dependency (such as a map library, network library, etc.) is used in the project, the corresponding dependency must be explicitly written into the oh-package.json5 of the appropriate level of dependencies field, rather than only being directly used in code import。
    • build-profile.json5: defines the app-level product and build modes (products、buildModeSet , etc.),targetSdkVersion、compatibleSdkVersion must match the development environment
    • hvigorfile.ts: import appTasks and export the default configuration:
      • system: appTasks
      • plugins: []
    • hvigor/hvigor-config.json5: Hvigor global configuration file; if missing, it will cause a build error similar to "Hvigor config file .../hvigor/hvigor-config.json5 does not exist"
    • AppScope/app.json5: defines bundleName、vendor、versionCode、versionName、icon、label , etc.
    • AppScope/resources/: contains at least the basic string and icon resources (placeholder resources can be generated by the agent according to the minimal configuration); if using layered_image as the app icon, you must provide under AppScope/resources/base/media/ both layered_image.json and the background、foreground media file it references (such as background.svg、foreground.svg), otherwise resource package error 11211120 will be reported.
  3. Under {ProjectName}/entry/ , create the module directory and the following files:
    • oh-package.json5: the package configuration file of the entry module itself (independent of the root directory oh-package.json5 , used to avoid DevEco / build tool errors "Missing file "oh-package.json5" in entry").When a dependency is used only in the entry module, the dependency should preferably be written into the entry module's oh-package.json5 's dependencies .
    • build-profile.json5: defines the entry module build configuration
    • hvigorfile.ts: imports hapTasks and exports the default configuration:
      • system: hapTasks
      • plugins: []
    • src/main/module.json5: defines the module name, type,mainElement、deviceTypes、pages、abilities , etc.
    • src/main/ets/entryability/EntryAbility.ets and src/main/ets/pages/Index.ets: contains the minimal UI and ability entry code
    • src/main/resources/: contains the resource JSON for strings, float values, colors, etc. referenced by the pages

Dependency management and installation rules

  • Dependency declaration location:
    • Any ohpm dependency used in the project (for example @bdmap/base、@bdmap/map , etc.) must be written into thespecific modulethat actually uses the dependency, in its oh-package.json5 's dependencies field (if only entry uses it, write it into {ProjectName}/entry/oh-package.json5)。
    • If the dependency is shared by multiple modules of the entire application, it can be written into the project root directory oh-package.json5according to the actual situation, but it must still be ensured that the build of the module using it can resolve the dependency.
  • Attempt to install dependencies:
    • When creating or modifying a project for the user, the agent should attempt to execute {ProjectName}/) in the corresponding project directory (usually ohpm install) to actually install the dependencies declared in oh-package.json5 .
    • If the runtime environment does not support actually executing the installation command, the response should clearly instruct the user to manually execute ohpm install or the corresponding installation command in the project directory, and ensure that the dependency list in oh-package.json5 is complete and correct.

Step 3: Modify basic application information

In the new project directory (for example {ProjectName}/), set or modify the configuration according to the following key points:

  • Application scope information:AppScope/app.json5

    • Path:{ProjectName}/AppScope/app.json5
    • Fields:
      • bundleName: set to the target package name (such as com.example.harmonydemo)
      • label: usually references a string resource (such as $string:app_name), and can remain unchanged if needed
      • versionCode / versionName: adjust accordingly if the user requests a specific version number
  • If needed, adjust the project name and product information:build-profile.json5

    • Path:{ProjectName}/build-profile.json5
    • Usually the default can be kept; if the user has requirements for the product name, etc., fine-tune it in products .

Step 4: Confirm the module configuration is complete

In the new project directory, check whether the following key files exist and are structurally complete (usually only confirmation is needed, no modification):

  • {ProjectName}/oh-package.json5

    • modelVersion field exists, for example "6.0.0"
    • If you need to use a testing framework,devDependencies contains @ohos/hypium and other dependencies
  • {ProjectName}/entry/src/main/module.json5

    • module.name is "entry"
    • mainElement points to "EntryAbility"
    • pages points to $profile:main_pages
    • abilities[0].srcEntry points to ./ets/entryability/EntryAbility.ets
  • {ProjectName}/hvigorfile.ts and {ProjectName}/entry/hvigorfile.ts

    • Use at the top level appTasks, and the entry module uses hapTasks

Step 5: Adjust the home page (optional)

If the user wants to customize a simple home page (rather than just the default Hello World), you can modify:

  • Path:{ProjectName}/entry/src/main/ets/pages/Index.ets

Keep the structure as a @Entry + @Component component, with the inner build() returning a basic layout (such as RelativeContainer or Column) and a Text text, ensuring the page structure is simple and compilable.


Feasibility self-check (verification points when the agent executes)

After creating the new empty project directory for the user, the agent should perform the following self-check to verify the feasibility of the structure:

  1. Structure check

    • Must exist:
      • {ProjectName}/oh-package.json5
      • {ProjectName}/build-profile.json5
      • {ProjectName}/hvigorfile.ts
      • {ProjectName}/hvigor/hvigor-config.json5
      • {ProjectName}/AppScope/app.json5
      • {ProjectName}/entry/oh-package.json5
      • {ProjectName}/entry/hvigorfile.ts
      • {ProjectName}/entry/src/main/module.json5
      • {ProjectName}/entry/src/main/ets/pages/Index.ets
    • If these files are missing, the agent should create the missing files or report to the user that the current structure is incomplete.
  2. Configuration consistency check

    • AppScope/app.json5 in bundleName is consistent with the user's target package name.
    • entry/src/main/module.json5 In
      • mainElement the ability pointed to actually exists in the abilities list.
      • abilities[0].srcEntry the .ets file pointed to actually exists.
  3. Pre-build check (Auto Run recommended)

    • If the HarmonyOS NEXT build toolchain is already installed in the environment,it is recommended to configure the Hvigor build command as part of the auto run process: after the new project is created or the template is modified, automatically run hvigorw assembleHap --mode module -p product=default -p buildMode=debug --no-daemonin the new project directory (or the equivalent build command provided by DevEco Studio), and confirm that there are no obvious structural errors.
    • For scenarios that continue development based on this empty project, it is recommended to configure a pre-commit or CI auto run script at the repository level to uniformly execute the above build command, ensuring that any changes based on this template can pass basic compilation checks.
    • If the build tool is unavailable, then use compliance of the structure with the requirements of "Project Structure Reference" and "Feasibility Self-check" in this skill as the criterion for judging "feasible", and indicate in the documentation or response that the user needs to manually execute hvigorw assembleHap --mode module -p product=default -p buildMode=debug --no-daemon after having the toolchain locally to complete the final verification.

Resource package and media resource constraints (required reading)

To avoid build errors Error Code: 11211120, Resource Pack Error: The resource reference '$media:xxx' is not defined, the following constraints must be observed when creating or copying an empty project:

  1. layered_image and references must exist in pairs

    • layered_image.json referenced in $media:background、$media:foreground indicates thatin the same directorythere must exist a media file named background、foreground (such as background.svg、foreground.svg)。
    • If in AppScope you use icon: "$media:layered_image"(see AppScope/app.json5), then you must place both under AppScope/resources/base/media/ :
      • layered_image.json
      • background.svg(or background.png, svg recommended)
      • foreground.svg(or foreground.png, svg recommended)
    • If in entry module is used icon: "$media:layered_image"(see entry/src/main/module.json5), then the above three items must likewise be placed under entry/src/main/resources/base/media/ (or at least background、foreground two media files + layered_image.json)。
    • Copying only layered_image.json without copying or creating background、foreground media files will cause a 11211120 error.
  2. Other $media references

    • Any $media:资源名appearing in the configuration (such as $media:startIcon) must have a file with the same name under the resources/base/media/ of the corresponding module (such as startIcon.svg), otherwise a resource pack error will likewise be triggered.
    • $media:资源名 The resolution ofthe project itselfresource directory (such as entry/src/main/resources/base/media/、AppScope/resources/base/media/) only occurs in .cursor/skills/... , and will not be read from skill directories such as
  3. Requirements for agents when creating an empty project

    • When using this skill template to create a new project, for any directory involving layered_image.json , the background、foreground media files that need to be placed must also be generated or specified (it is recommended to use a minimal usable svg placeholder image), and it is not allowed to create only layered_image.json。
    • Icons should uniformly use svg: App/ability icon-related media resources (including but not limited to layered_image of background/foreground、startWindowIcon of startIcon) should preferentially generate svg format files.
    • Generation priority rules: Preferentially automatically generate an svg matching the scenario based on the user's app scenario (app name/theme/business type, such as maps, travel, tools, etc.); if generation fails or the user does not provide any scenario information, then copy one from the sample source code provided in this skill documentcopy oneas a fallback placeholder resource (and still write it under the project's resources/base/media/ ).

For more details, see HarmonyOS resource tool restool。


Reference template code

This section uses the standard minimal executable sample project provided in the repository as the blueprint, and provides the template code and configuration for a minimal executable project. When generating files, the agent shouldremain consistent with this(only replacing identifiers such as directory name/package name), and ensure that media resources such as icons use svg rather than png.

1. Root directory oh-package.json5

```json
{
  "modelVersion": "6.0.0",
  "description": "Please describe the basic information.",
  "dependencies": {
  },
  "devDependencies": {
    "@ohos/hypium": "1.0.24",
    "@ohos/hamock": "1.0.0"
  }
}

### 2. 根目录 `build-profile.json5`

```markdown
```json
{
  "app": {
    "signingConfigs": [],
    "products": [
      {
        "name": "default",
        "signingConfig": "default",
        "targetSdkVersion": "6.0.0(20)",
        "compatibleSdkVersion": "5.0.4(16)",
        "runtimeOS": "HarmonyOS",
        "buildOption": {
          "strictMode": {
            "caseSensitiveCheck": true,
            "useNormalizedOHMUrl": true
          }
        }
      }
    ],
    "buildModeSet": [
      {
        "name": "debug",
      },
      {
        "name": "release"
      }
    ]
  },
  "modules": [
    {
      "name": "entry",
      "srcPath": "./entry",
      "targets": [
        {
          "name": "default",
          "applyToProducts": [
            "default"
          ]
        }
      ]
    }
  ]
}

### 3. 根目录 `hvigorfile.ts`

```markdown
```ts
import { appTasks } from '@ohos/hvigor-ohos-plugin';

export default {
  system: appTasks, /* Built-in plugin of Hvigor. It cannot be modified. */
  plugins: []       /* Custom plugin to extend the functionality of Hvigor. */
}

### 4. 根目录 `hvigor/hvigor-config.json5`

```markdown
```json5
{
  "modelVersion": "6.0.0",
  "dependencies": {
  },
  "execution": {
    // "analyze": "normal",
    // "daemon": true,
    // "incremental": true,
    // "parallel": true,
    // "typeCheck": false,
    // "optimizationStrategy": "memory"
  },
  "logging": {
    // "level": "info"
  },
  "debugging": {
    // "stacktrace": false
  },
  "nodeOptions": {
    // "maxOldSpaceSize": 8192,
    // "exposeGC": true
  }
}

### 5. `AppScope/app.json5`

```markdown
```json
{
  "app": {
    "bundleName": "com.example.application",
    "vendor": "example",
    "versionCode": 1000000,
    "versionName": "1.0.0",
    "icon": "$media:layered_image",
    "label": "$string:app_name"
  }
}

### 6. `AppScope/resources/base/element/string.json`

```markdown
```json
{
  "string": [
    {
      "name": "app_name",
      "value": "Harmony Demo"
    }
  ]
}

### 7. `AppScope/resources/base/media/layered_image.json`

```markdown
```json
{
  "layered-image": {
    "background": "$media:background",
    "foreground": "$media:foreground"
  }
}

> **约束**:`$media:background`、`$media:foreground` 必须在**同目录** `AppScope/resources/base/media/` 下存在对应文件(如 `background.svg`、`foreground.svg`),否则构建报错 11211120。详见上文「资源包与媒体资源约束」。推荐使用 svg,勿仅创建本 JSON 而不创建 background/foreground 文件。

### 8. entry 模块 `oh-package.json5`

```markdown
```json
{
  "name": "entry",
  "version": "1.0.0",
  "description": "Please describe the basic information.",
  "main": "",
  "author": "",
  "license": "",
  "dependencies": {}
}

### 9. entry 模块 `build-profile.json5`

```markdown
```json5
{
  "apiType": "stageMode",
  "buildOption": {
    "resOptions": {
      "copyCodeResource": {
        "enable": false
      }
    }
  },
  "buildOptionSet": [
    {
      "name": "release",
      "arkOptions": {
        "obfuscation": {
          "ruleOptions": {
            "enable": false,
            "files": [
              "./obfuscation-rules.txt"
            ]
          }
        }
      }
    },
  ],
  "targets": [
    {
      "name": "default"
    },
    {
      "name": "ohosTest",
    }
  ]
}

### 10. entry 模块 `hvigorfile.ts`

```markdown
```ts
import { hapTasks } from '@ohos/hvigor-ohos-plugin';

export default {
  system: hapTasks, /* Built-in plugin of Hvigor. It cannot be modified. */
  plugins: []       /* Custom plugin to extend the functionality of Hvigor. */
}

### 11. entry 模块 `src/main/module.json5`

```markdown
```json5
{
  "module": {
    "name": "entry",
    "type": "entry",
    "description": "$string:module_desc",
    "mainElement": "EntryAbility",
    "deviceTypes": [
      "phone"
    ],
    "deliveryWithInstall": true,
    "installationFree": false,
    "pages": "$profile:main_pages",
    "abilities": [
      {
        "name": "EntryAbility",
        "srcEntry": "./ets/entryability/EntryAbility.ets",
        "description": "$string:EntryAbility_desc",
        "icon": "$media:layered_image",
        "label": "$string:EntryAbility_label",
        "startWindowIcon": "$media:startIcon",
        "startWindowBackground": "$color:start_window_background",
        "exported": true,
        "skills": [
          {
            "entities": [
              "entity.system.home"
            ],
            "actions": [
              "ohos.want.action.home"
            ]
          }
        ]
      }
    ],
    "extensionAbilities": [
      {
        "name": "EntryBackupAbility",
        "srcEntry": "./ets/entrybackupability/EntryBackupAbility.ets",
        "type": "backup",
        "exported": false,
        "metadata": [
          {
            "name": "ohos.extension.backup",
            "resource": "$profile:backup_config"
          }
        ],
      }
    ]
  }
}

### 12. `EntryAbility.ets`(入口能力)

```markdown
```ts
import { AbilityConstant, ConfigurationConstant, UIAbility, Want } from '@kit.AbilityKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
import { window } from '@kit.ArkUI';

const DOMAIN = 0x0000;

export default class EntryAbility extends UIAbility {
  onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
    try {
      this.context.getApplicationContext().setColorMode(ConfigurationConstant.ColorMode.COLOR_MODE_NOT_SET);
    } catch (err) {
      hilog.error(DOMAIN, 'testTag', 'Failed to set colorMode. Cause: %{public}s', JSON.stringify(err));
    }
    hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onCreate');
  }

  onDestroy(): void {
    hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onDestroy');
  }

  onWindowStageCreate(windowStage: window.WindowStage): void {
    // Main window is created, set main page for this ability
    hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onWindowStageCreate');

    windowStage.loadContent('pages/Index', (err) => {
      if (err.code) {
        hilog.error(DOMAIN, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err));
        return;
      }
      hilog.info(DOMAIN, 'testTag', 'Succeeded in loading the content.');
    });
  }

  onWindowStageDestroy(): void {
    // Main window is destroyed, release UI related resources
    hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onWindowStageDestroy');
  }

  onForeground(): void {
    // Ability has brought to foreground
    hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onForeground');
  }

  onBackground(): void {
    // Ability has back to background
    hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onBackground');
  }
}

### 13. `EntryBackupAbility.ets`(备份扩展能力)

```markdown
```ts
import { hilog } from '@kit.PerformanceAnalysisKit';
import { BackupExtensionAbility, BundleVersion } from '@kit.CoreFileKit';

const DOMAIN = 0x0000;

export default class EntryBackupAbility extends BackupExtensionAbility {
  async onBackup() {
    hilog.info(DOMAIN, 'testTag', 'onBackup ok');
    await Promise.resolve();
  }

  async onRestore(bundleVersion: BundleVersion) {
    hilog.info(DOMAIN, 'testTag', 'onRestore ok %{public}s', JSON.stringify(bundleVersion));
    await Promise.resolve();
  }
}

### 14. `pages/Index.ets`(首页页面)

```markdown
```ts
@Entry
@Component
struct Index {
  @State message: string = 'Hello World';

  build() {
    RelativeContainer() {
      Text(this.message)
        .id('HelloWorld')
        .fontSize($r('app.float.page_text_font_size'))
        .fontWeight(FontWeight.Bold)
        .alignRules({
          center: { anchor: '__container__', align: VerticalAlign.Center },
          middle: { anchor: '__container__', align: HorizontalAlign.Center }
        })
        .onClick(() => {
          this.message = 'Welcome';
        })
    }
    .height('100%')
    .width('100%')
  }
}

### 15. entry 关键资源示例

- `entry/src/main/resources/base/element/string.json`

```markdown
```json
{
  "string": [
    {
      "name": "module_desc",
      "value": "module description"
    },
    {
      "name": "EntryAbility_desc",
      "value": "description"
    },
    {
      "name": "EntryAbility_label",
      "value": "label"
    }
  ]
}

- `entry/src/main/resources/base/element/float.json`

```markdown
```json
{
  "float": [
    {
      "name": "page_text_font_size",
      "value": "50fp"
    }
  ]
}

- `entry/src/main/resources/base/element/color.json`

```markdown
```json
{
  "color": [
    {
      "name": "start_window_background",
      "value": "#FFFFFF"
    }
  ]
}

- `entry/src/main/resources/base/profile/main_pages.json`

```markdown
```json
{
  "src": [
    "pages/Index"
  ]
}

- `entry/src/main/resources/base/profile/backup_config.json`

```markdown
```json
{
  "allowToBackupRestore": true
}

- `entry/src/main/resources/base/media/layered_image.json`

```markdown
```json
{
  "layered-image": {
    "background": "$media:background",
    "foreground": "$media:foreground"
  }
}

> **约束**:entry 的 `resources/base/media/` 下也须存在 `background.svg`、`foreground.svg`(或同名 png),否则 11211120。详见「资源包与媒体资源约束」。

- `entry/src/main/resources/base/media/startIcon.svg`

```markdown
```xml
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 108 108" width="108" height="108">
  <defs>
    <linearGradient id="bg" x1="0" y1="0" x2="1" y2="1">
      <stop offset="0%" stop-color="#2F7DFF"/>
      <stop offset="100%" stop-color="#0A59F7"/>
    </linearGradient>
  </defs>
  <rect x="0" y="0" width="108" height="108" rx="24" fill="url(#bg)"/>
  <rect x="28" y="28" width="22" height="22" rx="6" fill="#EAF1FF"/>
  <rect x="58" y="28" width="22" height="22" rx="6" fill="#DDE9FF"/>
  <rect x="28" y="58" width="22" height="22" rx="6" fill="#DDE9FF"/>
  <rect x="58" y="58" width="22" height="22" rx="6" fill="#BFD6FF"/>
</svg>

> **约束**:若 `entry/src/main/module.json5` 中存在 `"startWindowIcon": "$media:startIcon"`,则 entry 的 `resources/base/media/` 下必须存在 `startIcon.svg`(或 `startIcon.png`),并且**文件名大小写需与 `$media:` 引用一致**(受 `caseSensitiveCheck` 影响)。

代理在创建空工程时,应直接以本节模板为基础生成文件,并根据用户给定的 `{ProjectName}`、`bundleName` 等做相应替换,且在引入媒体资源时统一采用 svg 格式。

---

## 使用示例

### 示例一:创建默认空工程

用户:  
> @harmony 帮我创建一个 HarmonyOS NEXT 的空工程,用来做后续 SDK Demo。

代理应当:

1. 按“快速使用流程”在当前目录下创建 `{ProjectName}`(如 `harmony-demo`)工程结构。
2. 将包名设置为 `com.example.harmonydemo`。

### 示例二:创建带自定义包名的空工程

用户:  
> 基于现在这个最小工程结构,帮我再创建一个包名为 `com.example.mapdemo` 的鸿蒙空工程。

代理应当:

1. 在当前目录下创建 `{ProjectName}`(如 `harmony-map-demo`)工程结构。
2. 在新工程中修改:
   - `{ProjectName}/AppScope/app.json5` 中的 `bundleName` 为 `com.example.mapdemo`。
3. 按“可行性自检”章节检查关键文件与字段。

---

## 总结

- 本技能基于当前仓库自带的 `harmony` 最小可运行示例工程,通过**结构复制 + 少量配置修改**,快速为用户创建 HarmonyOS NEXT 标准空工程。
- 代理在执行时应始终对照模板工程结构进行检查,确保新工程在文件布局与关键配置上与模板保持一致,从而保证可行性。