zl程序教程

您现在的位置是:首页 >  APP

当前栏目

跟着小白一起学鸿蒙之第一个Hap应用(六)

2023-02-25 18:05:04 时间

​想了解更多关于开源的内容,请访问:​

​51CTO 开源基础软件社区​

​https://ost.51cto.com​

简介

HAP文件是在OpenHarmony系统下编译生成的可执行文件。HAP 包是由代码、资源、第三方库以及应用配置文件打包生成的模块包,主要分为两种类型:entry 和 feature。

entry:应用的主模块,作为 OpenHarmony 应用的入口,提供了应用的基础功能。
feature:应用的动态特性模块,作为应用能力的扩展,可以根据用户的需求和设备的类型进行选择性安装。

OpenHarmony 用户应用程序包可以只包含一个基础的 entry 包,也可以包含一个基础的 entry 包和一个或多个功能型的 feature 包。

工具

  1. DevEco Studio 3.0 Beta4
  • HUAWEI DevEco Studio For OpenHarmony是基于IntelliJ IDEA Community开源版本打造,面向OpenHarmony全场景多设备的一站式集成开发环境(IDE),DevEco Studio 3.0支持在HarmonyOS 3.0 Beta版上开发应用及服务,并已适配ArkUI声明式编程范式、ArkCompiler方舟编译,同时提供低代码开发、双向预览、全新构建工具、模拟器、调试调优、信息中心等功能,为开发者提供工程模板创建、开发、编译、调试、发布等E2E的OpenHarmony应用/服务开发。
  • 下载链接:​​HUAWEI DevEco Studio和SDK下载和升级 | HarmonyOS开发者​​。
  1. 安装步骤:​​下载与安装软件-快速开始-HUAWEI DevEco Studio For OpenHarmony使用指南-工具-HarmonyOS应用开发 | HarmonyOS​​​。
    注:建议在选项界面都勾选DevEco Studio,Add “bin” folder to the PATH,Add “Open Folder as Project”
  2. 配置开发环境:​​配置开发环境-快速开始-HUAWEI DevEco Studio For OpenHarmony使用指南-工具-HarmonyOS应用开发 | HarmonyOS​​。

ETS

  • 基于TS扩展的声明式开发范式的方舟开发框架是一套开发极简、高性能、跨设备应用的UI开发框架,支持开发者高效的构建跨设备应用UI界面。
  • 基于TS扩展的声明式开发范式提供了一系列基础组件,这些组件以声明方式进行组合和扩展来描述应用程序的UI界面,并且还提供了基本的数据绑定和事件处理机制,帮助开发者实现应用交互逻辑。
@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。

#冲刺创作新星# #跟着小白一起学鸿蒙#[六]第一个hap应用-开源基础软件社区

点击Next,各个参数保持默认值即可,点击Finish。

#冲刺创作新星# #跟着小白一起学鸿蒙#[六]第一个hap应用-开源基础软件社区

关于各个参数的详细介绍,请参考​​​创建OpenHarmony工程-工程管理-HUAWEI DevEco Studio For OpenHarmony使用指南-工具-HarmonyOS应用开发 | HarmonyOS​​。

  • 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:选择​FA模型​​​或​​Stage模型​​(Stage模型仅Compile API为9及以上支持)。
  • Enable Super Visual:选择开发模式,部分模板支持低代码开发,可选择打开该开关。
  • **Language:**开发语言。
  • Compatible SDK:兼容的SDK最低版本。
  • Device type:该工程模板支持的设备类型。
  • **Show in service center:**是否在服务中心露出。
  • 工程创建完成后,DevEco Studio会自动进行工程的同步,同步成功如下图所示。

#冲刺创作新星# #跟着小白一起学鸿蒙#[六]第一个hap应用-开源基础软件社区将搭载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应用-开源基础软件社区

2、目录结构

新项目的目录结构:

#冲刺创作新星# #跟着小白一起学鸿蒙#[六]第一个hap应用-开源基础软件社区

entry为应用的主模块,类似与Android Studio的app模块,一个APP中,对于同一设备类型必须有且只有一个entry类型的HAP,可独立安装运行。

使用previewer查看程序的预览图。

点击View > Tool Windows > Project > Previewer 如下图所示:

方法一:

#冲刺创作新星# #跟着小白一起学鸿蒙#[六]第一个hap应用-开源基础软件社区

方法二:

#冲刺创作新星# #跟着小白一起学鸿蒙#[六]第一个hap应用-开源基础软件社区#冲刺创作新星# #跟着小白一起学鸿蒙#[六]第一个hap应用-开源基础软件社区

成功预览后会生成.preview结构:

#冲刺创作新星# #跟着小白一起学鸿蒙#[六]第一个hap应用-开源基础软件社区#冲刺创作新星# #跟着小白一起学鸿蒙#[六]第一个hap应用-开源基础软件社区

使用build编译程序。

点击Build > Rebuild 进行编译; Build > Build Hap(s) /App(s) >Build Hap(s) 生成hap文件。

#冲刺创作新星# #跟着小白一起学鸿蒙#[六]第一个hap应用-开源基础软件社区

hap文件的生成路径:entry/build/outpus/default。

#冲刺创作新星# #跟着小白一起学鸿蒙#[六]第一个hap应用-开源基础软件社区

目录结构中文件分类如下:

.ets结尾的eTS(extended TypeScript)文件,用于描述UI布局、样式、事件交互和页面逻辑。各个文件夹和文件的作用:

  • app.ets文件用于全局应用逻辑和应用生命周期管理。
  • pages目录用于存放所有组件页面。
  • common目录用于存放公共代码文件,比如:自定义组件和公共方法。

说明:

  • 资源目录resources文件夹位于src/main下,此目录下资源文件的详细规范以及子目录结构规范参看​​资源文件的分类​​。
  • 页面支持导入TypeScript和JavaScript文件。

3、基础组件应用

  • 如上所说,基于TS扩展的声明式开发范式提供了一系列基础组件,如:基础组件,容器组件,媒体组件,绘制组件和画布组件等,本节我们主要使用容器组件。
  • list列表包含一系列相同宽度的列表项。适合连续、多行呈现同类数据,例如图片和文本。
  • listitem用来展示列表具体item,宽度默认充满List组件,必须配合List来使用。
  • text可以显示一段文本。
    编写一个简单的ui界面,其homepage为:
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为:

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应用-开源基础软件社区

4、界面跳转

在实现界面跳转时一般需要用到targetPage或者router:url方法。

  • targetpage方法
targetpage:"{页面路径}"
  • router方法
定义:
const 'NAME' = '路径';
实现:
Router.push({ uri: PAGE_URI_TEST_NAME });
  • js标签配置
    开发框架需要应用的config.json中配置相关的js标签,其中包含了实例名称、页面路由、视图窗口配置信息。pages定义每个页面入口组件的路由信息,每个页面由页面路径和页面名组成,页面的文件名就是页面名。比如:

#冲刺创作新星# #跟着小白一起学鸿蒙#[六]第一个hap应用-开源基础软件社区#冲刺创作新星# #跟着小白一起学鸿蒙#[六]第一个hap应用-开源基础软件社区

说明:

  • pages列表中第一个页面为应用的首页入口。
  • 页面文件名不能使用组件名称,比如:Text.ets、Button.ets等。
  • 每个页面文件中必须包含页面入口组件(@Entry装饰)。
  • 预览图:

#冲刺创作新星# #跟着小白一起学鸿蒙#[六]第一个hap应用-开源基础软件社区

5、api组件

  • 在基于TS扩展的声明式开发范式中有众多的API参考,初学者可以使用这些组件练习,以此来加深对ets的熟悉。如:
// 提供在给定范围内选择评分的组件
@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应用-开源基础软件社区#冲刺创作新星# #跟着小白一起学鸿蒙#[六]第一个hap应用-开源基础软件社区

6、自定义组件

组件的成员变量可以通过两种方式初始化:

本地初始化,如:

@State counter: Counter = new Counter()
ts

在构造组件时通过构造参数初始化,如:

MyComponent({counter: $myCounter})

如可以使用CustomDialogController类显示自定义弹窗。

导入对象。

dialogController : CustomDialogController = new CustomDialogController(value:{builder: CustomDialog, cancel?: () => void, autoCancel?: boolean})

使用open()和close()对其进行开关显示。

open(): void显示自定义弹窗内容,若已显示,则不生效。

close(): void关闭显示的自定义弹窗,若已关闭,则不生效。

示例:

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)
}
}

GITEE路径:
https://gitee.com/wshikh/ohosexample.git。

​想了解更多关于开源的内容,请访问:​

​51CTO 开源基础软件社区​

​https://ost.51cto.com​​。