因为OpenHarmony API 9开始新增的Stage模型,是目前主推且会长期演进的模型。 所以后面会全部使用Stage模型进行开发
DevEco是基于inteliJ开源项目进行开发的,所以和Android Studio基本一样。
开发工具整体来看和Android Studio基本类似。
直接下载安装即可。 整个使用和Android Studio基本一样。
接下来通过Create Project创建一个新项目。 这里选Empty Ablity的就可以。
Ability:应用的基本组成部分,是应用所具备能力的抽象。Ability是系统调度应用的最小单元,是能够完成一个独立功能的组件,一个应用可以包含一个或多个Ability。 在FA模型与Stage模型,分别定义了不同类型的Ability。
鸿蒙应用实际是通过Ability框架进行开发的,Ability在英文解释中是能力的意思。鸿蒙认为开发一个应用程序,其实是对设备能力的一种实现。
Ability是应用所具备能力的抽象,也是应用程序的重要组成部分。一个应用可以具备多种能力(即可以包含多个Ability),HarmonyOS支持应用以Ability为单位进行部署。
接下来就是和Android Studio一样,填项目名、Bundle name就是包名,是应用程序的唯一标识,一般用公司的域名 com.huawei.xxx这样。
Compatible SDK目前最新的就是API 9.
这里有个Enable Super Visual,这是一种低代码的开发模式,对于一些简单的app可以使用,一般不用使用。
接着就能看到整个项目的目录:
从上往下看:
-
AppScode中存放应用全局所需要的资源文件:
- AppScope下的app.json5 :应用的全局配置信息,存放应用公共的配置信息。例如: bundleName、versionName、icon、appName等。
- resource -> base -> element: 存放公众的字符串、布局文件等资源。
- resource -> base -> media: 全局公共的多媒体资源文件。
{
"app": {
"bundleName": "com.example.harmonyapp",
"vendor": "example",
"versionCode": 1000000,
"versionName": "1.0.0",
"icon": "$media:app_icon",
"label": "$string:app_name"
}
}
-
entry:应用的主模块,存放Harmony OS应用的代码、资源等。编译构建生成一个HAP包。
- oh-package.json5: 工程级依赖配置文件,用于记录引入包的配置信息。
- src > main > ets:用于存放ArkTS源码。下面又分为entryability:应用/服务的入口和pages:应用/服务包含的页面。
- src > main > resources:用于存放应用/服务所用到的资源文件,如图形、多媒体、字符串、布局文件等。关于资源文件,详见资源文件的分类。
- src > main > module.json5:模块配置文件。主要包含HAP包的配置信息、应用/服务在具体设备上的配置信息以及应用/服务的全局配置信息。
{
"module": {
"name": "entry",
"type": "entry",
"description": "$string:module_desc",
"mainElement": "EntryAbility",
"deviceTypes": [
"phone",
"tablet"
],
"deliveryWithInstall": true,
"installationFree": false,
"pages": "$profile:main_pages",
"abilities": [
{
"name": "EntryAbility",
"srcEntry": "./ets/entryability/EntryAbility.ts",
"description": "$string:EntryAbility_desc",
"icon": "$media:icon",
"label": "$string:EntryAbility_label",
"startWindowIcon": "$media:icon",
"startWindowBackground": "$color:start_window_background",
"exported": true,
"skills": [
{
"entities": [
"entity.system.home"
],
"actions": [
"action.system.home"
]
}
]
}
]
}
}
每个应用项目的代码目录下必须包含应用配置文件,这些配置文件会向编译工具、操作系统和应用市场提供应用的基本信息。
在基于Stage模型开发的应用项目代码下,都存在一个app.json5配置文件、以及一个或多个module.json5配置文件。
app.json5(应用的全局配置文件)配置文件主要包含以下内容:
-
应用的全局配置信息,包含应用的Bundle名称、开发厂商、版本号等基本信息。
-
特定设备类型的配置信息。
module.json5(模块的配置文件)配置文件主要包含以下内容:
-
Module的基本配置信息,包含Module名称、类型、描述、支持的设备类型等基本信息。
-
应用组件信息,包含UIAbility组件和ExtensionAbility组件的描述信息。
-
应用运行过程中所需的权限信息。
-
build-profile.json5:当前的模块信息 、编译信息配置项,包括buildOption、targets配置等。
{
"apiType": 'stageMode',
"buildOption": {
},
"targets": [
{
"name": "default",
"runtimeOS": "HarmonyOS"
},
{
"name": "ohosTest",
}
]
}
-
hvigorfile.ts:工程级编译构建任务脚本,hvigor是基于任务管理机制实现的一款全新的自动化构建工具,主要提供任务注册编排,工程模型管理、配置管理等核心能力。
-
obfuscation-rules.txt:混淆规则文件。混淆开启后,在使用Release模式进行编译时,会对代码进行编译、混淆及压缩处理,保护代码资产。
-
build-profile.json5:工程级级配置信息,包括签名signingConfigs、产品配置products等。
-
hvigorfile.ts:应用级编译构建任务脚本。
-
oh_modules:工程的依赖包,存放工程依赖的源文件。
-
src/main/resources/base/profile/main_pages.json: 保存的是页面page的路径配置信息,所有需要进行路由跳转的page页面都要在这里进行配置。
HarmonyOS的用户应用程序包以App Pack(Application Package)形式发布,它由一个或多个HAP(HarmonyOS Ability Package)以及描述每个HAP属性的pack.info组成。HAP是Ability的部署包,HarmonyOS应用代码围绕Ability组件展开。
很多应用由多个页面组成,比如用户可以从音乐列表页面单击歌曲,跳转到该歌曲的播放界面。开发者需要通过页面路由将这些页面串联起来,按需实现跳转。
装饰器:方舟开发框架定义了一些具有特殊含义的装饰器,用于装饰类、结构、方法和变量。例如,上例中的@Entry、@Component和@State都是装饰器。
import router from '@ohos.router'
// 装饰的自定义组件用作页面的默认入口组件,加载页面时,将首先创建并呈现@Entry装饰的自定义组件
@Entry
// 装饰的struct表示该接口提具有组件化能力,能够成为一个独立的组件
@Component
// 自定义组件内容
struct Index {
// @State装饰的变量是组件内部的状态数据,当状态数据被修改时,会自动进行UI刷新
@State message: string = 'Hello World'
// 自定义组件必须定义build方法,在其中以声明式的方式进行UI描述
build() {
// ArkUI提供的容器行组件
Row() {
// ArkUI提供的容器列组件
Column() {
// ArkUI提供的容器基础组件,如文字、字体大小、字体加粗
Text(this.message)
// 设置组件UI样式的属性方法
.fontSize(50)
.fontWeight(FontWeight.Bold)
// 添加按钮,以响应用户点击
Button() {
// 按钮文案、文字大小颜色、样式
Text('戳我')
.fontSize(40)
.fontColor(Color.Red)
// 比粗体更粗
.fontWeight(FontWeight.Bolder)
}.type(ButtonType.Capsule) // 按钮风格: 胶囊型按钮(圆角默认为高度的一半)
.margin({
// 距离上一个的高度
top: 20
})
.onClick(() => {
// 跳转到第二个页面
// 页面路由router根据页面的uri找到目标页面,从而实现跳转。
// 这个url路径就是main_pages.json中配置的路径
router.pushUrl({url: 'pages/Second'}).then(() => {
console.info('start second page')
})
})
.backgroundColor('#0D9FFB')
.width('40%')
.height('5%')
}
// 列布局的宽为屏幕宽度
.width('100%')
}
// 行布局的高度为屏幕高度
.height('100%')
}
}
ArkTS通过装饰器@Component和@Entry装饰struct关键字声明的数据结构,构成一个自定义组件。自定义组件中提供了一个build函数,开发者需在该函数内以链式调用的方式进行基本的UI描述.
- 装饰器: 用于装饰类、结构、方法以及变量,并赋予其特殊的含义。 如上述示例中@Entry、@Component和@State都是装饰器,@Component表示自定义组件,@Entry表示该自定义组件为入口组件,@State表示组件中的状态变量,状态变量变化会触发UI刷新。
- UI描述:以声明式的方式来描述UI的结构,例如build()方法中的代码块。
- 自定义组件:可复用的UI单元,可组合其他组件,如上述被@Component装饰的struct Hello。
- 系统组件:ArkUI框架中默认内置的基础和容器组件,可直接被开发者调用,比如示例中的Column、Text、Divider、Button。
- 属性方法:组件可以通过链式调用配置多项属性,如fontSize()、width()、height()、backgroundColor()等。
- 事件方法:组件可以通过链式调用设置多个事件的响应逻辑,如跟随在Button后面的onClick()。
- 系统组件、属性方法、事件方法具体使用可参考基于ArkTS的声明式开发范式。
下面新加一个页面Second.ets。 新加页面之后需要在resource-base-profile-main_pages.json文件中增加Second.ets页面的配置:
{
"src": [
"pages/Index",
"pages/Second"
]
}
下面写第二个页面的内容:
// router 需要导包,写router后会自动导入
import router from '@ohos.router'
@Entry
@Component
struct Second {
// 注意string是小写,不是String
@State message: string = "Hello HarmonyOS"
build() {
Row() {
Column() {
Text(this.message)
.fontSize(50)
.fontWeight(FontWeight.Bold)
Button() {
Text('Back')
.fontSize(25)
.fontWeight(FontWeight.Bold)
}
.type(ButtonType.Capsule)
.margin({
top: 20
})
.backgroundColor('#0D9FFB')
.width('40%')
.height('5%')
.onClick(() => {
// 点击按钮返回上一个页面
router.back();
})
}
.width('100%')
}
.height('100%')
}
}
在开发态,一个应用包含一个或者多个Module,可以在DevEco Studio工程中创建一个或者多个Module。Module是应用/服务的基本功能单元,包含了源代码、资源文件、第三方库及应用/服务配置文件,每一个Module都可以独立进行编译和运行。
Module分为“Ability”和“Library”两种类型,“Ability”类型的Module对应于编译后的HAP(Harmony Ability Package);“Library”类型的Module对应于HAR(Harmony Archive),或者HSP(Harmony Shared Package)。 一个Module可以包含一个或多个UIAbility组件
-
开发者通过DevEco Studio把应用程序编译为一个或者多个.hap后缀的文件,即HAP。HAP是应用安装的基本单位,包含了编译后的代码、资源、三方库及配置文件。HAP可分为Entry和Feature两种类型。
- Entry类型的HAP:是应用的主模块,在module.json5配置文件中的type标签配置为“entry”类型。在同一个应用中,同一设备类型只支持一个Entry类型的HAP,通常用于实现应用的入口界面、入口图标、主特性功能等。
- Feature类型的HAP:是应用的动态特性模块,在module.json5配置文件中的type标签配置为“feature”类型。一个应用程序包可以包含一个或多个Feature类型的HAP,也可以不包含;Feature类型的HAP通常用于实现应用的特性功能,可以配置成按需下载安装,也可以配置成随Entry类型的HAP一起下载安装(请参见module对象内部结构中的“deliveryWithInstall”)。
-
每个应用可以包含多个.hap文件,一个应用中的.hap文件合在一起称为一个Bundle,而bundleName就是应用的唯一标识(请参见app.json5配置文件中的bundleName标签)。需要特别说明的是:在应用上架到应用市场时,需要把应用包含的所有.hap文件(即Bundle)打包为一个.app后缀的文件用于上架,这个.app文件称为App Pack(Application Package),其中同时包含了描述App Pack属性的pack.info文件;在云端分发和端侧安装时,都是以HAP为单位进行分发和安装的。
多HAP使用规则:
-
App Pack包不能直接安装到设备上,只是上架应用市场的单元。
-
App Pack包打包时会对每个HAP在json文件中的配置进行校验,确保bundleName、versionCode等标签取值相同,详见App打包时的HAP合法性校验。
-
App Pack包中同一设备类型的所有HAP中必须有且只有一个Entry类型的HAP,Feature类型的HAP可以有一个或者多个,也可以没有。
-
App Pack包中的每个HAP必须配置moduleName标签,同一设备类型的所有HAP对应的moduleName标签必须唯一。
-
同一应用的所有HAP签名证书要保持一致。上架应用市场是以App Pack的形式上架,并对其进行了签名。应用市场分发时会将所有HAP从App Pack中拆分出来,同时对其中的所有HAP进行重签名,这样保证了所有HAP签名证书的一致性。在调试阶段,开发者通过命令行或IDE将HAP安装到设备上时要保证所有HAP签名证书一致,否则会出现安装失败的问题。
当前系统提供了两种共享包,HAR(Harmony Archive)静态共享包和HSP(Harmony Shared Package)动态共享包:
- HAR(Harmony Archive)是静态共享包,可以包含代码、C++库、资源和配置文件。通过HAR可以实现多个模块或多个工程共享ArkUI组件、资源等相关代码。HAR不同于HAP,不能独立安装运行在设备上,只能作为应用模块的依赖项被引用。
- HSP(Harmony Shared Package)是动态共享包,按照使用场景可以分为应用内HSP和应用间HSP。应用内HSP指的是专门为某一应用开发的HSP,只能被该应用内部其他HAP/HSP使用,用于应用内部代码、资源的共享。应用内HSP跟随其宿主应用的APP包一起发布,与宿主应用同进程,具有相同的包名和生命周期。(当前暂不支持应用间HSP)
HAR与HSP都是为了实现代码和资源的共享,都可以包含代码、C++库、资源和配置文件,最大的不同之处在于:HAR中的代码和资源跟随使用方编译,如果有多个使用方,它们的编译产物中会存在多份相同拷贝;而HSP中的代码和资源可以独立编译,运行时在一个进程中代码也只会存在一份。
HSP旨在解决多个模块引用相同的HAR,导致APP包大小膨胀的问题。
使用HSP的约束条件:
- HSP及其使用方都必须是Stage模型。
- HSP及其使用方都必须使用esmodule编译模式。
- HSP不支持在配置文件中声明abilities、extensionAbilities标签。
在HAR中也可以包含C++编写的so。对于so中的native方法,HAR通过以下方式导出,以导出libnative.so的加法接口add为例:
// library/src/main/ets/utils/nativeTest.ts
import native from "libnative.so"
export function nativeAdd(a: number, b: number) {
let result: number = native.add(a, b);
return result;
}
对于应用资源,在工程中,通过"$r('app.type.name')"形式引用。其中,app为应用内resources目录中定义的资源;type为资源类型或资源的存放位置,取值包含“color”、“float”、“string”、“plural”、“media”;name为资源命名,由开发者定义资源时确定。
对于rawfile目录资源,通过"$rawfile('filename')"形式引用。其中,filename为rawfile目录下文件的相对路径,文件名需要包含后缀,路径开头不可以以"/"开头。
对于rawfile目录的descriptor,可通过资源管理的getRawFd接口引用,其返回值descriptor.fd为hap包的fd。此时,访问rawfile文件需要结合{fd, offset, length}一起使用。
说明:
-
资源描述符不能拼接使用,仅支持普通字符串如'app.type.name'。
-
$r返回值为Resource对象,可通过getStringValue 方法获取对应的字符串。
资源组目录下的“资源文件示例”显示了.json文件内容,包含color.json文件、string.json文件和plural.json文件,访问应用资源时需先了解.json文件的使用规范。 资源的具体使用方法如下:
Text($r('app.string.string_hello'))
.fontColor($r('app.color.color_hello'))
.fontSize($r('app.float.font_hello'))
Text($r('app.string.string_world'))
.fontColor($r('app.color.color_world'))
.fontSize($r('app.float.font_world'))
// 引用string.json资源。Text中$r的第一个参数指定string资源,第二个参数用于替换string.json文件中的%s。
//如下示例代码value为"We will arrive at five of the clock"。
Text($r('app.string.message_arrive', "five of the clock"))
.fontColor($r('app.color.color_hello'))
.fontSize($r('app.float.font_hello'))
// 引用plural$资源。Text中$r的第一个指定plural资源,第二个参数用于指定单复数(在中文,单复数均使用other。在英文,one:代表单数,取值为1;other:代表复数,取值为大于等于1的整数),第三个参数用于替换%d
// 如下示例代码为复数,value为"5 apples"。
Text($r('app.plural.eat_apple', 5, 5))
.fontColor($r('app.color.color_world'))
.fontSize($r('app.float.font_world'))
Image($r('app.media.my_background_image')) // media资源的$r引用
Image($rawfile('test.png')) // rawfile$r引用rawfile目录下图片
Image($rawfile('newDir/newTest.png')) // rawfile$r引用rawfile目录下图片
除了自定义资源,开发者也可以使用系统中预定义的资源,统一应用的视觉风格。可以查看应用UX设计中关于资源的介绍,获取支持的系统资源ID及其在不同配置下的取值。
在开发过程中,分层参数的用法与资源限定词基本一致。对于系统资源,可以通过“$r('sys.type.resource_id')”的形式引用。其中,sys为系统资源;type为资源类型,取值包括“color”、“float”、“string”、“media”;resource_id为资源id。
说明:
-
仅声明式开发范式支持使用系统资源。
-
对于系统预置应用,建议使用系统资源;对于三方应用,可以根据需要选择使用系统资源或自定义应用资源。
Text('Hello')
.fontColor($r('sys.color.ohos_id_color_emphasize'))
.fontSize($r('sys.float.ohos_id_text_size_headline1'))
.fontFamily($r('sys.string.ohos_id_text_font_family_medium'))
.backgroundColor($r('sys.color.ohos_id_color_palette_aux1'))
Image($r('sys.media.ohos_app_icon'))
.border({
color: $r('sys.color.ohos_id_color_palette_aux1'),
radius: $r('sys.float.ohos_id_corner_radius_button'), width: 2
})
.margin({
top: $r('sys.float.ohos_id_elements_margin_horizontal_m'),
bottom: $r('sys.float.ohos_id_elements_margin_horizontal_l')
})
.height(200)
.width(300)