Skip to content

应用实例与项目结构

应用实例

每个 HarmonyOS 应用都从一个 UIAbility 开始。UIAbility 是带界面的能力单元,负责管理一组页面和生命周期。

typescript
// entry/src/main/ets/entryability/EntryAbility.ets
import { UIAbility, AbilityConstant, Want } from '@kit.AbilityKit'
import { window } from '@kit.ArkUI'

export default class EntryAbility extends UIAbility {
  onCreate(want: Want, launchParam: AbilityConstant.LaunchParam) {
    // 应用创建时调用
    console.info('EntryAbility onCreate')
  }

  onDestroy() {
    // 应用销毁时调用
    console.info('EntryAbility onDestroy')
  }

  onWindowStageCreate(windowStage: window.WindowStage) {
    // 窗口创建时调用,加载入口页面
    windowStage.loadContent('pages/Index', (err) => {
      if (err.code) {
        console.error('加载页面失败', JSON.stringify(err))
        return
      }
      console.info('页面加载成功')
    })
  }

  onWindowStageDestroy() {
    // 窗口销毁时调用
  }

  onForeground() {
    // 进入前台时调用
  }

  onBackground() {
    // 进入后台时调用
  }
}

UIAbility 生命周期

onCreate → onWindowStageCreate → onForeground → onBackground → onWindowStageDestroy → onDestroy
                ↑______________________________________________↓
生命周期触发时机典型用途
onCreate应用首次创建初始化数据、读取配置
onWindowStageCreate窗口创建加载入口页面
onForeground应用进入前台恢复数据、刷新界面
onBackground应用进入后台保存状态、释放资源
onWindowStageDestroy窗口销毁清理窗口相关资源
onDestroy应用销毁最终清理

页面组件

传给 windowStage.loadContent() 的是页面路径,对应的页面组件:

typescript
// entry/src/main/ets/pages/Index.ets
@Entry
@Component
struct Index {
  // 页面级状态
  @State title: string = '首页'

  // 页面生命周期
  aboutToAppear() {
    console.info('页面即将显示')
  }

  aboutToDisappear() {
    console.info('页面即将销毁')
  }

  onPageShow() {
    console.info('页面显示')
  }

  onPageHide() {
    console.info('页面隐藏')
  }

  build() {
    Column() {
      Text(this.title)
        .fontSize(24)
        .fontWeight(FontWeight.Bold)
    }
    .width('100%')
    .height('100%')
    .justifyContent(FlexAlign.Center)
  }
}

页面生命周期

aboutToAppear → build → onPageShow → onPageHide → aboutToDisappear
     ↑________________________________________________↓
生命周期触发时机典型用途
aboutToAppear页面创建前请求数据、初始化状态
onPageShow页面显示时刷新数据、埋点统计
onPageHide页面隐藏时暂停动画、保存临时数据
aboutToDisappear页面销毁前取消订阅、清理资源

组件树

实际应用通常由多个组件组成树状结构:

Index (入口页面)
├── Header (自定义组件)
│   ├── Logo
│   └── Title
├── Content (自定义组件)
│   ├── Sidebar
│   └── Main
└── Footer (自定义组件)
typescript
// Header.ets
@Component
export struct Header {
  @Prop title: string

  build() {
    Row() {
      Image($r('app.media.logo'))
        .width(40)
        .height(40)
      Text(this.title)
        .fontSize(20)
        .margin({ left: 12 })
    }
    .width('100%')
    .height(60)
    .padding({ left: 16, right: 16 })
    .backgroundColor('#F5F5F5')
  }
}

// Index.ets
import { Header } from './components/Header'

@Entry
@Component
struct Index {
  @State pageTitle: string = '我的应用'

  build() {
    Column() {
      Header({ title: this.pageTitle })

      // 页面内容
      Column() {
        Text('这是页面内容')
          .fontSize(16)
      }
      .layoutWeight(1)
      .width('100%')

      // 底部
      Text('© 2024')
        .fontSize(12)
        .fontColor('#999')
        .height(40)
    }
    .width('100%')
    .height('100%')
  }
}

多个应用实例

一个工程可以包含多个 UIAbility:

typescript
// module.json5 配置多个 Ability
{
  "module": {
    "abilities": [
      {
        "name": "EntryAbility",
        "srcEntry": "./ets/entryability/EntryAbility.ets",
        "mainElement": "EntryAbility"
      },
      {
        "name": "SecondAbility",
        "srcEntry": "./ets/entryability/SecondAbility.ets"
      }
    ]
  }
}

启动另一个 Ability:

typescript
import { Want } from '@kit.AbilityKit'
import { common } from '@kit.AbilityKit'

async function startSecondAbility() {
  const context = getContext(this) as common.UIAbilityContext
  const want: Want = {
    bundleName: 'com.example.myapp',
    abilityName: 'SecondAbility'
  }
  await context.startAbility(want)
}

应用配置

应用级配置 AppScope/app.json5

json5
{
  "app": {
    "bundleName": "com.example.myapp",
    "vendor": "example",
    "versionCode": 1,
    "versionName": "1.0.0",
    "icon": "$media:app_icon",
    "label": "$string:app_name"
  }
}

模块级配置 module.json5

json5
{
  "module": {
    "name": "entry",
    "type": "entry",
    "deviceTypes": ["phone", "tablet"],
    "mainElement": "EntryAbility",
    "pages": "$profile:main_pages",
    "abilities": [
      {
        "name": "EntryAbility",
        "srcEntry": "./ets/entryability/EntryAbility.ets",
        "description": "$string:EntryAbility_desc",
        "icon": "$media:app_icon",
        "label": "$string:EntryAbility_label",
        "startWindowIcon": "$media:app_icon",
        "startWindowBackground": "$color:start_window_background",
        "exported": true,
        "skills": [
          {
            "entities": ["entity.system.home"],
            "actions": ["action.system.home"]
          }
        ]
      }
    ],
    "requestPermissions": [
      {
        "name": "ohos.permission.INTERNET",
        "reason": "$string:reason_internet",
        "usedScene": {}
      }
    ]
  }
}

重要提示

所有应用配置必须在 windowStage.loadContent() 之前完成!