#冲刺创作新星# [十] JS应用控制LED 原创 精华
作者:王石
在《[九] 写个简单的LED驱动》我们熟悉了如何在OpenHarmony开发驱动应用,并通过hdc工具拷贝至开发板运行。在《[六]第一个hap应用》的文章里我们学会如何用IDE工具编写hap应用并他通过IDE工具安装至开发板运行。我们学会了hap程序的开发,但是hap程序是运行在标准系统的应用,对于轻量和小型系统我们应该如何进行开发呢?接下来我们需要学习下如何开发JS应用。
轻量、小型系统JS应用
Ace(foundation/arkui/ace_engine_lite)是OpenHarmony的轻量级系统所使用的UI框架子系统,为开发者提供JS-UI开发框架。包括.html,.css,.js。开发者可以通过DevEco工具进行开发。其中JS的引擎采用三方库里的JerryScript(jerryscript是IoT设备上的轻量级JS引擎,支持ECMAScript 5.1标准,适配低内存硬件,最小运行在64KB RAM和小于200KB的flash,提供C API)。关于jerryscript的详细介绍可以看如下参考链接(https://github.com/jerryscript-project/jerryscript )
详细的内容介绍在一下链接内可以看到官方的说明:
参考链接:https://gitee.com/openharmony/arkui_ace_engine_lite
此样例参考小熊派设计,使用小熊派HM_Micro开发板进行验证
JS-UI开发流程
graph LR
--> 配置工程 --> 增加LED程序 --> 添加JSAPI接口
st=>start: 创建工程
sub1=>subroutine: 配置工程
sub2=>subroutine: 增加LED程序
sub3=>subroutine: 添加JSAPI接口
e=>end: 编译运行
st(right)->sub1(right)->sub2(right)->sub3(right)->e
-
建立[Lite]Empty Ability
-
配置工程
-
工程结构说明
工程目录主要在entry里,有以下内容:
- .preview: 界面预览目录;
- build: 工程编译目录;
- src:包括i18n(国际化翻译路径),pages(界面目录,index.css, index.hml, index.js)
- 工程预览
-
添加按键功能控制LED灯
- 修改index.hml
<div class="container"> <text class="title"> {{ $t('strings.hello') }} {{ title }} </text> <div class="rowcontainer"> <text class="content" if="{{statu == '0'}}">[状态:{{ $t('strings.ledoff') }}]</text> <text class="content" if="{{statu == '1'}}">[状态:{{ $t('strings.ledon') }}]</text> <text class="content" onclick="ledon"> {{ $t('strings.ledon') }} </text> <text class="content" onclick="ledoff"> {{ $t('strings.ledoff') }} </text> <text class="content" onclick="ledtoggle"> {{ $t('strings.ledtoggle') }} </text> </div> <text class="content" onclick="exit"> {{ $t('strings.exit') }} </text> </div>
- 修改index.css
.container { width: 100%; height: 100%; flex-direction: column; justify-content: center; align-items: center; } .title { width: 200px; font-size: 30px; text-align: center; } .content{ width: 200px; font-size: 30px; text-align: center; } .rowcontainer { width: 100%; height: 50%; flex-direction: row; justify-content: center; align-items: center; }
- 修改index.js
var led = {open:1,close:0,change:2} import app from '@system.app'; export default { data: { title: "", statu:'0' }, onInit() { this.title = this.$t('strings.world'); }, ledon(e) { let that = this console.info("ledon") app.ledcontrol({ code:led.open, success(res){ that.statu = res.led_status }, fail(res,code){ console.error("ledon error") }, complete(){ console.info("ledon complete") } }) }, ledoff(e) { let that = this console.info("ledoff") app.ledcontrol({ code:led.close, success(res){ that.statu = res.led_status }, fail(res,code){ console.error("ledoff error") }, complete(){ console.info("ledoff complete") } }) }, ledtoggle(e) { let that = this console.info("ledtoggle") app.ledcontrol({ code:led.change, success(res){ that.statu = res.led_status }, fail(res,code){ console.error("ledtoggle failed") }, complete(){ console.info("ledtoggle complete") } }) }, exit(e) { app.terminate() }, }
- 预览
-
将代码编译成hap包:点击编辑器最左下角的OhosBuild Varilants,打开编译模式选择视图,编译模式分debug和release,选择release模式;
-
点击编辑器上方菜单栏的Build->Build Hap(s)/App(s)->Build Hap(s),系统就会开始自动编译代码成hap包,等到下方Build Output无编译错误,就表示代码编译完成了。
-
增加JS的API接口
-
在app_module.h里增加接口
JSI::SetModuleAPI(exports, "ledcontrol", AppModule::ToggleLed);
-
在app_module.cpp里增加接口实现
#include "hdf_sbuf.h" #include "hdf_io_service_if.h" #define LED_WRITE_READ 1 #define LED_SERVICE "hdf_led" ...... static int OnDevEventReceived(void *priv, uint32_t id, struct HdfSBuf *data) { uint32_t value; HdfSbufReadUint32(data, &value); HILOG_ERROR(HILOG_MODULE_ACE,"%s: dev event received: %u %u\n", (char *)priv, id, value); return HDF_SUCCESS; } static int GpioWriteRead(struct HdfIoService *serv, int32_t eventData, int32_t *val) { int ret = HDF_FAILURE; struct HdfSBuf *data = HdfSBufObtainDefaultSize(); struct HdfSBuf *reply = HdfSBufObtainDefaultSize(); if (data == NULL || reply == NULL) { HILOG_ERROR(HILOG_MODULE_ACE,"fail to obtain sbuf data\n"); return ret; } if (!HdfSbufWriteUint8(data, (uint8_t)eventData)) { HILOG_ERROR(HILOG_MODULE_ACE,"fail to write sbuf\n"); HdfSBufRecycle(data); HdfSBufRecycle(reply); return ret; } ret = serv->dispatcher->Dispatch(&serv->object, LED_WRITE_READ, data, reply); if (ret != HDF_SUCCESS) { HILOG_ERROR(HILOG_MODULE_ACE,"fail to send service call\n"); HdfSBufRecycle(data); HdfSBufRecycle(reply); return ret; } if (!HdfSbufReadInt32(reply, val)) { HILOG_ERROR(HILOG_MODULE_ACE,"fail to get service call reply\n"); ret = HDF_ERR_INVALID_OBJECT; HdfSBufRecycle(data); HdfSBufRecycle(reply); return ret; } HILOG_ERROR(HILOG_MODULE_ACE,"Get reply is: %d\n", val); HdfSBufRecycle(data); HdfSBufRecycle(reply); return ret; } JSIValue AppModule::ToggleLed(const JSIValue thisVal, const JSIValue *args, uint8_t argsNum) { HILOG_ERROR(HILOG_MODULE_ACE, "led button pressed."); struct HdfIoService *serv = HdfIoServiceBind(LED_SERVICE); if (serv == NULL) { HILOG_ERROR(HILOG_MODULE_ACE,"fail to get service2 %s\n", LED_SERVICE); return JSI::CreateUndefined(); } if ((args == nullptr) || (argsNum == 0) || (JSI::ValueIsUndefined(args[0]))) { return JSI::CreateUndefined(); } JSIValue success = JSI::GetNamedProperty(args[0], CB_SUCCESS); JSIValue fail = JSI::GetNamedProperty(args[0], CB_FAIL); JSIValue complete = JSI::GetNamedProperty(args[0], CB_COMPLETE); int32_t num = (int32_t)JSI::GetNumberProperty(args[0], "code"); int32_t replyData = 0; if (GpioWriteRead(serv, num, &replyData)) { HILOG_ERROR(HILOG_MODULE_ACE,"fail to send event\n"); JSI::CallFunction(fail, thisVal, nullptr, 0); JSI::CallFunction(complete, thisVal, nullptr, 0); JSI::ReleaseValueList(success, fail, complete); return JSI::CreateUndefined(); } JSIValue result = JSI::CreateObject(); JSI::SetNumberProperty(result, "led_status", replyData); JSIValue argv[ARGC_ONE] = {result}; JSI::CallFunction(success, thisVal, argv, ARGC_ONE); JSI::CallFunction(complete, thisVal, nullptr, 0); JSI::ReleaseValueList(success, fail, complete, result); HdfIoServiceRecycle(serv); return JSI::CreateUndefined(); }
-
在
foundation\ace\ace_engine_lite\ace_lite.gni
中添加HDF头文件路径ace_lite_include_dirs += [ ...... "//drivers/framework/ability/sbuf/include", "//drivers/framework/include/core", "//drivers/framework/include/utils", "//drivers/adapter/uhdf/posix/include", ]
-
添加编译依赖
修改foundation\ace\ace_engine_lite\frameworks\BUILD.gn,在public_deps中添加以下代码 "//drivers/adapter/uhdf/manager:hdf_core", 修改foundation\ace\ace_engine_lite\test\ace_test_config.gni,在extra_deps中添加以下代码 "//drivers/adapter/uhdf/manager:hdf_core",
-
总结
- 基于JS扩展的类Web开发范式的方舟开发框架,采用经典的HML、CSS、JavaScript三段式开发方式。使用HML标签文件进行布局搭建,使用CSS文件进行样式描述,使用JavaScript文件进行逻辑处理。UI组件与数据之间通过单向数据绑定的方式建立关联,当数据发生变化时,UI界面自动触发更新。此种开发方式,更接近Web前端开发者的使用习惯,快速将已有的Web应用改造成方舟开发框架应用。主要适用于界面较为简单的中小型应用开发;
- 通过appmodule调用framework层接口,然后通过framework接口调用Hdf接口。
这样我们就有了自己的driver和配置,后面的章节我们会讲如何在hap应用里调用驱动接口
参考链接:
https://docs.openharmony.cn/pages/v3.1/zh-cn/application-dev/ui/ui-js-overview.md/
https://gitee.com/bearpi/bearpi-hm_micro_app/blob/master/README.md
终于到JS环节了
不错不错
学下JS下的应用开发
鸿蒙未来应该也会支持JS的吧