HaaS UI小程序解决方案基础教学之六: 第一个自定义JSAPI

简介: HaaS UI内置的JSAPI为虽然JS提供了调用底层系统能力的接口,例如数据存储、网络管理、文件操作等,但是这些内置的JSAPI不能满足用户所有的开发需求。HaaS UI提供了扩展JSAPI的方法,用户可以根据项目需求和平台能力实现不同的扩展,以满足不同的功能需要。用户如果想要自定义一些JSAPI,可以按照本教程进行扩展。

名词解释
AliOS Things: 阿里云智能IoT团队自研的物联网操作系统

HaaS:全称是Hardware as a Service,阿里云智能IoT团队基于AliOS Things系统推出的硬件即服务

HaaS UI:全称是Hardware as a Service User Interface,是源自AliOS Things操作系统上的一套应用&图形解决方案,支持C/C++和 JS两种开发语言

1、HaaS UI JSAPI扩展

HaaS UI内置的JSAPI为虽然JS提供了调用底层系统能力的接口,例如数据存储、网络管理、文件操作等,但是这些内置的JSAPI不能满足用户所有的开发需求。HaaS UI提供了扩展JSAPI的方法,用户可以根据项目需求和平台能力实现不同的扩展,以满足不同的功能需要。用户如果想要自定义一些JSAPI,可以按照本教程进行扩展。

1.1、扩展JSAPI教程

本节内容用于扩展HaaS UI的JSAPI,提供js的扩展能力,下面将介绍一个demo JSAPI的编写步骤。

接口编写时主要有以下步骤:

  • 编写接口头文件和实现,以及接口的编译配置.
  • 注册接口到小程序容器
  • 修改小程序容器的编译配置,添加新增的jsapi模块

JSAPI工程目录:

aos.mk用于在alios things编译

├── jsapi_demo
        ├── ExtensionProxyBase.h
    ├── DemoApiExtension.cpp
    ├── DemoApiExtension.h
    └── aos.mk

1.1.1 、重要说明

  • 不论是接口还是事件,输入/输出的参数请确保为合法的json格式字符串
  • 在回调中mProxy->postCallback(),方法必须执行,否则会导致内存泄露.就算没有返回值也必须调用.
  • 接口定义参数为固定形式,只接收两个字符串类型参数,请参照testApi(const std::string& ,const std::string&)格式定义(不要修改定义)

1.1.2、 JSAPI方法实现

所有扩展的JSAPI在使用前需通过REGISTER_JSAPI()方法注册:

extensionProxy->REGISTER_JSAPI(&testApi, moduleName, testApi);

接口实现示例:

DemoApiExtension.h,依赖于ExtensionProxyBase.h:


#include "ExtensionProxyBase.h" // 扩展jsapi时需要include该头文件

using namespace ariver::iot;

namespace demo
{
    /**
     * 异步方法
     * @param callbackid naitve回调js方法时的回调id
     * @param params js调用native方法时的参数,json字符串
     */
    void testApi1(const std::string& callbackid, const std::string& params);

    /**
     * 同步方法
     * 同步方法和异步方法写法一模一样,区别在于上层js调用时是同步还是异步.
     * @param callbackid naitve回调js方法时的回调id
     * @param params js调用native方法时的参数,json字符串
     */
    void testApi2(const std::string& callbackid, const std::string& params);

    /**
     * jsapi注册方法
     *
     */
    extern "C" void testapi_init_jsapis();
};
}  // namespace demo

DemoApiExtension.cpp:


namespace falcon
{
/**
 * @param callbackid 用于回调js
 * @param params (必现是json格式)
 */
void testJSApi1(const std::string& callbackid, const std::string& params) // 异步方法
{
    /* user code */
    printf("Native testJSApi1 called params(%s).\n", params.c_str());
    /* user code */
    // callback
    ariver::iot::ExtensionProxyBase* extensionProxy = ariver::iot::getJSApiExtensionProxy();
    // 必须回调,成功返回成功,失败返回错误码
    extensionProxy->postCallback(callbackid, ariver::iot::API_Success, "{\"result\": \"testJSApi1 call success\"}");
}

/**
 * @param callbackid 用于回调js
 * @param params (必现是json格式)
 */
void testApi2(const std::string& callbackid, const std::string& params) // 同步方法
{
    printf("%s", ("testApi2 params:" + params + "\n").c_str());
    /*
     * 同步方法和异步方法写法一模一样,区别在于上层js调用时是同步还是异步.
     */
    std::string cbParams = "{\"paramsToJs\":\"result2\", \"otherOutput\":222}";
    // 必须回调,成功返回成功,失败返回错误码
    mProxy->postCallback(callbackid, API_Success, cbParams);
}

// extern给容器调用初始化
extern "C" void testapi_init_jsapis()
{
    ariver::iot::ExtensionProxyBase* extensionProxy = ariver::iot::getJSApiExtensionProxy();
    // call from js like:
    // import testapi from "$jsapi/testapi";
    // testapi.testJSApi1({}, r => {});
    extensionProxy->REGISTER_JSAPI(&testJSApi1, testapi, testJSApi1); 
    // param1: apiFunction, param2: module, param3: apiName
}
}

ExtensionProxyBase.h:

#include <string>
#include <stdio.h>
#include <map>

namespace ariver
{
namespace iot
{
enum APIStatus {
    API_Success = 0,
    API_NotSupport = 1,  // 无效的api调用
    API_ParamError = 2,  // 无效的参数
    API_Failed = 3,
    API_NoPermission = 4,
    API_Timeout,
    API_UserDenied,
    API_UserCancelled = 11,
};

class ExtensionProxyBase
{
public:
    typedef void (*InvokeFunction)(const std::string& callbackid, const std::string& params);

    /**
     * @deprecated
     * 后续会废弃,使用REGISTER_MODULE_JSAPI替代
     *
     * 业务方扩展JSAPI使用该接口注册
     * func: jsapi具体的实现函数
     * label_name: 映射到js端的函数名称,如$falcon.jsapi.alert label_name=alert
     */
#define REGISTER_STD_JSAPI(func, label_name) \
    registerJSApi(func, #label_name);

    /**
     * 业务方扩展JSAPI使用该接口注册
     * func: jsapi具体的实现函数
     * module: 模块名,映射到js端的模块名称,如$falcon.jsapi.module
     * label_name: 映射到js端的函数名称,如$falcon.jsapi.module.alert label_name=alert
     */
#define REGISTER_JSAPI(func, module, label_name) \
    registerJSApi(func, #module, #label_name);

    /**
     * @deprecated
     */
    virtual void registerJSApi(InvokeFunction func, const std::string& labelName) = 0;
    /**
     * 业务方扩展JSAPI使用该接口注册
     * func: jsapi具体的实现函数
     * module: 模块名,映射到js端的模块名称,如$falcon.jsapi.module
     * label_name: 映射到js端的函数名称,如$falcon.jsapi.module.alert label_name=alert
     */
    virtual void registerJSApi(InvokeFunction func, const std::string& module, const std::string& labelName) = 0;
    /**
     *  Jsapi回调函数
     *  callbackId: 如容器侧未下传callbackid,需要在jsapi extension实现侧自行生成
     */
    virtual void postCallback(const std::string& callbackid, APIStatus status, const std::string& params) = 0;

    /**
     *  容器上行发送自定义事件的接口
     *  js端使用 $falcon.on("customEvent", (param)=>{}) 注册
     *  customEvent: 事件名称
     *  param: 参数
     */
    virtual void sendCustomEvent(const std::string& customEvent, const std::string& param) = 0;

    /**
     *  容器上行发送自定义事件的接口
     *  js端使用方法
     *  import module from "$jsapi/moduleName"
     *  module.on("customEvent", (param)=>{})
     *  进行注册
     *
     *  module: 模块名称
     *  customEvent: 事件名称
     *  param: 参数
     */
    virtual void sendCustomEvent(const std::string& module, const std::string& customEvent, const std::string& param) = 0;
};

ExtensionProxyBase* getJSApiExtensionProxy();
}  // namespace iot
}  // namespace ariver

1.1.3、 添加接口目录下的编译文件

aos.mk


$(NAME)_MBINS_TYPE := share
$(NAME)_VERSION := 0.0.1    #版本号
$(NAME)_SUMMARY := jsapi demo #改为自己的模块描述

$(NAME)_INCLUDES += ./ #include路径

$(NAME)_SOURCES  += DemoApiExtension.cpp #源码列表

1.1.4、 向小程序容器注册接口

在容器初始化之前实例化JSAPI接口,在JSApilniter.cpp中调用初始化接口:

testapi_init_jsapis();

1.1.5、 修改JSAPI工程根目录下的编译文件

文件:jsapi/aos.mk


$(NAME)_MBINS_TYPE := share
$(NAME)_VERSION := 0.0.1
$(NAME)_SUMMARY := jsapi lib

$(NAME)_INCLUDES += ../common/include ./

$(NAME)_COMPONENTS += jsapi_demo
$(NAME)_COMPONENTS += jsapi_wifi
$(NAME)_COMPONENTS += jsapi_new #添加新增的接口模块
...

1.2、 扩展JSAPI调用

HaaS UI中的扩展jsapi接口挂载于$falcon.jsapi对象下,所有的扩展jsapi接口均可通过该对象访问.

调用jsapi将返回一个Promise对象 ,可通过callback回调,也可通过await等待请求返回.

$falcon.jsapi.testApi({}, (params) => {
  console.log("callback", params);
});

// 2.带模块名的api(推荐使用带模块名的api)
// 示例的模块名为testapi
const testapi = $falcon.jsapi.testapi;
// 通过callback回调
testapi.testApi({}, (params) => {
  console.log("callback", params);
});
// 或者使用await,需要在async方法中调用
const result = await testapi.testApi({});
if (result && result.error) {
  console.log('jsapi failed, error=', result.error);
} else {
    console.log('jsapi succeed', result);
}

2、开发者技术支持

如需更多技术支持,可加入钉钉开发者群,或者关注微信公众号

image.png

更多技术与解决方案介绍,请访问阿里云AIoT首页https://iot.aliyun.com/

相关文章
|
1月前
|
人工智能 小程序 前端开发
一个小程序轻量AR体感游戏,开发实现解决方案
针对青少年运动兴趣不足问题,AR体感游戏凭借沉浸式互动体验脱颖而出。结合小程序“AI运动识别”插件与WebGL渲染技术,可实现无需外设的轻量化AR健身游戏,如跳糕、切水果等,兼具趣味性与锻炼效果,适用于儿童健身及职工团建,即开即玩,低门槛高参与。
|
6月前
|
小程序 前端开发
2025商业版拓展校园圈子论坛网络的创新解决方案:校园跑腿小程序系统架构
校园跑腿小程序系统是一款创新解决方案,旨在满足校园配送需求并拓展校友网络。跑腿员可接单配送,用户能实时跟踪订单并评价服务。系统包含用户、客服、物流、跑腿员及订单模块,功能完善。此外,小程序增设信息咨询发布、校园社区建设和活动组织等功能,助力校友互动、经验分享及感情联络,构建紧密的校友网络。
268 1
2025商业版拓展校园圈子论坛网络的创新解决方案:校园跑腿小程序系统架构
|
6月前
|
JSON 监控 小程序
微信百度字节小程序包过大解决方案(实战经验总结)-优雅草卓伊凡|果果|小无
微信百度字节小程序包过大解决方案(实战经验总结)-优雅草卓伊凡|果果|小无
594 14
微信百度字节小程序包过大解决方案(实战经验总结)-优雅草卓伊凡|果果|小无
|
小程序 JavaScript 前端开发
uni-app开发微信小程序:四大解决方案,轻松应对主包与vendor.js过大打包难题
uni-app开发微信小程序:四大解决方案,轻松应对主包与vendor.js过大打包难题
2636 1
|
7月前
|
小程序 UED
拓展校友网络的创新解决方案:校园论坛圈子小程序+跑腿+二手市场系统
这是一款基于小程序的校园跑腿服务平台,支持多种注册登录方式、下单支付、跑腿接单配送、订单跟踪评价及物流查询功能,并配备客服模块提升用户体验。系统包含用户、客服、物流、跑腿员和订单五大核心模块,功能完善。此外,平台还拓展了校友网络功能,如信息咨询发布、校园社区建设和活动组织等,旨在增强校友互动与联系,形成紧密的校友生态。
251 4
|
11月前
「Mac畅玩鸿蒙与硬件46」UI互动应用篇23 - 自定义天气预报组件
本篇将带你实现一个自定义天气预报组件。用户可以通过选择不同城市来获取相应的天气信息,页面会显示当前城市的天气图标、温度及天气描述。这一功能适合用于动态展示天气信息的小型应用。
501 38
「Mac畅玩鸿蒙与硬件46」UI互动应用篇23 - 自定义天气预报组件
|
开发框架 人工智能 小程序
小程序常见的 UI 框架
【10月更文挑战第17天】小程序 UI 框架为开发者提供了便捷的工具和资源,帮助他们快速构建高质量的小程序界面。在选择框架时,需要综合考虑各种因素,以找到最适合项目的解决方案。随着技术的不断进步,UI 框架也将不断发展和创新,为小程序开发带来更多的便利和可能性。
846 58
|
UED
「Mac畅玩鸿蒙与硬件31」UI互动应用篇8 - 自定义评分星级组件
本篇将带你实现一个自定义评分星级组件,用户可以通过点击星星进行评分,并实时显示评分结果。为了让界面更具吸引力,我们还将添加一只小猫图片作为评分的背景装饰。
288 6
「Mac畅玩鸿蒙与硬件31」UI互动应用篇8 - 自定义评分星级组件
|
前端开发 开发者
「Mac畅玩鸿蒙与硬件23」鸿蒙UI组件篇13 - 自定义组件的创建与使用
自定义组件可以帮助开发者实现复用性强、逻辑清晰的界面模块。通过自定义组件,鸿蒙应用能够提高代码的可维护性,并简化复杂布局的构建。本篇将介绍如何创建自定义组件,如何向组件传递数据,以及如何在不同页面间复用这些组件。
298 5
「Mac畅玩鸿蒙与硬件23」鸿蒙UI组件篇13 - 自定义组件的创建与使用
|
API UED 容器
深入探索 Element UI:自定义滚动条与弹出层管理的技巧
在这篇博客中,我们将深入探讨 Element UI 中的自定义滚动条及弹出层管理技巧。文章详细介绍了 el-scrollbar 组件的使用和参数设置,以及 PopupManager 如何有效管理弹出层的 z-index。我们还将探讨如何实现灵活的全屏组件,利用 vue-popper 创建自定义弹出层,最后介绍 ClickOutside 指令的用法。这些高级技巧将帮助你提升 Element UI 应用程序的用户体验与交互灵活性。
1323 1
深入探索 Element UI:自定义滚动条与弹出层管理的技巧