一、创建一个示例项目
-
DevEco Studio 开始页面,单击新建项目
-
选择一个应用模板,这里以第一个 Empty Ability 为例,然后单击下一步 Next
-
根据项目要求,设置 项目名称、应用包名、保存路径、SDK 版本、模块名称和设备类型,这里使用默认参数作为演示,然后点击完成 Finish
-
稍等片刻,DevEco Studio 会自动配置项目环境安装需要的依赖
-
通过右侧的 预览器 标签页可快速预览应用的界面,至此一个示例的 Hello World 项目新建完毕
二、模拟器运行与调试
-
打开设备管理器
-
根据 (可选)HarmonyOS 模拟器配置 的流程下载并启动虚拟机
-
在 DevEco Studio 中选择已启动的模拟器,并点击项目运行按钮或使用快捷键 Ctrl+F5 即可运行应用于模拟器之上
-
等待项目编译后将自动安装至模拟器并启动该应用
-
也可以通过点击调试按钮对应用进行断点调试
三、项目工程结构介绍
-
HarmonyOS 应用的项目工程结构如下图所示:
-
工程结构主要包含的文件类型及用途如下:
文件类型 说明 配置文件 包括应用级配置信息、以及 Module 级配置信息。
- AppScope > app.json5:app.json5 配置文件,用于声明应用的全局配置信息,比如应用 Bundle 名称、应用名称、应用图标、应用版本号等。
- Module_name > src > main > module.json5:module.json5 配置文件,用于声明Module基本信息、支持的设备类型、所含的组件信息、运行所需申请的权限等。ArkTS 源码文件 - Module_name > src > main > ets:用于存放 Module 的 ArkTS 源码文件(.ets文件)。 资源文件 包括应用级资源文件、以及 Module 级资源文件,支持图形、多媒体、字符串、布局文件等,详见 资源分类与访问。
- AppScope > resources :用于存放应用需要用到的资源文件。
- Module_name > src > main > resources :用于存放该 Module 需要用到的资源文件。其他配置文件 用于编译构建,包括构建配置文件、编译构建任务脚本、混淆规则文件、依赖的共享包信息等。
- build-profile.json5:工程级或 Module 级的构建配置文件,包括应用签名、产品配置等。
- hvigorfile.ts:应用级或 Module 级的编译构建任务脚本,开发者可以自定义编译构建工具版本、控制构建行为的配置参数。
- obfuscation-rules.txt:混淆规则文件。混淆开启后,在使用 Release 模式进行编译时,会对代码进行编译、混淆及压缩处理,保护代码资产。
- oh-package.json5:用于存放依赖库的信息,包括所依赖的三方库和共享包。
四、示例项目代码详解
-
在开始讲解项目之前,得先简单介绍几个 HarmonyOS 里面的概念(可能现在看不太懂,也没关系),更多详细的解释请参考官网文档。
-
Ability Kit(程序框架服务)提供了应用程序开发和运行的应用模型,是系统为开发者提供的应用程序所需能力的抽象提炼,它提供了应用程序必备的组件和运行机制。有了应用模型,开发者可以基于一套统一的模型进行应用开发,使应用开发更简单、高效。
-
Stage 模型提供 UIAbility(示例项目使用的) 和 ExtensionAbility 两种类型的组件,这两种组件都有具体的类承载,支持面向对象的开发方式。
-
UIAbility 组件是一种包含UI的应用组件,主要用于和用户交互。例如,图库类应用可以在UIAbility 组件中展示图片瀑布流,在用户选择某个图片后,在新的页面中展示图片的详细内容。同时用户可以通过返回键返回到瀑布流页面。UIAbility 组件的生命周期只包含创建/销毁/前台/后台等状态,与显示相关的状态通过 WindowStage 的事件暴露给开发者。
-
WindowStage 每个UIAbility实例都会与一个 WindowStage 类实例绑定,该类起到了应用进程内窗口管理器的作用。它包含一个主窗口。也就是说 UIAbility 实例通过 WindowStage 持有了一个主窗口,该主窗口为ArkUI提供了绘制区域。
-
Context 在 Stage 模型上,Context 及其派生类向开发者提供在运行期可以调用的各种资源和能力。UIAbility 组件和各种 ExtensionAbility 组件的派生类都有各自不同的 Context 类,他们都继承自基类 Context,但是各自又根据所属组件,提供不同的能力。
-
-
示例项目的代码文件主要是以下俩个文件:
-
-
MyApplication > src > main > ets > entryability > EntryAbility.ets: 该文件主要用来实现 Ability 的生命周期中的一些行为和操作,应用程序和窗口的生命周期的状态变化可以参考上面的两个示意图。在示例项目中,生命周期的不同阶段会打印对应的文本日志,让开发者可以通过日志快速了解各个状态触发的时机,当然也可以在这些状态中实现程序或者任务需要的实际功能,除了打印日志以外唯一的操作只有加载 pages/Index 页面,这将让 Index 页面作为主界面显示出来。
// 导入 Ability 相关的模块 import { AbilityConstant, UIAbility, Want } from '@kit.AbilityKit'; // 导入 Log 模块 import { hilog } from '@kit.PerformanceAnalysisKit'; // 导入 window 模块 import { window } from '@kit.ArkUI'; // 继承 UIAbility 导出一个 EntryAbility export default class EntryAbility extends UIAbility { // Ability 启动时 onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void { // 打印 Log hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onCreate'); } // Ability 关闭时 onDestroy(): void { // 打印 Log hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onDestroy'); } // Ability 主页面创建时 onWindowStageCreate(windowStage: window.WindowStage): void { // Main window is created, set main page for this ability // 打印 Log hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageCreate'); // 加载 Index 页面作为主页面 windowStage.loadContent('pages/Index', (err) => { if (err.code) { // 打印 Log hilog.error(0x0000, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err) ?? ''); return; } // 打印 Log hilog.info(0x0000, 'testTag', 'Succeeded in loading the content.'); }); } // Ability 主页面销毁时 onWindowStageDestroy(): void { // Main window is destroyed, release UI related resources // 打印 Log hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageDestroy'); } // Ability 切换前台时 onForeground(): void { // Ability has brought to foreground // 打印 Log hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onForeground'); } // Ability 切换后台时 onBackground(): void { // Ability has back to background // 打印 Log hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onBackground'); } }
-
-
-
MyApplication > src > main > ets > pages > Index.ets: 该文件主要用来实现页面的相关功能和界面渲染,示例页面非常简单只有一个文本组件显示 Hello World。代码中通过 @State 装饰器创建一个组件内的状态变量 message,这个变量作为参数传递给组件后,将能单向绑定组件,当状态变量修改时,也将驱动页面更新显示的内容。当然示例代码中并没有体现这个能力,只需稍微修改一下代码,即可实现点击切换文本的功能,具体代码请参考下方标注添加的代码,可以看到实现这样数据驱动界面变化的方式是非常直观和方便的。
@Entry // 页面入口装饰器 @Component // 组件装饰器 // 页面的结构体 struct Index { // @State 装饰器:组件内状态,可单向或双向绑定 UI,实现数据驱动界面变化,或界面驱动数据变化 @State message: string = 'Hello World'; // 页面构建函数 build() { // 相对布局容器 RelativeContainer() { // 文本组件, message 变量单向绑定该组件,当 message 修改时,UI 界面会同步修改 Text(this.message) // 组件 ID .id('HelloWorld') // 字体 .fontSize(50) // 字重 .fontWeight(FontWeight.Bold) // 对齐方式 .alignRules({ center: { anchor: '__container__', align: VerticalAlign.Center }, middle: { anchor: '__container__', align: HorizontalAlign.Center } }) // 添加点击事件 .onClick(() => { // 修改状态变量 message this.message = this.message === 'Hello World' ? 'Hello HarmonyOS' : 'Hello World'; }); } // 容器的宽高 .height('100%') .width('100%') } }
-
-