本文为稀土掘金技术社区首发签约文章,30天内禁止转载,30天后未获授权禁止转载,侵权必究!
大家好,我是拭心。
上篇文章《# 深圳打响第一枪!鸿蒙技术是否有前途的最强信号来了》 提到,深圳已经发了 2024 年关于鸿蒙软件生态的规划,如果目标达到,过几年很有可能出现 iOS Android 鸿蒙三足鼎立的情况,因此我们客户端程序员有必要储备一下鸿蒙知识。
接下来我将分几篇文章介绍鸿蒙开发的入门、实战和跨平台相关知识,今天这篇文章作为开篇,主要介绍一下鸿蒙开发使用的 IDE 和一个简单工程的项目结构,解决读者在刚接触鸿蒙开发时一脸茫然、无从下手的问题。
IDE
鸿蒙开发的 IDE 叫做 DevEco Studio
,它是基于 IntelliJ IDEA Community 的开源版本打造,和 Android Studio 血脉相通,因此做过 Android 开发或者使用过 IDEA 的工程师们切换到鸿蒙开发时,会发现查看项目目录、文件结构、调试/运行、设备选择、日志、命令行等都是相同的位置,像回家一样自然,非常顺滑。
新建项目页面也类似:
上两图是开发鸿蒙和 Android 应用时新建项目的页面,可以看到两者很相似。在鸿蒙中,Ability 类似 Android 的 Activity,IDE 提供了一些典型业务的 Ability 实例工程;另外鸿也提供了类似 JNI 的 NApi 工程,用于开发需要调用 C++ 的项目。
项目结构
当我们使用 DevEco Studio 新建一个鸿蒙项目后,创建的项目长这样:
AppScope
按照上图中从上往下的顺序(忽略前两个文件夹 .hvigor .idea,不重要),第一个比较重要的文件夹是 AppScope:
AppScope 的作用是配置 app 的核心信息,包括唯一标识(bundleName)、版本号、icon 和名称等等。新建项目后我们一般都会修改这些内容,这时候就需要修改上图中的 app.json5 文件。
.json5 是鸿蒙项目中配置文件的格式,这个格式结尾的文件就是配置文件(好像是句废话哈哈).
第二个重要的文件夹是 entry,它是鸿蒙项目的默认入口代码目录,内容比较多我们稍后介绍。
hvigor
第三个文件夹是 hvigor。
hvigor 是鸿蒙项目的构建工具(可以类比 Gradle),支持使用 JavaScript/TypeScript 开发配置脚本。
根目录下的 hvigor 文件夹用来配置构建工具的版本号、用到的插件、执行配置、日志配置、调试配置等信息:
当我们需要升级 hvigor 本身或者官方构建插件(@ohos/hvigor-ohos-plugin)的版本号时,需要去 hvigor/hvigor-config.json5 文件中修改(文件内容见上图右侧)。
- 如果编译速度慢,需要修改这个文件的 execution 部分,比如开启守护进程、打开增量编译和并行编译。
- 如果调试的时候经常断开(可能是内存不够),可以试一下把这个文件的 nodeOptions 属性的 maxOldSpaceSize 参数调大一点(单位是 MB)。
hvigor 依赖 node,因此在开发鸿蒙项目时我们需要安装并配置 node 环境。
了解 hvigor 是什么后,接下来看下项目根目录下的 hvigorfile.ts 文件。
hvigorfile.ts 是用来配置项目的构建校本,我们可以在其中创建自定义的 task 和 plugin(两者差不多,不同在于 plugin 方便项目之间复用),然后添加到项目的构建流程中。
由于配置文件是 ts 文件格式,因此自定义 hvigor 构建 task 很简单,只需要定义一个 pluginId、实现 run 方法即可。
在上图中,我们的 myTask 函数就是一个自定义的 task,它的 id 是 myTask,然后在任务的执行方法里打印了一条日志。
自定义 plugin 也是类似的,区别在于需要继承 HvigorPlugin:
自定义 task/plugin 函数以后,我们把它添加到导出的 plugins 数组即可。
了解 hvigor 及 hvigorfile.ts 文件后,接下来我们看看根目录下另外比较重要的两个文件。
build-profile.json5
build-profile.json5 用来配置 app 的签名信息、使用的 SDK 版本号、构建模式和多 module 信息。
签名信息配置在 signingConfigs
中:
{
"app": {
//工程的签名信息,可包含多个签名信息
"signingConfigs": [
{
"name": "default", //标识签名方案的名称,用户可自定义
"type": "HarmonyOS", //标识HarmonyOS应用
//该方案的签名材料
"material": {
"certpath": "D:\\SigningConfig\\debug_hos.cer", //调试或发布证书文件,格式为.cer
"storePassword": "******", //密钥库密码,以密文形式呈现
"keyAlias": "debugKey", //密钥别名信息
"keyPassword": "******", //密钥密码,以密文形式呈现
"profile": "D:\\SigningConfig\\debug_hos.p7b", //调试或发布证书Profile文件,格式为.p7b
"signAlg": "SHA256withECDSA", //密钥库signAlg参数
"storeFile": "D:\\SigningConfig\\debug_hos.p12" //密钥库文件,格式为.p12
}
}
],
}
}
如上图所示,签名信息可以有多个,每个配置信息主要包括它的名称、使用的证书和密钥信息、密码等文件。
构建模式配置在 buildModeSet
中:
"buildModeSet": [
{
"name": "debug", //定义构建模式的类型名称,系统默认给出test、debug和release,用户也可以自定义
"buildOption": { //配置项目在构建过程中使用的相关配置
"packOptions": { 包配置选项,用于限制包大小和包数量
"mainPackageLimitSize": 2,
"normalPackageLimitSize": 2
},
"debuggable": true,
"resOptions": {},
//cpp相关编译配置
"externalNativeOptions": {
"path": "./src/main/cpp/CMakeLists.txt", //CMake配置文件,提供CMake构建脚本
"arguments": "", //传递给CMake的可选编译参数
"abiFilters": [ //用于设置本机的ABI编译环境
"armeabi-v7a",
"arm64-v8a",
"x86_64"
],
"cppFlags": "" //设置C++编译器的可选参数
},
"sourceOption": { //使用不同的标签对源代码进行分类,以便在构建过程中对不同的源代码进行不同的处理
"worker": []
},
//配置筛选har依赖.so资源文件的过滤规则
"napiLibFilterOption": {
//按照.so文件的优先级顺序,打包最高优先级的.so文件
"pickFirsts": [
"**/1.so"
],
//按照.so文件的优先级顺序,打包最低优先级的.so 文件
"pickLasts": [
"**/2.so"
],
//排除的.so文件
"excludes": [
"**/3.so"
],
//允许当.so重名冲突时,使用高优先级的.so文件覆盖低优先级的.so文件
"enableOverride": true
},
}
}
]
和开发 Android 应用类似,开发鸿蒙应用时也支持对不同包(比如 debug 包和 release 包)做不同的配置,其中比较关键的有这几个:
externalNativeOptions
:项目有 C/C++ 代码时需要配置,比如 CMakeList 文件路径、参数、ABI 类型等等napLibFilterOption
:项目里有 .so 文件冲突时,在这里配置使用规则,比如 pickFirsts、excludes
build-profile.json5 中最后一个关键的配置信息是 modules,即模块配置信息。
在大点的项目里一般会有多个模块,当我们新建一个模块后,就需要在 build-profile.json5 文件的 modules 属性中加一个配置:
"modules": [
{
"name": "entry", //模块名称,须与模块中module.json5文件中的module.name保持一致
"srcPath": "./entry", //标明模块根目录相对工程根目录的相对路径
"targets": [ //定义构建的APP产物,由product和各模块定义的targets共同定义
{
"name": "default", //target名称,由各个模块的build-profile.json5中的targets字段定义
"applyToProducts": [
"default" //表示将该模块下的“default” Target打包到“default” Product中
]
}
]
}
]
配置信息包括模块名称、路径、产物信息等。
比较可惜的是,目前 build-profile.json5 文件还不支持条件语句,这在大型项目编译时可是刚需啊。毕竟很多时候业务只想编译自己用到的那几个模块,如果能像 Gradle 一样根据 properties 文件里的值修改配置信息就好了,希望华为可以早点支持这个功能。
oh-package.json5
oh-package.json5 和前端项目里的 package.json 文件类似,主要用来声明项目名称、版本号、描述、入口和依赖信息。
一个项目里会有多个 oh-package.json5 文件,除了根目录下,每个模块都有自己的 oh-package.json5 文件。
当模块有导出文件时,就需要在 oh-package.json5 的 main 属性填写要导出的文件名称,比如 index.ets。
oh-package.json5 中声明的依赖信息,在项目打开或者手动点击 Sync And Refresh Project
后 ohpm 会下载对应的库到当前目录的 oh_modules 文件夹下:
ohpm 是鸿蒙的包管理工具,类似 npm。
当我们在不同项目里用到同一个三方库时,为了避免版本冲突,可以在项目根目录下的 oh-package.json5 里强制指定版本号:
上图中在 overrides 中配置的三方库版本号将作为最终使用的版本。
entry
介绍完上面的文件和文件夹作用后,终于到了最重要的 entry
目录:
entry
的名字不一样,重点是它的内容,每个新建的模块一样。
从上图可以看到,entry 目录下也有 build-profile.json5、hvigorfile.ts 和 oh-package.json5 文件,这是因为在鸿蒙项目里,每个模块可以单独配置自己的构建流程和依赖信息。
模块中最重要的配置文件却不在这三者之间,而是 src/main/module.json5
。
module.json5
module.json5 文件用来配置一个模块的名称、类型、进程信息和入口等,其中比较关键的配置有这些:
- type: 表示当前模块的类型,类型有:entry(项目入口)、feature(动态特性包)、har(静态包)、shared(动态共享包)。一般来说项目的入口模块类型是 entry,其他业务模块的类型是 feature,纯粹的库类型为 shared
- mainElement:表示当前模块的入口 UIAbility 名称,名词要和后面的 abilities 中声明的一致
- deviceType:表示当前模块可以运行在哪类设备上,支持的值为 phone、tablet、tv、wearable、car(可以看到,鸿蒙能开发的应用类型还是很多的)
- pages:当前模块的页面路由配置文件路径,默认为
src/main/resources/base/profile/main_pages.json
- abilities:当前模块里的所有 UIAbility 信息
UIAbility 的配置信息有这些:
- name:组件名称,前面的 mainElement 中写的要和这里的一致
- srcEntry:UIAbility 文件的相对路径
- launchType:当前 Ability 的启动模式
- startWindowIcon:启动页面的 icon
- skills:当前 UIAbility 能够接收的 Want 特征
UIAbility 的启动模式有三种:
- multition:多实例,每次启动都新创建一个
- singleton:单例模式,只有第一次启动创建
- specified:指定模式,运行时由开发者决定是否创建新实例
记得很多年前 Android 面试中 Activity 的启动模式经常被问到,鸿蒙的 UIAbility 启动模式或许以后也是个考察点,可以重点关注下。
skills 标签表示 UIAbility 被启动时能够接收的 Want 特征,那什么是 Want 呢?
Want 是在组件启动时传递的对象,比如在 UIAbilityA 中要启动 UIAbilityB 时,可以通过定义一个 Want 对象传递数据给 UIAbilityB 。
根据是否指定要打开的 Ability 信息,Want 分为两种:
- 显式 Want:通过 bundleName 和 abilityName 确定了要打开的 Ability 是什么
- 隐式 Want:没有明确指定要打开的 Ability 名称,而是通过 action、entities 定义要使用的内容,由系统匹配支持的应用来处理
可以看到,鸿蒙的 Want 类似 Android 的 Intent。
回到 skills,skills 就是用来声明这个 UIAbility 支持的能力,包括 entities、actions 和 uris 属性:
"skills": [
{
"entities": [
"entity.system.home"
],
"actions": [
"action.system.home"
]
}
]
actions 表示能够接收的行为,包括系统预定义的和自定义的。entities 和它类似,暂时没搞清楚两者区别。
一个 app 可以配置多个具有入口能力的 skills标签(即配置了ohos.want.action.home 和 entity.system.home)。
OK,这就是一个模块的 module.json5 文件核心属性。
其他
介绍完上面的内容,entry 文件夹中剩下的就是 cpp、ets 和 resources 文件夹。
- cpp 用于保存 cpp/h 和 CMakeLists.txt 文件(可以没有)
- ets 用于存放 .ts 和 .ets 文件(鸿蒙的代码格式)
- resources 用于保存字符串、颜色值、图片和路由配置等信息
到这里我们就了解了 entry 目录的主要内容及作用。
总结
好了,这篇文章到这里就结束了,主要讲了:
- 鸿蒙开发和 Android 开发 IDE 的相似性,降低读者对鸿蒙开发上手的担忧
- 鸿蒙项目的关键文件、文件夹的作用,让读者对鸿蒙项目的各个组成部分有更深入的认识
在这篇文章中,我们刻意略过了一些鸿蒙技术名词的含义(比如 Ability),这是因为它展开的内容很多,我们刚接触鸿蒙开发时先不了解这么多,先对鸿蒙项目有个整体的认识,当要修改相关信息时,知道该改哪里,就够了。
后面的文章我们会逐步介绍鸿蒙开发的语言、框架和跨平台技术细节,感兴趣可以持续关注哦~
感谢你的阅读,欢迎留下你对这篇文章以及鸿蒙开发的想法,以及你想了解的鸿蒙开发知识,我们下期再见!