OpenHarmony开发者论坛
标题:
OpenHarmony系统之如何编写简单的hap程序
[打印本页]
作者:
深开鸿_胡瑞涛
时间:
2023-10-27 16:42
标题:
OpenHarmony系统之如何编写简单的hap程序
[md]## **OpenHarmony系统之如何编写简单的hap程序**
### 简介
HAP文件是在OpenHarmony系统下编译生成的可执行文件。HAP 包是由代码、资源、第三方库以及应用配置文件打包生成的模块包,主要分为两种类型:entry 和 feature。
> entry:应用的主模块,作为 OpenHarmony 应用的入口,提供了应用的基础功能。
> feature:应用的动态特性模块,作为应用能力的扩展,可以根据用户的需求和设备的类型进行选择性安装。
OpenHarmony 用户应用程序包可以只包含一个基础的 entry 包,也可以包含一个基础的 entry 包和一个或多个功能型的 feature 包。
### 工具
1. DevEco Studio 3.1
* HUAWEI DevEco Studio For OpenHarmony是基于IntelliJ IDEA Community开源版本打造,面向OpenHarmony全场景多设备的一站式集成开发环境(IDE),DevEco Studio 3.1配套支持HarmonyOS 3.1版本及以上的应用及服务开发,提供了代码智能编辑、低代码开发、双向预览等功能,以及轻量构建工具DevEco Hvigor 、本地模拟器,持续提升应用及服务开发效率。
* **下载链接:** [HUAWEI DevEco Studio和SDK下载和升级 | HarmonyOS开发者](
https://developer.harmonyos.com/ ... tudio#download_beta
)
* **安装步骤:** [工具简介-DevEco Studio使用指南-工具-HarmonyOS应用开发](
https://developer.harmonyos.com/ ... 3?catalogVersion=V3
)
**注:建议在选项界面都勾选DevEco Studio,Add “bin” folder to the PATH,Add “Open Folder as Project”**
* **配置开发环境:**[配置开发环境-快速开始-DevEco Studio使用指南-工具-HarmonyOS应用开发](
https://developer.harmonyos.com/ ... 3?catalogVersion=V3
)
### ArkTS
- ArkTS是OpenHarmony优选的主力应用开发语言。ArkTS围绕应用开发在TypeScript(简称TS)生态基础上做了进一步扩展,保持了TS的基本风格,使能静态类型。
- 基于TS扩展的声明式开发范式的方舟开发框架是一套开发极简、高性能、跨设备应用的UI开发框架,支持开发者高效的构建跨设备应用UI界面。
- 基于TS扩展的声明式开发范式提供了一系列基础组件,这些组件以声明方式进行组合和扩展来描述应用程序的UI界面,并且还提供了基本的数据绑定和事件处理机制,帮助开发者实现应用交互逻辑。
```html
@Entry //用@Entry装饰的自定义组件用作页面的默认入口组件,也可以理解为页面的根节点。 一个页面有且仅能有一个@Entry,只有被@Entry修饰的组件或者其子组件,才会在页面上显示。
@Component //@Component装饰的struct表示该结构体具有组件化能力,能够成为一个独立的组件,这种类型的组件也称为自定义组件,在build方法里描述UI结构。
struct Hello { //在声明式UI中,所有的页面都是由组件构成。组件的数据结构为struct
@State myText: string = 'World'
build() { //build函数用于定义组件的声明式UI描述,在build方法中以声明式方式进行组合自定义组件或系统内置组件。
Column() { //Column:沿垂直方向布局的容器。
Text('Hello') //Text:显示一段文本的组件。
.fontSize(30)
Text(this.myText)
.fontSize(32)
Divider() //Divider:提供分隔器组件,分隔不同内容块/内容元素。
Button() { //Button:按钮组件,可快速创建不同样式的按钮,通常用于响应用户的点击操作。
Text('Click me')
.fontColor(Color.Red)
}.onClick(() => {
this.myText = 'UI'
})
.width(500)
.height(200)
}
}
}
```
### 基本概念
* 装饰器:方舟开发框架定义了一些具有特殊含义的装饰器,用于装饰类、结构、方法和变量。装饰器就是某一种修饰,给被装饰的对象赋予某一种能力,比如@Entry就是页面入口的能力,@Component就是组件化能力。
* 自定义组件:可重用的UI单元,可以与其他组件组合,如@Component装饰的struct Hello。
* UI描述:声明性描述UI结构,例如build()方法中的代码块。
* 内置组件:框架中默认内置的基本组件和布局组件,开发者可以直接调用,仅用于解释UI描述规范。如Column、Text、Divider、Button等。
* 属性方法:用于配置组件属性,如fontSize()、width()、height()、color()等。
* 事件方法:在事件方法的回调中添加组件响应逻辑。例如,为Button组件添加onClick方法,在onClick方法的回调中添加点击响应逻辑。
### 应用
#### 1. 创建
* 在DevEco Studio的欢迎页,选择Create Project开始创建一个新工程。
* 根据工程创建向导,在OpenHarmony页签,选择“Empty Ability”模板,点击Next。
![img](
https://forums.openharmony.cn/fo ... es&type=fixnone
)
* 点击Next,各个参数保持默认值即可,点击Finish。
![img](
https://forums.openharmony.cn/fo ... es&type=fixnone
)
**关于各个参数的详细介绍,请参考**[创建一个新的工程-工程管理-DevEco Studio使用指南-工具-HarmonyOS应用开发](
https://developer.harmonyos.com/ ... 3?catalogVersion=V3
)
* **Project name:** 工程的名称,可以自定义。
* **Project type:** 工程的类型,标识该工程是一个传统方式的需要安装的应用(Application)或原子化服务(Atomic service),默认类型为Application。
* **Bundle name:** 软件包名称,默认情况下,应用ID也会使用该名称,应用发布时,应用ID需要唯一。如果“Project type”选择了Atomic service,则Bundle name的后缀名必须是.hmservice。
* **Save location:** 工程文件本地存储路径。
* **Compile SDK:** 编译的SDK版本。
* **Model:** 选择 Stage模型,[Stage模型应用程序包结构](
https://docs.openharmony.cn/page ... structure-stage.md/
)(Stage模型仅Compile API为9及以上支持)。
* **Enable Super Visual:** 选择开发模式,部分模板支持低代码开发,可选择打开该开关。
* **Language:** 开发语言。
* **Compatible SDK:** 兼容的SDK最低版本。
* **Device type:** 该工程模板支持的设备类型。
* **Show in service center:** 是否在服务中心露出。
* 工程创建完成后,DevEco Studio会自动进行工程的同步,同步成功如下图所示。
* 将搭载OpenHarmony标准系统的开发板与电脑连接。
* 点击File > Project Structure > Project > Signing Configs界面勾选“Automatically generate signature”,等待自动签名完成即可,点击“OK”。如下图所示:
* 为了保证OpenHarmony应用的完整性和来源可靠,在应用构建时需要对应用进行签名。经过签名的应用才能在真机设备上安装、运行、和调试。如果没有配置签名,会报错:hvigor WARN: Will skip sign ‘hap’,Invalid signingConfig is configured for ‘default’ product.
![#冲刺创作新星#[六]第一个hap应用-开源基础软件社区](
https://dl-harmonyos.51cto.com/i ... rocess=image/resize
,w_820,h_611 "#冲刺创作新星#[六]第一个hap应用-开源基础软件社区")
#### 2. 目录结构
* 新项目的目录结构
![#冲刺创作新星#[六]第一个hap应用-开源基础软件社区](
https://dl-harmonyos.51cto.com/i ... rocess=image/resize
,w_244,h_281 "#冲刺创作新星#[六]第一个hap应用-开源基础软件社区")
**entry**为应用的主模块,类似与Android Studio的app模块,一个APP中,对于同一设备类型必须有且只有一个entry类型的HAP,可独立安装运行。
* 使用**previewer**查看程序的预览图
点击View > Tool Windows > Project > Previewer 如下图所示:
* 方法一:
![#冲刺创作新星#[六]第一个hap应用-开源基础软件社区](
https://dl-harmonyos.51cto.com/i ... rocess=image/resize
,w_499,h_389 "#冲刺创作新星#[六]第一个hap应用-开源基础软件社区")
* 方法二:
![#冲刺创作新星#[六]第一个hap应用-开源基础软件社区](
https://dl-harmonyos.51cto.com/i ... rocess=image/resize
,w_277,h_134 "#冲刺创作新星#[六]第一个hap应用-开源基础软件社区")
* 成功预览后会生成.preview结构:
![#冲刺创作新星#[六]第一个hap应用-开源基础软件社区](
https://dl-harmonyos.51cto.com/i ... rocess=image/resize
,w_260,h_97 "#冲刺创作新星#[六]第一个hap应用-开源基础软件社区")
* 使用**build**编译程序
点击Build > Rebuild 进行编译; Build > Build Hap(s) /App(s) >Build Hap(s) 生成hap文件
![#冲刺创作新星#[六]第一个hap应用-开源基础软件社区](
https://dl-harmonyos.51cto.com/i ... rocess=image/resize
,w_295,h_139 "#冲刺创作新星#[六]第一个hap应用-开源基础软件社区")
* hap文件的生成路径:entry/build/outpus/default
![#冲刺创作新星#[六]第一个hap应用-开源基础软件社区](
https://dl-harmonyos.51cto.com/i ... rocess=image/resize
,w_336,h_221 "#冲刺创作新星#[六]第一个hap应用-开源基础软件社区")
* **目录结构中文件分类如下:**
.ets结尾的eTS(extended TypeScript)文件,用于描述UI布局、样式、事件交互和页面逻辑。
**各个文件夹和文件的作用:**
* **app.ets**文件用于全局应用逻辑和应用生命周期管理。
* **pages**目录用于存放所有组件页面。
* **common**目录用于存放公共代码文件,比如:自定义组件和公共方法。
> **说明:**
>
> * 资源目录resources文件夹位于src/main下,此目录下资源文件的详细规范以及子目录结构规范参看[UI开发,ArkTS声明式开发范式](
https://docs.openharmony.cn/page ... opment-overview.md/
)。
> * 页面支持导入TypeScript和JavaScript文件。
#### 3. 基础组件应用
* 如上所说,基于TS扩展的声明式开发范式提供了一系列基础组件,如:基础组件,容器组件,媒体组件,绘制组件和画布组件等,本节我们主要使用容器组件。
* list列表包含一系列相同宽度的列表项。适合连续、多行呈现同类数据,例如图片和文本。
* listitem用来展示列表具体item,宽度默认充满List组件,必须配合List来使用。
* text可以显示一段文本。
编写一个简单的ui界面,其homepage为:
```html
import ConfigData from '../../Utils/ConfigData';
import {SubEntryComponent} from '../../component/subEntryComponent';
@Entry
@Component
struct HomePage {
@State message: string = 'The Test'
build() {
Column(){
GridContainer({columns:12, sizeType: SizeType.Auto, gutter: vp2px(1) === 2 ? '12vp' : '0vp', margin: vp2px(1) === 2 ? '24vp' : '0vp'}) {
Row({}) {
Column() {}
.width(ConfigData.WH_100_100)
.height(ConfigData.WH_100_100)
.useSizeType({
xs: { span: 0, offset: 0 }, sm: { span: 0, offset: 0 },
md: { span: 0, offset: 0 }, lg: { span: 2, offset: 0 }
});
Column() {
Text(this.message)
.fontSize($r("app.float.font_30"))
.lineHeight($r("app.float.lineHeight_41"))
.fontWeight(FontWeight.Bold)
.fontFamily('HarmonyHeiTi')
.textAlign(TextAlign.Start)
.width(ConfigData.WH_100_100)
.padding({left: $r('app.float.distance_26'), top: $r('app.float.distance_12'), bottom: $r('app.float.distance_17')})
Column({space:'16vp'}){
List(){
ListItem(){ SubEntryComponent({targetPage:"pages/test1",title
r("app.string.test1")})
}
.padding({top: $r('app.float.distance_2'), bottom: $r('app.float.distance_2')})
ListItem(){ SubEntryComponent({targetPage:"pages/test2",title
r("app.string.test2")})
}
.padding({top: $r('app.float.distance_2'), bottom: $r('app.float.distance_2')})
ListItem(){
SubEntryComponent({targetPage:"pages/test3",title
r("app.string.test3")})
}
.padding({top: $r('app.float.distance_2'), bottom: $r('app.float.distance_2')})
ListItem(){
SubEntryComponent({targetPage:"pages/test4",title
r("app.string.test4")})
}
.padding({top: $r('app.float.distance_2'), bottom: $r('app.float.distance_2')})
}
}
.width(ConfigData.WH_100_100)
}
.padding({left: $r('app.float.distance_24'), right: $r('app.float.distance_24')})
.width(ConfigData.WH_100_100)
.height(ConfigData.WH_100_100)
.useSizeType({
xs: { span: 12, offset: 0 }, sm: { span: 12, offset: 0 },
md: { span: 12, offset: 0 }, lg: { span: 8, offset: 2 }
});
Column() {}
.width(ConfigData.WH_100_100)
.height(ConfigData.WH_100_100)
.useSizeType({
xs: { span: 0, offset: 12 }, sm: { span: 0, offset: 12 },
md: { span: 0, offset: 12 }, lg: { span: 2, offset: 10 }
})
}
.width(ConfigData.WH_100_100)
.height(ConfigData.WH_100_100);
}
.width(ConfigData.WH_100_100)
.height(ConfigData.WH_100_100);
}
.backgroundColor($r("sys.color.ohos_id_color_sub_background"))
.width(ConfigData.WH_100_100)
.height(ConfigData.WH_100_100);
}
}
```
* 调用的subEntryComponent为:
```html
import ConfigData from '../Utils/ConfigData';
@Component
export struct SubEntryComponent{
private targetPage: string;
private title:string | Resource;
@State isTouched:boolean = false;
private date: any = null;
private deviceId: any = null;
build() {
Navigator({target: this.targetPage}){
Flex({ justifyContent: FlexAlign.SpaceBetween, alignItems:ItemAlign.Center }) {
Row() {
Text(this.title)
.fontSize($r('app.float.font_30'))
.lineHeight($r('app.float.wh_value_32'))
.fontColor($r('app.color.font_color_182431'))
.fontWeight(FontWeight.Medium)
.margin({left: $r('app.float.distance_8')})
.textAlign(TextAlign.Start)
.height($r('app.float.wh_value_32'));
}
Image(('app.media.ic_settings_arrow'))
.width($r('app.float.wh_value_12'))
.height($r('app.float.wh_value_100'))
.margin({right: $r('app.float.distance_8')});
}
.height(ConfigData.WH_100_100)
.width(ConfigData.WH_100_100)
.borderRadius($r('app.float.radius_12'))
.linearGradient(this.isTouched ? {
angle: 90,
direction: GradientDirection.Right,
colors: [[$r("app.color.DCEAF9"), 0.0], [$r("app.color.FAFAFA"), 1.0]]
} : {
angle: 90,
direction: GradientDirection.Right,
colors: [[$r("sys.color.ohos_id_color_foreground_contrary"), 1], [$r("sys.color.ohos_id_color_foreground_contrary"), 1]]})
.onTouch((event: TouchEvent) => {
if (event.type === TouchType.Down) {
this.isTouched = true;
}
if (event.type === TouchType.Up) {
this.isTouched = false;
}
})
}
.params( {date: this.date, deviceId: this.deviceId} )
.padding($r('app.float.distance_4'))
.height($r('app.float.wh_value_100'))
.borderRadius($r('app.float.radius_24'))
.backgroundColor($r("sys.color.ohos_id_color_foreground_contrary"));
}
}
```
* 预览图:
![#冲刺创作新星#[六]第一个hap应用-开源基础软件社区](
https://dl-harmonyos.51cto.com/i ... rocess=image/resize
,w_226,h_481 "#冲刺创作新星#[六]第一个hap应用-开源基础软件社区")
#### 4. 界面跳转
在实现界面跳转时一般需要用到targetPage或者router:url方法。
* targetpage方法
```html
targetpage:"{页面路径}"
```
* router方法
```html
定义:
const 'NAME' = '路径';
实现:
Router.push({ uri: PAGE_URI_TEST_NAME });
```
* js标签配置
开发框架需要应用的config.json中配置相关的js标签,其中包含了实例名称、页面路由、视图窗口配置信息。pages定义每个页面入口组件的路由信息,每个页面由页面路径和页面名组成,页面的文件名就是页面名。比如:
![#冲刺创作新星#[六]第一个hap应用-开源基础软件社区](
https://dl-harmonyos.51cto.com/i ... rocess=image/resize
,w_315,h_286 "#冲刺创作新星#[六]第一个hap应用-开源基础软件社区")
> **说明:**
>
> * pages列表中第一个页面为应用的首页入口。
> * 页面文件名不能使用组件名称,比如:Text.ets、Button.ets等。
> * 每个页面文件中必须包含页面入口组件(@Entry装饰)。
* 预览图:
![#冲刺创作新星#[六]第一个hap应用-开源基础软件社区](
https://dl-harmonyos.51cto.com/i ... rocess=image/resize
,w_612,h_482 "#冲刺创作新星#[六]第一个hap应用-开源基础软件社区")
#### 5. api组件
* 在基于TS扩展的声明式开发范式中有众多的API参考,初学者可以使用这些组件练习,以此来加深对ets的熟悉。如:
```html
// 提供在给定范围内选择评分的组件
@Entry
@Component
struct RatingExample {
@State rating: number = 1
@State indicator: boolean = false
build() {
Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.SpaceBetween }) {
Text('current score is ' + this.rating).fontSize(20)
Rating({ rating: this.rating, indicator: this.indicator })
.stars(5)
.stepSize(0.5)
.onChange((value: number) => {
this.rating = value
})
}.width(350).height(200).padding(35)
}
}
```
* 预览图:
![#冲刺创作新星#[六]第一个hap应用-开源基础软件社区](
https://dl-harmonyos.51cto.com/i ... rocess=image/resize
,w_215,h_243 "#冲刺创作新星#[六]第一个hap应用-开源基础软件社区")
#### 6. 自定义组件
组件的成员变量可以通过两种方式初始化:
* 本地初始化,如:
```html
@State counter: Counter = new Counter()
ts
```
* 在构造组件时通过构造参数初始化,如:
```html
MyComponent({counter: $myCounter})
```
如可以使用CustomDialogController类显示自定义弹窗
* 导入对象
```html
dialogController : CustomDialogController = new CustomDialogController(value:{builder: CustomDialog, cancel?: () => void, autoCancel?: boolean})
```
* 使用open()和close()对其进行开关显示。
open(): void
显示自定义弹窗内容,若已显示,则不生效。
close(): void
关闭显示的自定义弹窗,若已关闭,则不生效。
* 示例:
```html
class ClassA {
public a:number
constructor(a: number) {
this.a = a
}
}
@Entry
@Component
struct Parent {
@State parentState: ClassA = new ClassA(1)
build() {
Column() {
Flex({ justifyContent: FlexAlign.Start, alignItems: ItemAlign.Center }) {
CompA({ aState: new ClassA(2), aLink: $parentState })
}
Flex({ justifyContent: FlexAlign.Start, alignItems: ItemAlign.Center }) {
CompA({ aLink: $parentState })
}
Flex({ justifyContent: FlexAlign.Start, alignItems: ItemAlign.Center }) {
CompA({ aState: new ClassA(3), aLink: $parentState })
}
}
}
}
@Component
struct CompA {
@State aState: any = false
@Link aLink: ClassA
build() {
Column() {
CompB({ bLink: $aLink, bProp: this.aState })
CompB({ bLink: $aState, bProp: false })
}
}
}
@Component
struct CompB {
@Link bLink: ClassA
@Prop bProp: boolean
build() {
Flex({ justifyContent: FlexAlign.Start, alignItems: ItemAlign.Center }) {
Text(JSON.stringify(this.bLink.a)).fontSize(30)
Text(JSON.stringify(this.bProp)).fontSize(30).fontColor(Color.Red)
}.margin(10)
}
}
```
**总结**
ArkTS是一种为构建高性能应用而设计的编程语言。ArkTS在继承TypeScript语法的基础上进行了优化,以提供更高的性能和开发效率。ArkTS提供对方舟开发框架ArkUI的声明式语法和其他特性的支持。
[/md]
欢迎光临 OpenHarmony开发者论坛 (https://forums.openharmony.cn/)
Powered by Discuz! X3.5