Harmonyos App

majiayu000/spellbook/skills/harmonyos-app

作者 majiayu000ed52af74bce85ba9e71db109c72708833012eaf2无许可证收录于 2026年10月9日更新于 2026年10月9日

HarmonyOS application development expert. Use when building HarmonyOS apps with ArkTS, ArkUI, Stage model, and distributed capabilities. Covers HarmonyOS NEXT (API 12+) best practices.

AI 生成的概览

指导使用 ArkTS、ArkUI、Stage 模型和分布式能力进行 HarmonyOS 应用开发。

功能
该技能为构建 HarmonyOS 应用提供专业指导,涵盖 ArkTS、ArkUI 声明式 UI、Stage 模型和分布式特性。它提供强制编码规则、状态管理模式、项目结构建议和组件示例,并附带 ArkTS、ArkUI、分布式能力、Stage 模型及扩展内容的参考文件。此外还包含一份项目模板文档。
适用场景
适用于开发或组织 HarmonyOS 应用,尤其是 HarmonyOS NEXT(API 12+)。适合涉及 ArkTS 类型安全、ArkUI 组件与状态装饰器、UIAbility Stage 模型搭建或跨设备分布式设计的任务。
运行要求
无需脚本或特殊工具,仅包含说明和参考文档。智能体需要能够访问随附的参考文件和模板文件以加载详细内容。

HarmonyOS Application Development

Core Principles

  • ArkTS First — Use ArkTS with strict type safety, no any or dynamic types
  • Declarative UI — Build UI with ArkUI's declarative components and state management
  • Stage Model — Use modern Stage model (UIAbility), not legacy FA model
  • Distributed by Design — Leverage cross-device capabilities from the start
  • Atomic Services — Consider atomic services and cards for lightweight experiences
  • One-time Development — Design for multi-device adaptation (phone, tablet, watch, TV)

Hard Rules (Must Follow)

These rules are mandatory. Violating them means the skill is not working correctly.

No Dynamic Types

ArkTS prohibits dynamic typing. Never use any, type assertions, or dynamic property access.

typescript
// ❌ FORBIDDEN: Dynamic typeslet data: any = fetchData();let obj: object = {};obj['dynamicKey'] = value;  // Dynamic property access(someVar as SomeType).method();  // Type assertion
// ✅ REQUIRED: Strict typinginterface UserData {  id: string;  name: string;}let data: UserData = fetchData();
// Use Record for dynamic keyslet obj: Record<string, string> = {};obj['key'] = value;  // OK with Record type

No Direct State Mutation

Never mutate @State/@Prop variables directly in nested objects. Use immutable updates.

typescript
// ❌ FORBIDDEN: Direct mutation@State user: User = { name: 'John', age: 25 };
updateAge() {  this.user.age = 26;  // UI won't update!}
// ✅ REQUIRED: Immutable updateupdateAge() {  this.user = { ...this.user, age: 26 };  // Creates new object, triggers UI update}
// For arrays@State items: string[] = ['a', 'b'];
// ❌ FORBIDDENthis.items.push('c');  // UI won't update
// ✅ REQUIREDthis.items = [...this.items, 'c'];

Stage Model Only

Always use Stage model (UIAbility). Never use deprecated FA model (PageAbility).

typescript
// ❌ FORBIDDEN: FA Model (deprecated)// config.json with "pages" arrayexport default {  onCreate() { ... }  // PageAbility lifecycle}
// ✅ REQUIRED: Stage Model// module.json5 with abilities configurationimport { UIAbility } from '@kit.AbilityKit';
export default class EntryAbility extends UIAbility {  onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {    // Modern Stage model lifecycle  }
  onWindowStageCreate(windowStage: window.WindowStage): void {    windowStage.loadContent('pages/Index');  }}

Component Reusability

Extract reusable UI into @Component. No inline complex UI in build() methods.

typescript
// ❌ FORBIDDEN: Monolithic build method@Entry@Componentstruct MainPage {  build() {    Column() {      // 200+ lines of inline UI...      Row() {        Image($r('app.media.avatar'))        Column() {          Text(this.user.name)          Text(this.user.email)        }      }      // More inline UI...    }  }}
// ✅ REQUIRED: Extract components@Componentstruct UserCard {  @Prop user: User;
  build() {    Row() {      Image($r('app.media.avatar'))      Column() {        Text(this.user.name)        Text(this.user.email)      }    }  }}
@Entry@Componentstruct MainPage {  @State user: User = { name: 'John', email: '[email protected]' };
  build() {    Column() {      UserCard({ user: this.user })    }  }}

Quick Reference

When to Use What

ScenarioPatternExample
Component-local state@StateCounter, form inputs
Parent-to-child data@PropRead-only child data
Two-way binding@LinkShared mutable state
Cross-component state@Provide/@ConsumeTheme, user context
Persistent statePersistentStorageUser preferences
App-wide stateAppStorageGlobal state
Complex state logic@Observed/@ObjectLinkNested object updates

State Decorator Selection

@State        → Component owns the state, triggers re-render on change@Prop         → Parent passes value, child gets copy (one-way)@Link         → Parent passes reference, child can modify (two-way)@Provide      → Ancestor provides value to all descendants@Consume      → Descendant consumes value from ancestor@StorageLink  → Syncs with AppStorage, two-way binding@StorageProp  → Syncs with AppStorage, one-way binding@Observed     → Class decorator for observable objects@ObjectLink   → Links to @Observed object in parent

Project Structure

Recommended Architecture

MyApp/├── entry/                          # Main entry module│   ├── src/main/│   │   ├── ets/│   │   │   ├── entryability/       # UIAbility definitions│   │   │   │   └── EntryAbility.ets│   │   │   ├── pages/              # Page components│   │   │   │   ├── Index.ets│   │   │   │   └── Detail.ets│   │   │   ├── components/         # Reusable UI components│   │   │   │   ├── common/         # Common components│   │   │   │   └── business/       # Business-specific components│   │   │   ├── viewmodel/          # ViewModels (MVVM)│   │   │   ├── model/              # Data models│   │   │   ├── service/            # Business logic services│   │   │   ├── repository/         # Data access layer│   │   │   ├── utils/              # Utility functions│   │   │   └── constants/          # Constants and configs│   │   ├── resources/              # Resources (strings, images)│   │   └── module.json5            # Module configuration│   └── build-profile.json5├── common/                         # Shared library module│   └── src/main/ets/├── features/                       # Feature modules│   ├── feature_home/│   └── feature_profile/└── build-profile.json5             # Project configuration

Layer Separation

┌─────────────────────────────────────┐│           UI Layer (Pages)          │  ArkUI Components├─────────────────────────────────────┤│         ViewModel Layer             │  State management, UI logic├─────────────────────────────────────┤│         Service Layer               │  Business logic├─────────────────────────────────────┤│        Repository Layer             │  Data access abstraction├─────────────────────────────────────┤│    Data Sources (Local/Remote)      │  Preferences, RDB, Network└─────────────────────────────────────┘

ArkUI Component Patterns

Basic Component Structure

typescript
import { router } from '@kit.ArkUI';
@Componentexport struct ProductCard {  // Props from parent  @Prop product: Product;  @Prop onAddToCart: (product: Product) => void;
  // Local state  @State isExpanded: boolean = false;
  // Computed values (use getters)  get formattedPrice(): string {    return `¥${this.product.price.toFixed(2)}`;  }
  // Lifecycle  aboutToAppear(): void {    console.info('ProductCard appearing');  }
  aboutToDisappear(): void {    console.info('ProductCard disappearing');  }
  // Event handlers  private handleTap(): void {    router.pushUrl({ url: 'pages/ProductDetail', params: { id: this.product.id } });  }
  private handleAddToCart(): void {    this.onAddToCart(this.product);  }
  // UI builder  build() {    Column() {      Image(this.product.imageUrl)        .width('100%')        .aspectRatio(1)        .objectFit(ImageFit.Cover)
      Text(this.product.name)        .fontSize(16)        .fontWeight(FontWeight.Medium)
      Text(this.formattedPrice)        .fontSize(14)        .fontColor('#FF6B00')
      Button('Add to Cart')        .onClick(() => this.handleAddToCart())    }    .padding(12)    .backgroundColor(Color.White)    .borderRadius(8)    .onClick(() => this.handleTap())  }}

List with LazyForEach

typescript
import { BasicDataSource } from '../utils/BasicDataSource';
class ProductDataSource extends BasicDataSource<Product> {  private products: Product[] = [];
  totalCount(): number {    return this.products.length;  }
  getData(index: number): Product {    return this.products[index];  }
  addData(product: Product): void {    this.products.push(product);    this.notifyDataAdd(this.products.length - 1);  }
  updateData(index: number, product: Product): void {    this.products[index] = product;    this.notifyDataChange(index);  }}
@Componentstruct ProductList {  private dataSource: ProductDataSource = new ProductDataSource();
  build() {    List() {      LazyForEach(this.dataSource, (product: Product, index: number) => {        ListItem() {          ProductCard({ product: product })        }      }, (product: Product) => product.id)  // Key generator    }    .lanes(2)  // Grid with 2 columns    .cachedCount(4)  // Cache 4 items for smooth scrolling  }}

Custom Dialog

typescript
@CustomDialogstruct ConfirmDialog {  controller: CustomDialogController;  title: string = 'Confirm';  message: string = '';  onConfirm: () => void = () => {};
  build() {    Column() {      Text(this.title)        .fontSize(20)        .fontWeight(FontWeight.Bold)        .margin({ bottom: 16 })
      Text(this.message)        .fontSize(16)        .margin({ bottom: 24 })
      Row() {        Button('Cancel')          .onClick(() => this.controller.close())          .backgroundColor(Color.Gray)          .margin({ right: 16 })
        Button('Confirm')          .onClick(() => {            this.onConfirm();            this.controller.close();          })      }    }    .padding(24)  }}
// Usage@Entry@Componentstruct MainPage {  dialogController: CustomDialogController = new CustomDialogController({    builder: ConfirmDialog({      title: 'Delete Item',      message: 'Are you sure you want to delete this item?',      onConfirm: () => this.deleteItem()    }),    autoCancel: true  });
  private deleteItem(): void {    // Delete logic  }
  build() {    Button('Delete')      .onClick(() => this.dialogController.open())  }}

Extended Reference

Detailed material starting at ## State Management Patterns has been moved to reference/extended.md [blocked] to keep this skill concise. Load that reference when the task requires the moved examples, command catalogs, checklists, platform details, or implementation templates.

来源与署名

来源:majiayu000/spellbook位于skills/harmonyos-app提交ed52af7

许可证: 无许可证

内容归原作者所有。SourceWeft 从公开仓库中收录这些内容。

举报或申请下架