作者 | 小狮子

导读

鸿蒙零碎(HarmonyOS)是华为推出的一款面向万物互联的全场景分布式操作系统。鸿蒙反对手机、平板、智能穿戴、智慧屏和车机等多种终端设备,发展史如下:

01 HarmonyOS开发简介

1.1 技术概念

在万物智联时代重要机遇期,鸿蒙零碎联合挪动生态倒退的趋势,提出了三大技术理念:一次开发,多端部署;可分可合,自在流转;对立生态,原生智能。

1.1.1 一次开发,多端部署

一次开发,多端部署:指的是一个工程,一次开发上架,多端按需部署。目标是为了撑持开发者高效的开发多种终端设备上的利用。为了实现这一目标,鸿蒙零碎提供了几个外围能力,包含多端开发环境,多端开发能力及多端散发机制。

1.1.2 可分可合,自在流转

元服务是鸿蒙零碎提供的一种全新的利用状态,具备独立入口,用户能够通过点击、碰一碰,扫一扫等形式间接触发,无需显式装置,由程序框架后盾静默装置应用,可为用户提供便捷服务。

可分可合:在开发态,开发者通过业务解耦,把不同的业务拆分为多个模块。在部署态,开发者能够将一个或多个模块自由组合,打包成一个 App Pack 对立上架。在散发运行态,每个 HAP 都能够独自散发满足用户繁多应用场景,也能够多个 HAP 组合散发满足用户更加简单的应用场景。

自在流转:传统利用只能在单个设施内运行,当用户有多个设施,且要实现多个工作时,则要在多个设施间来回切换。因而利用可能在设施之间流转,不间断给用户提供服务的能力就变得十分重要。鸿蒙零碎提供了自在流转的能力,使得开发者能够不便的开发出逾越多个设施的利用,用户也可能不便的应用这些性能。

1.1.3 对立生态,原生智能

对立生态:挪动操作系统和桌面操作系统的跨平台利用开发框架不尽相同,从渲染形式的角度能够演绎为 WebView 染原、原生渲染和自渲染这三类,鸿蒙零碎对应的提供零碎 WebView、ArkUI 框架和 XComponent 能力来撑持三种类型的跨平台框架的接入。

原生智能:鸿蒙零碎内置弱小的 AI 能力,面相鸿蒙生态利用的开发,通过不同档次的 AI 能力凋谢,满足开发者的不同开发场景下的诉求,升高利用的开发门槛,帮忙开发者疾速实现利用智能化。

1.2 开发套件

鸿蒙开发套件蕴含设计、开发、测试、运维套件以及 OS 凋谢能力集:

HarmonyOS Design:鸿蒙视觉设计套件

ArkTS:鸿蒙编程语言

ArkUI:鸿蒙申明式UI框架

ArkCompoler:鸿蒙方舟编译器

DevEco Studio:鸿蒙开发IDE

DevEco Testing:鸿蒙测试套件

AppGallery Connect:鸿蒙利用公布套件

1.2.1 开发语言 - ArkTS

ArkTS基于TypeScript(简称TS)的超集,扩大名为.ets,继承了TS的所有个性(NEXT版本有阉割)。引入了动态类型,扩大了申明式UI、状态治理等能力,让开发者以更简洁、更天然的形式开发高性能利用。

1.2.2 ArkUI框架

ArkUI框架提供开发者两种开发方式:基于ArkTS的申明式开发范式和基于JS扩大的类Web开发范式。申明式开发范式更加简洁,类 Web 开发范式对 Web 及前端开发者更敌对。

(1)ArkTS的申明式开发范式:

采纳申明式开发范式进行利用开发,雷同场景下,比照类 Web 开发范式代码更为精简,并且在性能内存方面进一步优化晋升。另外 ArkUI 框架还提供了 API 扩大机制,通过此种机制进行封装格调对立的 JS 接口。包含状态治理、布局、组件化、装璜器、动效、事件交互、绘制能力、混合开发、跨平台

  • 状态治理

申明式开发范式的核心思想是数据驱动 UI 变动,通过提供的状态进行数据管理,这里状态治理指的是,治理数据发生变化时,UI 组件更新的范畴。

@State:组件领有的状态属性,当@State 装璜的变量更改时,组件会从新渲染更新 UI。

@Link:组件依赖于其父组件领有的某些状态属性,当任何一个组件中的数据更新时,另一个组件的状态都会更新,父子组件从新渲染。

@Prop:相似@Link,但子组件所做的更改不会同步到父组件上,属于单向传递。

@Provide:作为数据的提供方,能够更新其子节点的数据,并触发页面渲染。

@Consume:在感知到@Provide 数据更新后,会触发以后自定义组件的从新渲染。

@StorageLink :组件通过应用@StorageLink(key)装璜的状态变量,与AppStorage 建设双向数据绑定,key为 AppStorage 中的属性键值。当创立蕴含@StorageLink 的状态变量的组件时,该状态变量的值将应用AppStorage 中的值进行初始化。在 UI 组件中对@StorageLink 的状态变量所做的更改将同步到AppStorage ,并从 AppStorage 同步到任何其余绑定实例中。

@StorageProp :组件通过应用@StorageProp(key)装璜的状态变量,将与 AppStorage 建设单向数据绑定,key 标识 AppStorage 中的属性键值。当创立蕴含@StoageProp 的状态变量的组件时,该状态变量的值将应用 AppStorage 中的值进行初始化。AppStorage 中的属性值的更改会导致绑定的 UI 组件进行状态更新。

  • 布局

用特定的组件或者属性来治理用户页面所搁置 UI 组件的大小和地位。ArkUI 框架反对多种布局形式,如弹性布局、列表、宫格、栅格布局等。

  • 组件化

组件是 ArkUI 框架中的根底显示单元,所有 UI 显示的内容都是组件。ArkUI 框架提供多种开箱即用的 UI 组件,如文本显示Text、Button等,并提供了向多种设施状态的多态 UI 能力。开发者能够间接应用预置组件或者自定义本人的组件。

  • 装璜器

自定义组件的场景中,通常会遇到要动静传入不同的 UI 元素的状况,为了满足该场景 ArkUI 框架同时提供了动静构建 UI 元素的能力。

@Builder:可通过 @Builder 装器进行形容,该装器能够润饰函数,此函数能够在 build() 函数之外申明,并在 build() 函数中或其余 @Builder 修的函数中应用,在一个自定义组件内疾速生成多个布局内容。

@Style:申明式范式为了防止开发者对反复款式的设置,通过@Styles 装器能够将多条款式设置提炼成一个办法,间接在组件申明的地位应用。

@Extend:@Extend 装璜器能够将新的属性函数增加到内置组件上,如Text、Column、Button 等,疾速扩大原生组件。

  • 动效

与传统开发方式不同,ArkUI动画是由数据变动驱动动画启动,而不再是间接管制动画的播放。

1、属性动画:组件的某些通用属性变动时,能够通过属性动画实现突变成果,比方设置组件size。

2、显式动画:全局 animateTo 显式动画接口,指定因为闭包代码导致的状态变动插入过渡动效,比方组件的显示与暗藏。

3、转场动画:转场动画包含间转场、组件内过渡转场和共享元素转场三种,比方页面跳转。

  • 事件交互

ArkUI 框架提供了很多交互事件,这些事件提供了不同的信息用于解决相干程序交互逻辑,大抵分位两类:

1、UI 组件事件:比方 TextInput 输入框产生的 onEditChange 输出文本变更事件,List 列表组件产生的 onScrollIndex 列表滚动事件。

2、交互事件:点击事件,拖拽事件,焦点事件,触摸事件,按键事件,鼠标事件,手势事件等

  • 绘制能力

ArkUI 框架提供两种 2D 自定义绘制能力。一种是通过图形组合的形式,利用布局、相对定位和各种图形进行组合实现;另种是通过绘制 API 在 Canvas 画布上进行绘制。

  • 混合开发

ArkUI 框架提供了XComponent 组件,反对加载利用动静库、NAPI 跨语言调用,进行 C++绘制能力的开发。

  • 跨平台

鸿蒙生态构建了 ArkUI 跨平台框架的外围设施,将相应的能力扩大到 iOS 和 Android平台上。开发者能够通过一份代码,联合相应的工具链,同时生成多个 OS 平台的利用工程,并可编译出相应的应用程序,在相应的平台运行。

(2)类Web 开发范式:

类 Web 范式的整体接口采纳与传统 Web 开发类似的设计理念,采纳 HML、CSS与 JS 三种类型的文件进行页面开发,开发者能够基于此范式不便地进行 UI 构建,同时提供数据绑定机制,反对通过 JS 进行数据更新,进而更新UI。

02 第一个鸿蒙版Hello World

2.1 开发环境搭建

  • 装置DevEco Studio(最新版为3.3.1)
  • 下载DevEco Studio(https://developer.huawei.com/consumer/cn/deveco-studio/)并安...

  • 装置NodeJS
  • 关上DevEco Studio,如果曾经装置NodeJS会主动载入门路


△留神:最新LTS版本为18,但鸿蒙要求v14.I9.1\~v17.0.0,官网IDE为v16.19.1。

  • 手动装置NodeJS:
// 装置nvm,nvm能够治理多版本NodeJS。npm install -g n// 装置v16.19.1nvm install v16.19.1// 切换应用指定的版本nodenvm use v16.19.1// 彻底切换版本nvm alias default v16.19.1
  • 装置Ohpm(Open Harmony Pack Manager)鸿蒙包管理系统,装置第三库
  • 装置Harmony SDK

留神的是如果不小心敞开了,也不须要恐慌,因为再次关上也回不到开始的配置页面了。

此时能够关上 DevEco Studio -> Help -> Diagnose Development Environment 重新配置。

2.2 创立第一个鸿蒙利用

Create Project -> Application -> Empty Ability

Next

Mode:ArkTS的申明式开发范式与类Web 开发范式,官网主推Stage 申明式开发范式。

2.3 我的项目构造(有一点点像Android Studio!!)

上部左侧为工程目录,上部两头为代码区,上部右侧为预览区,下部为调试区。

2.3.1 工程目录

  • AppScope -> app.json5:利用配置信息,蕴含报名、利用名、版本等

  • entry为该工程下的Module利用包
  • entryability -> EntryAbility.ts 为该Module的启动入口

  • entry -> pages 寄存页面文件

  • entry -> resources 寄存资源文件
  • entry -> module.json5 配置页面信息,能够用与router跳转
  • entry -> ohosTest 为测试模块

2.3.2 预览区

鸿蒙提供实时的页面预览,且Reload模式能够实时更新UI,终于能够不必Command+R了。

2.4 运行

鸿蒙提供Previewer 预览模式、Local Emulator 本地模拟器、Remote Emulator 近程模拟器、Remote Device 近程真机、Local Device 本地真机等模式运行。

实测Mate30运行鸿蒙利用屏幕刷新有问题,十分卡,能够应用scrcpy投屏来解决显示问题。Mate60失常。

2.4.1 真机运行

  • 遥遥领先间断点击 "零碎版本号" 开启开发者模式。
  • 零碎 -> 更新,开启abd调试。
  • 插入数据线,抉择 "传输文件"。
  • 证书配置:File > Project Structure > Project > Signing Configs界面,勾选“Automatically generate signature”。

03 小试牛刀 - 度加首页

3.1 底部Tab

应用Tabs组件创立底部tabbar,子page别离为CreatePage、ClassPage、MinePage。

import promptAction from '@ohos.promptAction'import { TabbarItem } from '../Models/TabbarItem'import { ClassPage } from './ClassPage'import { CreatePage } from './CreatePage'import { MinePage } from './MinePage'@Entry@Componentstruct Index {  // tabbar数据源  tabList: TabbarItem[] = [    {      defaultIcon: $r("app.media.home"),      activeIcon: $r("app.media.home_focus"),      title:"创作"    },    {      defaultIcon: $r("app.media.class"),      activeIcon: $r("app.media.class_focus"),      title:"课堂"    },    {      defaultIcon: $r("app.media.my"),      activeIcon: $r("app.media.my_focus"),      title:"我的"    },  ]  // 记录索引,index从0开始  @State tabActivityIndex: number = 0  // 展现tabbaritem  @Builder  TabbarBuilder(item: TabbarItem, index: number) {    Column({space: 5}) {      Image(this.tabActivityIndex == index ? item.activeIcon : item.defaultIcon)        .width(24)        .aspectRatio(1)      Text(item.title)        .fontSize(12)        .fontColor(this.tabActivityIndex == index ? "#FFFFFF" :"#99FFFFFF")    }  }  build() {    Column() {      // Tabs      Tabs({index: this.tabActivityIndex}) {        ForEach(this.tabList,(item: TabbarItem, index: number) => {          TabContent() {            if (index == 0) {              CreatePage()            } else if (index == 1) {              ClassPage()            } else {              MinePage()            }          }          .tabBar(this.TabbarBuilder(item,index))        } )      }      .barPosition(BarPosition.End) // tab放在底部      .onChange((index: number) => {        this.tabActivityIndex = index        promptAction.showToast({message:index.toString()})      })    }    .height("100%")    .width("100%")    .backgroundColor("#16141F")    .justifyContent(FlexAlign.Center)   }}

3.2 创作page

创作页面分为5大区域:迎新年、开始创作、工具栏、热点流动tab、热点互动内容。

import { ActivityComponent } from '../Components/ActivityComponent'import { HotComponent } from '../Components/HotComponent'// 创作页面@Componentexport struct CreatePage {  // 流动下标  @State activitySelectedIndex: number = 0  build() {    Column() {      // 迎新年行      Row() {        Row(){          Text("迎新年,瓜分万元流量券") // 新玩法!AI帮你制作专属贺岁视频            .width("178")            .fontColor("rgba(255,255,255,0.6)")            .fontSize(14)          Image($r("app.media.img_home_link_arrow"))            .width(16)            .aspectRatio(1)        }        .width(194)        .padding({left: 10})        Row(){          Image($r("app.media.img_reward_star"))            .width(16)            .height(16)          Text("签到")            .width("40")            .fontColor("rgba(255,255,255,0.6)")            .fontSize(14)            .textAlign(TextAlign.Center)        }        .width(66)      }      .height("50")      .width("100%")      .justifyContent(FlexAlign.SpaceBetween)        // 开始创作      Row({space: 10}){        // 开始创作        Stack() {          Image($r("app.media.img_home_entrance"))            .width("100%")            .height("100%")            .borderRadius(8) // 圆角          Image($r("app.media.jiandao1"))            .width(30)            .aspectRatio(1)            .margin({bottom: 30})          Text("开始创作")            .width(56)            .height(20)            .fontColor("rgba(255,255,255,1)")            .fontSize(14)            .margin({top: 30})        }        .height("100%")        .layoutWeight(1) // 通知占满残余        .borderRadius(8) // 圆角        // 草稿箱        Column(){          Text("2")            .fontColor("#fff")            .fontSize(20)            .margin({top: 15})          Text("草稿箱")            .fontColor("#fff")            .fontSize(14)            .margin({top: 10})        }        .backgroundColor("#282438")        .height("100%")        .width(86)        .borderRadius(8) // 圆角      }      .height(86)      .width("100%")      .justifyContent(FlexAlign.SpaceBetween)      .padding({left: 15, right: 15})      // AI提词器      Row() {        Row() {          Column() {            Image($r("app.media.home_prompter"))              .width(40)              .height(28)            Text("AI 提词")              .fontColor("#fff")              .fontSize(10)          }          .width(70)          .height(70)          .justifyContent(FlexAlign.Center)          .margin({left: 15})          Column() {            Image($r("app.media.home_ttv"))              .width(40)              .height(28)            Text("AI 成片")              .fontColor("#fff")              .fontSize(10)          }          .width(70)          .height(70)          .justifyContent(FlexAlign.Center)          Column() {            Image($r("app.media.home_digital_human"))              .width(40)              .height(28)            Text("AI 数字人")              .fontColor("#fff")              .fontSize(10)          }          .width(70)          .height(70)          .justifyContent(FlexAlign.Center)          Column() {            Image($r("app.media.home_subtitle"))              .width(40)              .height(28)            Text("文字提取")              .fontColor("#fff")              .fontSize(10)          }          .width(70)          .height(70)          .justifyContent(FlexAlign.Center)          .margin({right: 15})        }        .height("100%")        .width("100%")        .backgroundColor("#282438")        .borderRadius(8)        .justifyContent(FlexAlign.SpaceBetween)      }      .backgroundColor("#16141F")      .height(76)      .width("100%")      .padding({left: 15, right: 15})      .margin({top: 15})       .borderRadius(8)      // 春节流动      Row() {        Row() {          Image($r("app.media.huodong1"))            .borderRadius(8)        }        .height("100%")        .width("100%")        .backgroundColor("#282438")        .justifyContent(FlexAlign.SpaceBetween)      }      .backgroundColor("#16141F")      .height(76)      .width("100%")      .padding({left: 15, right: 15})      .margin({top: 15})      .borderRadius(8)      // 热点      Row() {        Row() {          Image(this.activitySelectedIndex == 0 ? $r("app.media.img_hot_tab_focus") : $r("app.media.img_hot_tab"))            .width(45)            .height(25)        }        .margin({left: 20})        .width(45)        .height(54)        .onClick( () => {          this.activitySelectedIndex = 0        })        Text("流动")          .fontSize(18)          .fontColor(this.activitySelectedIndex == 0 ? "rgba(255,255,255,0.4)" : "rgba(255,255,255,1)")          .margin({left: 20})          .onClick( () => {            this.activitySelectedIndex = 1          })          .margin({left: 15, top: 2})          .height(54)      }      .margin({top: 5})      .height(54)      if (this.activitySelectedIndex == 0){        HotComponent()      } else {        ActivityComponent()      }    }    .width("100%")    .height("100%")    .alignItems(HorizontalAlign.Start)  }}

3.3 热点Component

import { hotContentItemList, hotContentItemList2, HotContentItemModel } from '../Models/HotContentItemModel'import { HotContentComponent } from './HotContentComponent'import { TabItemListComponent, TabItemModel } from './TabItemListComponent'// 热点@Componentexport struct HotComponent {  // 定义item的数据源  @State  tabItemModelList: TabItemModel[] = [    new TabItemModel({title: "全网"}),    new TabItemModel({title: "娱乐"}),    new TabItemModel({title: "情感"}),    new TabItemModel({title: "历史"}),    new TabItemModel({title: "衰弱"}),    new TabItemModel({title: "社会"}),    new TabItemModel({title: "科技"}),    new TabItemModel({title: "春节"})  ]  // 选中的item下标  @State selectedIndex: number = 0  // 热点内容列表  @State hotContentItemList: HotContentItemModel[] = hotContentItemList  // 热点内容列表2.为了模仿不同tab下的数据  @State hotContentItemList2: HotContentItemModel[] = hotContentItemList2  build() {    Column() {      Text("全网热点 每分钟更新")        .fontColor("rgba(255,255,255,0.3)")        .fontSize(12)        .margin({left: 15, top: 0})      // 热点tab列表      TabItemListComponent({itemModelList: $tabItemModelList, selectedIndex: $selectedIndex})      if (this.selectedIndex == 0) {        // 热点内容        HotContentComponent({itemList: this.hotContentItemList})      } else if (this.selectedIndex == 1) {        // 热点内容        HotContentComponent({itemList: this.hotContentItemList2})      } else {        // 热点内容        HotContentComponent({itemList: this.hotContentItemList})      }    }    .alignItems(HorizontalAlign.Start)    .width("100%")    .layoutWeight(1)     .padding({bottom: 80})  }}

3.4 流动Component

import { createActivityListItemList, CreateActivityListItemModel } from '../Models/CreateActivityListItemModel'// 流动@Componentexport  struct ActivityComponent {  @State createActivityListItemList: CreateActivityListItemModel[] = createActivityListItemList  // 工夫戳格式化  formatDateTime(timestamp: number) {    let dateTime = new Date(timestamp * 1000)    const year = dateTime.getFullYear();    const month = dateTime.getMonth() + 1 < 10 ? '0' + (dateTime.getMonth() + 1) : dateTime.getMonth() + 1;    const date = dateTime.getDate() < 10 ? '0' + dateTime.getDate() : dateTime.getDate();    const hours = dateTime.getHours() < 10 ? '0' + dateTime.getHours() : dateTime.getHours();    const minutes = dateTime.getMinutes() < 10 ? '0' + dateTime.getMinutes() : dateTime.getMinutes();    const seconds = dateTime.getSeconds() < 10 ? '0' + dateTime.getSeconds() : dateTime.getSeconds();    return (month + '月' + date + '日');  }  build() {    List() {      ForEach(this.createActivityListItemList, (model: CreateActivityListItemModel, index: number) => {        ListItem() {          Row() {            Image(model.pic)              .width(114)              .height(64)              .margin({left: 15})              .borderRadius(8)            Column() {              Text(model.name)                .fontColor(Color.White)                .fontWeight(14)              Text(this.formatDateTime(model.start_time) + "-" + this.formatDateTime(model.end_time))                .fontColor("rgba(255,255,255,0.3)")                .fontWeight(12)                .margin({top:10})            }            .alignItems(HorizontalAlign.Start)            .margin({left: 15})          }        }        .height(84)      })    }    .width("100%")    .aspectRatio(1)  }}

04 根底图谱


——————————END——————————

参考资料:

[1]官网Demo:

https://gitee.com/harmonyos/codelabs

[2]鸿蒙开发者网站:

https://developer.huawei.com/consumer/cn/

[3]鸿蒙开发者社区:

https://developer.huawei.com/consumer/cn/forum/

[4]《鸿蒙生态利用开发白皮书V2.0》:https://developer.huawei.com/consumer/cn/doc/guidebook/harmon...

[5]鸿蒙开发者认证:https://developer.huawei.com/consumer/cn/training/dev-certifi...

截止至2023年12月31日,曾经有50000余开发者退出了鸿蒙开发行列,置信随着鸿蒙的倒退迭代,将来队伍将会越来越壮大。

举荐浏览:

漫谈数据分布可视化剖析
云上业务一键性能调优,应用程序性能诊断工具 Btune 上线
一文详解动态图和动态图中的主动求导机制