#冲刺创作新星# [十] JS应用控制LED-鸿蒙开发者社区-51CTO.COM

#冲刺创作新星# [十] JS应用控制LED 原创 精华

左翼风发
发布于 2022-10-19 09:15
浏览
5收藏

作者:王石

在《[九] 写个简单的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

#冲刺创作新星# [十] JS应用控制LED-鸿蒙开发者社区

详细的内容介绍在一下链接内可以看到官方的说明:

参考链接: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

  1. 建立[Lite]Empty Ability

    #冲刺创作新星# [十] JS应用控制LED-鸿蒙开发者社区

  2. 配置工程
    #冲刺创作新星# [十] JS应用控制LED-鸿蒙开发者社区

  3. 工程结构说明

#冲刺创作新星# [十] JS应用控制LED-鸿蒙开发者社区

工程目录主要在entry里,有以下内容:

  • .preview: 界面预览目录;
  • build: 工程编译目录;
  • src:包括i18n(国际化翻译路径),pages(界面目录,index.css, index.hml, index.js)
  1. 工程预览

#冲刺创作新星# [十] JS应用控制LED-鸿蒙开发者社区

  1. 添加按键功能控制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()
        },
    
    }
    
    • 预览

#冲刺创作新星# [十] JS应用控制LED-鸿蒙开发者社区

  • 将代码编译成hap包:点击编辑器最左下角的OhosBuild Varilants,打开编译模式选择视图,编译模式分debug和release,选择release模式;

  • 点击编辑器上方菜单栏的Build->Build Hap(s)/App(s)->Build Hap(s),系统就会开始自动编译代码成hap包,等到下方Build Output无编译错误,就表示代码编译完成了。

  1. 增加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",
      

总结

  1. 基于JS扩展的类Web开发范式的方舟开发框架,采用经典的HML、CSS、JavaScript三段式开发方式。使用HML标签文件进行布局搭建,使用CSS文件进行样式描述,使用JavaScript文件进行逻辑处理。UI组件与数据之间通过单向数据绑定的方式建立关联,当数据发生变化时,UI界面自动触发更新。此种开发方式,更接近Web前端开发者的使用习惯,快速将已有的Web应用改造成方舟开发框架应用。主要适用于界面较为简单的中小型应用开发;
  2. 通过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

©著作权归作者所有,如需转载,请注明出处,否则将追究法律责任
已于2022-12-30 10:05:06修改
9
收藏 5
回复
举报
4条回复
按时间正序
/
按时间倒序
红叶亦知秋
红叶亦知秋

终于到JS环节了

回复
2022-10-19 10:06:31
物联风景
物联风景

不错不错

回复
2022-10-19 10:16:53
liurick
liurick

学下JS下的应用开发

回复
2022-10-21 14:16:21
wzhishun
wzhishun

鸿蒙未来应该也会支持JS的吧

回复
2022-10-21 17:00:02
回复
    相关推荐