一、简介
- 鸿蒙 (HarmonyOS) 是一款由华为开发的,面向全场景的分布式操作系统。其开源项目为 OpenHarmony。
- 超级小程序
- 可剪裁系统
- 模改通讯协议
- 类似普通话,统一了方言。鸿蒙成为 IoT 互联互通的标准语言
发布会现场
二、储备知识
- 熟悉前端技术栈(HTML、CSS、JS)
- 类 Web 范式编程(鸿蒙开发不是浏览器环境)
- 例如:鸿蒙中的 div 是自己封装的,不是 Web 端的 div
- 熟悉微信小程序
- 熟悉 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)
鸿蒙js
- JS UI 框架
- JS 应用开发框架
- JS 原生模块(NAPI)
- 应用层
- 前端框架层
- 完成前端页面解析,提供 MVVM 开发模式、页面路由和自定义组件等能力
- 引擎层
- 完成动画解析、DOM 树构建、布局计算、渲染命令构建与绘制、事件管理等
- 适配层
- 完成对平台层的对接,比如:事件对接、渲染管线对接和系统生命周期对接等
- JS Data binding
- JS 数据绑定框架使用 JavaScript 语言提供一套基础的数据绑定能力。
- JS runtime
- JS Runtime 的解析引擎为 JerryScript
- JS framework
- JS 框架部分使用 C++ 语言实现,提供 JS API 和组件的框架机制。
https://jerryscript.net/
JS 原生(NAPI)
- NativeEngine
- JS 引擎抽象层,统一 JS 引擎在 NAPI 层的接口行为。
- ModuleManager
- ScopeManager
- ReferenceManager
- 管理 NativeReference 的生命周期。
https://github.com/quickjs-zh/QuickJS
六、案例
目录结构
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;
const ABILITY_TYPE_EXTERNAL = 0;
const ABILITY_TYPE_INTERNAL = 1;
const ACTION_SYNC = 0;
const ACTION_ASYNC = 1;
const ACTION_MESSAGE_CODE = 1001;
var wearableMediaListener = function (e) {
if (e.matches) {
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());
},
onReady()
{
console.log(TAG + 'onReady');
console.log(TAG + getDeviceInfo());
},
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);
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;
}
@media screen and (device-type: wearable) {
.top-tool-bar {
display: none;
}
.bottomBar-wrapper {
display: none;
}
}
@media screen and (device-type: phone) {
.fragment_main_wearable {
display: none;
}
}
@media screen and (device-type: tablet) {
.fragment_main_wearable {
display: none;
}
}
@media screen and (device-type: tv) {
.fragment_main_wearable {
display: none;
}
.item-title {
color: black;
}
.top-tool-bar {
display: none;
}
.bottomBar-wrapper {
display: none;
}
}
运行结果
|