作者:王石
在《#跟着小白一起學鴻蒙# [九] 寫個簡單的LED驅動》我們熟悉了如何在開源鴻蒙開發驅動應用,并通過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(); }
- 在
中添加HDF頭檔案路徑foundation\ace\ace_engine_lite\ace_lite.gni
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",
- 在app_module.h裡增加接口
總結
- 基于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
代碼參考:
https://gitee.com/wshikh/ohosexample