0
点赞
收藏
分享

微信扫一扫

教不会你算我输系列 | 手把手教你HarmonyOS应用开发

教不会你算我输系列 | 手把手教你HarmonyOS应用开发_Developer


导读


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

教不会你算我输系列 | 手把手教你HarmonyOS应用开发_Developer_02

全文13098字,预计阅读时间34分钟。

01 HarmonyOS开发简介

1.1 技术概念

在万物智联时代重要机遇期,鸿蒙系统结合移动生态发展的趋势,提出了三大技术理念:一次开发,多端部署;可分可合,自由流转;统一生态,原生智能。

教不会你算我输系列 | 手把手教你HarmonyOS应用开发_Developer_03

1.1.1 一次开发,多端部署

教不会你算我输系列 | 手把手教你HarmonyOS应用开发_HarmonyOS_04

一次开发,多端部署:指的是一个工程,一次开发上架,多端按需部署。目的是为了支撑开发者高效的开发多种终端设备上的应用。为了实现这一目的,鸿蒙系统提供了几个核心能力,包括多端开发环境,多端开发能力及多端分发机制。

1.1.2 可分可合,自由流转

元服务是鸿蒙系统提供的一种全新的应用形态,具有独立入口,用户可以通过点击、碰一碰,扫一扫等方式直接触发,无需显式安装,由程序框架后台静默安装使用,可为用户提供便捷服务。

教不会你算我输系列 | 手把手教你HarmonyOS应用开发_Developer_05

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

教不会你算我输系列 | 手把手教你HarmonyOS应用开发_HarmonyOS_06

自由流转:传统应用只能在单个设备内运行,当用户有多个设备,且要完成多个任务时,则要在多个设备间来回切换。因此应用能够在设备之间流转,不间断给用户提供服务的能力就变得非常重要。鸿蒙系统提供了自由流转的能力,使得开发者可以方便的开发出跨越多个设备的应用,用户也能够方便的使用这些功能。

1.1.3 统一生态,原生智能

统一生态:移动操作系统和桌面操作系统的跨平台应用开发框架不尽相同,从渲染方式的角度可以归纳为 WebView 染原、原生渲染和自渲染这三类,鸿蒙系统对应的提供系统 WebView、ArkUI 框架和 XComponent 能力来支撑三种类型的跨平台框架的接入。

教不会你算我输系列 | 手把手教你HarmonyOS应用开发_Developer_07

原生智能:鸿蒙系统内置强大的 AI 能力,面相鸿蒙生态应用的开发,通过不同层次的 AI 能力开放,满足开发者的不同开发场景下的诉求,降低应用的开发门槛,帮助开发者快速实现应用智能化。

1.2 开发套件

教不会你算我输系列 | 手把手教你HarmonyOS应用开发_ArkTS_08

鸿蒙开发套件包含设计、开发、测试、运维套件以及 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框架

教不会你算我输系列 | 手把手教你HarmonyOS应用开发_Developer_09

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

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

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

  • 状态管理

教不会你算我输系列 | 手把手教你HarmonyOS应用开发_HarmonyOS_10

声明式开发范式的核心思想是数据驱动 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 开发范式:

教不会你算我输系列 | 手把手教你HarmonyOS应用开发_ArkTS_11

类 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/)并安装(如果看不到就继续往下拉...)

教不会你算我输系列 | 手把手教你HarmonyOS应用开发_Developer_12

  • 安装NodeJS
  • 打开DevEco Studio,如果已经安装NodeJS会自动载入路径

教不会你算我输系列 | 手把手教你HarmonyOS应用开发_Developer_13

△注意:最新LTS版本为18,但鸿蒙要求v14.I9.1~v17.0.0,官方IDE为v16.19.1。
  • 手动安装NodeJS:

// 安装nvm,nvm可以管理多版本NodeJS。
npm install -g n

// 安装v16.19.1
nvm install v16.19.1

// 切换使用指定的版本node
nvm use v16.19.1

// 彻底切换版本
nvm alias default v16.19.1

  • 安装Ohpm(Open Harmony Pack Manager)鸿蒙包管理系统,安装第三库
  • 安装Harmony SDK

注意的是如果不小心关闭了,也不需要恐慌,因为再次打开也回不到开始的配置页面了。

此时可以打开 DevEco Studio -> Help -> Diagnose Development Environment 重新配置。

教不会你算我输系列 | 手把手教你HarmonyOS应用开发_ArkTS_14

2.2 创建第一个鸿蒙应用

Create Project -> Application -> Empty Ability

教不会你算我输系列 | 手把手教你HarmonyOS应用开发_ArkTS_15

Next

教不会你算我输系列 | 手把手教你HarmonyOS应用开发_ArkTS_16

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

2.3 项目结构(有一点点像Android Studio!!)

教不会你算我输系列 | 手把手教你HarmonyOS应用开发_HarmonyOS_17

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

2.3.1 工程目录

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

教不会你算我输系列 | 手把手教你HarmonyOS应用开发_HarmonyOS_18

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

教不会你算我输系列 | 手把手教你HarmonyOS应用开发_Developer_19

  • entry -> pages  存放页面文件

教不会你算我输系列 | 手把手教你HarmonyOS应用开发_Developer_20

  • 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 小试牛刀 - 度加首页

教不会你算我输系列 | 手把手教你HarmonyOS应用开发_Developer_21

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
@Component
struct 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'

// 创作页面
@Component
export 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'
// 热点
@Component
export 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'
// 活动
@Component
export  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 基础图谱

入门

鸿蒙基础架构


开发环境搭建


ArkTS与开发范式

TS/ArkTS、FA/Stage模型

应用开发

UIAbility、

Component生命周期

onCreate、onDestroy、onWindowStageCreate、onWindowStageDestroy、onForeground、onBackground...

装饰器

@Entry、@Preview、@Component、@State、@Builder、@Prop、@Link...

数据存储&持久化

AppStorage、LocalStorage、PersistentStorage...

条件判断

if、for、switch

ArkUI

Column、Row、List、Stack、Scroll、Text、Image、Button、Tabs...

对象

interface、implements、extends

路由

router.pushUrl、router.replaceUrl、router.back

权限申请

abilityAccessCtrl

网络请求

httpRequest

通知

notificationManager

手势

gesture()、onTouch()

动画

animation()、animateTo()、

sharedTransition()

媒体播放

AVPlayer

国际化

configuration.getLocale()

组件化

SharedLibrary、StaticLibrary

第三方依赖

ohpm

应用测试

HarmonyOS Test


HarmonyOS JUnit


OpenHarmony Test


应用上架

AppGallery Connect



——————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/harmonyecoapp-guidebook-0000001761818040

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

推荐阅读:

千万级高性能长连接Go服务架构实践

百度搜索Push个性化:新的突破

漫谈数据分布可视化分析



举报

相关推荐

0 条评论