> 文档中心 > 鸿蒙应用开发初试

鸿蒙应用开发初试


一、简介

  • 鸿蒙 (HarmonyOS) 是一款由华为开发的,面向全场景的分布式操作系统。其开源项目为 OpenHarmony。
  • 超级小程序
    • H5 -> 小程序 -> 超级小程序
  • 可剪裁系统
    • 128 KB – 128 MB – 4 GB
  • 模改通讯协议
    • 类似普通话,统一了方言。鸿蒙成为 IoT 互联互通的标准语言

发布会现场

在这里插入图片描述

二、储备知识

  • 熟悉前端技术栈(HTML、CSS、JS)
    • 类 Web 范式编程(鸿蒙开发不是浏览器环境)
    • 例如:鸿蒙中的 div 是自己封装的,不是 Web 端的 div
  • 熟悉微信小程序
    • 页面结构、API、配置方式
  • 熟悉 Vue 2
    • 鸿蒙自己实现的类 Vue 2 的 MVVM 模式(观察者模式,数据劫持)
  • 有安卓开发经验更好

在这里插入图片描述

三、鸿蒙系统架构

在这里插入图片描述
鸿蒙系统架构

  • 应用层
    • 鸿蒙的应用由一个或多个 FA(Feature Ability)或 PA(Particle Ability)组成
    • FA 有 UI 界面,提供与用户交互的能力;而 PA 无 UI 界面,提供后台运行任务的能力
  • 框架层
    • 提供了 Java/C/C++/JS 等用户程序框架和 Ability 框架
    • 两种 UI 框架(Java UI 框架、JS UI 框架)
  • 系统服务层
    • 系统服务层是鸿蒙的核心能力集合,通过框架层对应用程序提供服务
  • 内核层
    • 采用多内核设计,支持针对不同资源受限设备,选用适合的 OS 内核

对Ability(能力)的解释

在这里插入图片描述

在这里插入图片描述

四、鸿蒙是不是安卓套壳

我们对比一下鸿蒙和安卓的架构

安卓系统
在这里插入图片描述
鸿蒙系统
在这里插入图片描述

对比

在这里插入图片描述

五、鸿蒙应用开发

在线体验:https://playground.harmonyos.com/

开发环境搭建(DevEco Studio)

  • 版本
  • DevEco Studio 1.0(for EMUI)
  • DevEco Studio 2.0(for HarmonyOS)
  • 下载
  • https://developer.harmonyos.com/cn/develop/deveco-studio#download
  • 安装
  • 确保安装过程中有网络环境
  • 初始化项目
    • 了解 JS UI 的基本语法
    • JS SDK
    • 了解 JS UI 的源码实现

鸿蒙js

  • JS UI 框架
    • 类 Web 范式编程的 UI 界面展示
    • https://gitee.com/openharmony/ace_ace_engine
  • JS 应用开发框架
    • 轻量级的 MVVM 实现(仿 Vue 2)
    • https://gitee.com/openharmony/ace_engine_lite
  • JS 原生模块(NAPI)
    • 实现 JS 与 C/C++ 代码互相访问
    • https://gitee.com/openharmony/ace_napi

在这里插入图片描述

  • 应用层
    • 开发者使用 JS UI 框架开发的 FA 应用
  • 前端框架层
    • 完成前端页面解析,提供 MVVM 开发模式、页面路由和自定义组件等能力
  • 引擎层
    • 完成动画解析、DOM 树构建、布局计算、渲染命令构建与绘制、事件管理等
  • 适配层
    • 完成对平台层的对接,比如:事件对接、渲染管线对接和系统生命周期对接等

在这里插入图片描述

  • JS Data binding
    • JS 数据绑定框架使用 JavaScript 语言提供一套基础的数据绑定能力。
  • JS runtime
    • 支持 JS 代码的解析和执行。
  • JS Runtime 的解析引擎为 JerryScript
    • JS framework
    • JS 框架部分使用 C++ 语言实现,提供 JS API 和组件的框架机制。

https://jerryscript.net/

在这里插入图片描述

JS 原生(NAPI)

在这里插入图片描述

  • NativeEngine
    • JS 引擎抽象层,统一 JS 引擎在 NAPI 层的接口行为。
  • ModuleManager
    • 管理模块,用于模块加载、模块信息缓存。
  • ScopeManager
    • 管理 NativeValue 的生命周期。
  • ReferenceManager
    • 管理 NativeReference 的生命周期。

https://github.com/quickjs-zh/QuickJS

在这里插入图片描述

  • 数据存储
    • https://developer.harmonyos.com/cn/docs/documentation/doc-references/js-apis-data-storage-0000000000626080
  • 数据存储的实现
    • https://gitee.com/openharmony/ace_napi/tree/master/sample/native_module_storage

六、案例

目录结构

在这里插入图片描述
html

<element name="fragment_main" src="../../common/fragment_main/fragment_main.hml"></element><div class="container">    <div class="top-tool-bar"> <image class="toolbar-image1" src="{{ images_resource.image_add }}" onclick="onClick"></image> <image class="toolbar-image2" src="{{ images_resource.image_add }}" onclick="onClick"></image> <image class="toolbar-image3" src="{{ images_resource.image_more }}" onclick="onClick2"></image>    </div>    <tabs class="tabs" index="0" vertical="false" onchange="change"> <tab-bar class="bottomBar-wrapper" mode="fixed">     <div class="bottomBar-item-wrapper">  <image class="bottomBarItem-image" src="{{ images_resource.image_icon }}"></image>  <text class="bottomBarItem-text">{{ $t('strings.tab_name') }}</text>     </div>     <div class="bottomBar-item-wrapper">  <image class="bottomBarItem-image" src="{{ images_resource.image_icon }}"></image>  <text class="bottomBarItem-text">{{ $t('strings.tab_name') }}</text>     </div>     <div class="bottomBar-item-wrapper">  <image class="bottomBarItem-image" src="{{ images_resource.image_icon }}"></image>  <text class="bottomBarItem-text">{{ $t('strings.tab_name') }}</text>     </div>     <div class="bottomBar-item-wrapper">  <image class="bottomBarItem-image" src="{{ images_resource.image_icon }}"></image>  <text class="bottomBarItem-text">{{ $t('strings.tab_name') }}</text>     </div>     <div class="bottomBar-item-wrapper">  <image class="bottomBarItem-image" src="{{ images_resource.image_icon }}"></image>  <text class="bottomBarItem-text">{{ $t('strings.tab_name') }}</text>     </div> </tab-bar> <tab-content class="tabContent" scrollable="true">     <div class="item-content">  <fragment_main></fragment_main>     </div>     <div class="item-content">  <text class="item-title">{{ $t('strings.second_page') }}</text>     </div>     <div class="item-content">  <text class="item-title">{{ $t('strings.third_page') }}</text>     </div>     <div class="item-content">  <text class="item-title">{{ $t('strings.fourth_page') }}</text>     </div>     <div class="item-content">  <text class="item-title">{{ $t('strings.fifth_page') }}</text>     </div> </tab-content>    </tabs>    <div class="fragment_main_wearable"> <fragment_main id="id_fragment_main"></fragment_main>    </div></div>

js

import prompt from '@system.prompt';import device from '@system.device';import mediaquery from '@system.mediaquery';const TAG = '[index]';var mMediaQueryList;var context;// js call java// abilityType: 0-Ability; 1-Internal Abilityconst ABILITY_TYPE_EXTERNAL = 0;const ABILITY_TYPE_INTERNAL = 1;// syncOption(Optional, default sync): 0-Sync; 1-Asyncconst ACTION_SYNC = 0;const ACTION_ASYNC = 1;const ACTION_MESSAGE_CODE = 1001;var wearableMediaListener = function (e) {    if (e.matches) { // do something console.log(TAG + "Success Media Listen"); context.initial_value = 4; context.$child('id_fragment_main').initial_index_value = 0; context.$child('id_fragment_main').list_data.forEach(element => {     element.item_icon = context.images_resource_dark_mode.image_icon;     element.item_right_arrow = context.images_resource_dark_mode.image_right_arrow; });    }};var getDeviceInfo = function () {    var res = '';    device.getInfo({ success: function (data) {     console.log(TAG + 'Success device obtained. screenShape=' + data.screenShape);     this.res = data.screenShape; }, fail: function (data, code) {     console.log(TAG + 'Failed to obtain device. Error code=' + code + '; Error information: ' + data); },    });    return res;};export default {    data: { images_resource: {     "image_icon": "common/images/ic.png",     "image_add": "common/images/add64.png",     "image_more": "common/images/more.png",     "image_right_arrow": "common/images/right_arrow.png" }, images_resource_dark_mode: {     "image_icon": "common/images/ic_dark_mode.png",     "image_add": "common/images/add64.svg",     "image_more": "common/images/more.svg",     "image_right_arrow": "common/images/right_arrow_dark_mode.png" }, initial_value: 0    },    onInit() { console.log(TAG + 'onInit'); context = this; this.mMediaQueryList = mediaquery.matchMedia("screen and (device-type: wearable)"); this.mMediaQueryList.addListener(wearableMediaListener); console.info(TAG + "java js" + this.getSystemColorModeByJava()); // async call and return null    },    onReady()    { console.log(TAG + 'onReady'); console.log(TAG + getDeviceInfo()); // getDeviceInfo after Init    },    onShow()    { console.log(TAG + 'onShow');    },    onDestroy() { console.log(TAG + 'onDestroy'); mMediaQueryList.removeListener(wearableMediaListener);    },    onClick() { prompt.showToast({     message: "add",     duration: 3000, });    },    onClick2() { prompt.showToast({     message: "more",     duration: 3000, });    },    getSystemColorModeByJava: async function() { var actionData = {}; actionData.firstNum = 123; actionData.secondNum = 465; var action = {}; action.bundleName = 'com.example.myapplication'; action.abilityName = 'com.example.myapplication.ServiceAbilityForJS'; action.messageCode = ACTION_MESSAGE_CODE; action.data = actionData; action.abilityType = ABILITY_TYPE_EXTERNAL; action.syncOption = ACTION_SYNC; var result = await FeatureAbility.callAbility(action); var ret = JSON.parse(result); if (ret.code == 0) {     console.info('result is:' + JSON.stringify(ret.abilityResult)); } else {     console.error('error code:' + JSON.stringify(ret.code)); } if (ret.getColorMode == 0) {     console.info(TAG + ret.getColorMode);     // get system color mode and do something     this.images_resource = this.images_resource_dark_mode; }    }}

css

.container {    display: flex;    flex-direction: column;    justify-content: flex-start;    align-items: flex-start;    width: 100%;    left: 0px;    top: 0px;}.top-tool-bar {    display: flex;    flex-direction: row;    justify-content: flex-end;    align-items: center;    width: 100%;    height: 56px;    padding-left: 24px;    padding-right: 24px;}.toolbar-image1 {    width: 24px;    height: 24px;    margin-right: 40px;    opacity: 0.9;}.toolbar-image2 {    width: 24px;    height: 24px;    margin-right: 40px;    opacity: 0.9;}.toolbar-image3 {    width: 24px;    height: 24px;    opacity: 0.9;}.tabs {    width: 100%;}.bottomBar-wrapper {    width: 100%;    height: 56px;    flex-direction: row;    justify-content: flex-start;    align-items: center;    position: fixed;    bottom: 0px;}.bottomBar-item-wrapper {    width: 100%;    height: 100%;    flex-direction: column;    justify-content: center;    align-items: center;    margin-top: 0px;    margin-bottom: 8px;}.bottomBarItem-image {    height: 24px;    width: 24px;}.bottomBarItem-text {    font-size: 14px;    opacity: 0.9;    margin-top: 2px;}.tabContent {    width: 100%;    padding-bottom: 56px;}.item-content {    display: flex;    flex-direction: column;    justify-content: flex-start;    align-items: flex-start;    width: 100%;}.item-title {    width: 100%;    height: 100%;    font-size: 18px;    text-align: center;}/* wearable */@media screen and (device-type: wearable) {    .top-tool-bar { display: none;    }    .bottomBar-wrapper { display: none;    }}/* phone */@media screen and (device-type: phone) {    .fragment_main_wearable { display: none;    }}/* tablet */@media screen and (device-type: tablet) {    .fragment_main_wearable { display: none;    }}/* tv */@media screen and (device-type: tv) {    .fragment_main_wearable { display: none;    }    .item-title { color: black;    }    .top-tool-bar { display: none;    }    .bottomBar-wrapper { display: none;    }}

运行结果

在这里插入图片描述