写点什么

【开源三方库】Aki:一行代码极简体验 JS&C++ 跨语言交互

  • 2023-08-07
    中国香港
  • 本文字数:3198 字

    阅读完需:约 10 分钟

【开源三方库】Aki:一行代码极简体验JS&C++跨语言交互

开源项目 OpenHarmony

是每个人的 OpenHarmony



一、简介

OpenAtom OpenHarmony(以下简称“OpenHarmony”)的前端开发语言是 ArkTS,在 TypeScript(简称 TS)生态基础上做了进一步扩展,继承了 TS 的所有特性,是 JavaScript(简称 JS)的超集。而 Node-API(简称 NAPI)是方舟引擎用于封装 JS 能力为 Native 插件的 API,是前端 JS 与 Native C/C++的 FFI(Foreign Function Interface 跨语言交互接口)。


Aki——针对 OpenHarmony 上提供 JS 与 C/C++跨语言互调的场景提供解决方案,提供了复杂度仅为 O(1)级别的极简语法糖使用方式,一行代码完成 JS 与 C/C++的无障碍跨语言互调,所键即所得。同时开发者无需关心 NAPI 的线程安全问题、Native 对象 GC 问题,为开发者屏蔽 NAPI 内部复杂逻辑。



OpenHarmony 中 NAPI 的用法不在本文阐述,不然就有点像孔乙己“茴香豆有几种写法”的感觉了。感兴趣的可以参考 OpenHarmony 关于 Native API 使用指导。而开发者使用 NAPI 过程中还会发现:为了做跨线程任务,需要做线程管理,需要关心环境上下文;为了使用结构体对象,需要关注 napi_value 生命周期如何管理;巴拉巴拉等等与自己业务无关的逻辑。搞了半天,发现业务代码一行没写,还在写 NAPI 的跨语言调用实现。拥有洁癖的开发者还会发现,很难做到隔离 NAPI 代码与业务代码,我们讨厌毫无边界性的编程。

二、所键即所得:NAPI 的尽头就是 Aki


归根结底 NAPI 要做的就是 FFI 即跨语言调用,而开发者重视的是自己的业务逻辑而不是如何做跨语言调用:我就想把大象放进冰箱,你非要告诉我:先打开冰箱,然后抬起大象放进去,再关上冰箱。开发者想要的就是直截了当指明这个函数是个跨语言调用函数。Aki 提供了 JSBind 语法糖,就做了这么一件事,开发者集成后,完全做到一行代码:所键即所得,并把业务代码与 FFI 代码完美隔离,提供了友好的边界性编程体验。


示例一:同步异步接口封装

示例一期望将 C++业务逻辑(GetName)注册为 JS 同步接口(getSync)、异步接口(getAsync),Aki 提供了极简的 JSBind 函数绑定语法糖,一行代码绑定跨语言调用接口:

● C/C++ Code#include <aki/jsbind.h>

#include <aki/jsbind.h>
// C++业务逻辑std::string GetName(std::string key){ std::string result = ...... // 获取数据的业务逻辑
return result; // 返回字符串类型}
// Aki JSBind语法糖JSBIND_ADDON(task_runner);JSBIND_GLOBAL() { JSBIND_FUNCTION(GetName, "getNameSync"); // 绑定同步方法 JSBIND_PFUNCTION(GetName, "getNameAsync"); // 绑定异步方法}
复制代码


● JavaScript Code


import libtask_runner from 'libtask_runner.so';
const name = libstorage.getNameSync('name');// 调用同步方法console.log('name is ' + name);
// 调用异步方法libstorage.getNameAsync('name').then(date => { console.log('name is ' + data);}).catch(error => { console.log('error: ' + error);});
复制代码


示例二:Native 与 JS 对象绑定

示例二期望将 C++结构体/类对象(Person)逻辑注册为 JS 类对象(Person),包含类构造函数+类成员函数+类静态函数+类属性访问等特性,通知支持类对象作为参数及返回值。Aki 提供了极简的 JSBind 对象绑定语法糖,开发者无需关注 Native 对象内存与 JS 引擎 GC 垃圾回收关系,直接绑定 Native 对象:


● C/C++ Code#include <aki/jsbind.h>

#include <aki/jsbind.h>
// C++逻辑struct Person { // 构造函数,用于JS侧 new 对象 Person(std::string name) : name(name) {}
// 静态函数 static Person GetAllPerson(); // 支持类对象作为参数
// 成员函数 int SayHello();
std::string name;};
// Aki JSBind语法糖JSBIND_ADDON(person);JSBIND_CLASS(Person) { JSBIND_CONSTRUCTOR<std::string>(); // 绑定构造函数 JSBIND_METHOD(GetAllPerson); // 绑定类静态函数 JSBIND_METHOD(SayHello); // 绑定类成员函数 JSBIND_PROPERTY(name); // 绑定类成员属性}

复制代码


● JavaScript Codeimport libperson from 'libperson.so';

import libperson from 'libperson.so';
let person = new libperson.Person("aki"); // 调用构造函数console.log('person name: ' + person.name); // 访问类属性let greeting = person.SayHello(); // 调用类成员函数let persons = libperson.Person.GetAllPerson(); // 调用类静态函数
复制代码


示例三:在非 JS 线程中回调 JS 接口

示例三期望在非 JS 线程中回调 JS 接口,Aki 提供了线程安全的 JSBind 语法糖,开发者无需关注 JS 线程安全问题——OpenHarmony 方舟引擎规定 JS 回调的任务必须抛到 JS 线程中才能执行,否则会出现崩溃(即 Native 侧只能在 JS 线程使用 NAPI)。


● C/C++ Code#include <aki/jsbind.h>

#include <aki/jsbind.h>
// C++逻辑void SafetyCallback(std::function<void (std::string)> callback) { std::thread t([callback = std::move(callback)] () { callback("aki"); // 线程安全,直接调用 }); t.detach();}
// Aki JSBind语法糖JSBIND_ADDON(sub_thread);JSBIND_GLOBAL() { JSBIND_FUNCTION(SafetyCallback);}
复制代码


● JavaScript Code

import libsub_thread from 'libsub_thread.so';// 入参为JS方法回调libsub_thread.SafetyCallback((data) => {  console.error('test result = ' + data); // test result = aki})
复制代码


示例四:Native 调用绑定 JS 函数

示例四期望在 C/C++侧调用 JS 接口(非回调)创建 rdb 关系型数据库表。Aki 提供了 JS 侧的内建 JSBind 语法糖,开发者可直接绑定 JS 侧函数供 Native 侧调用。


● JavaScript Code

import libAddon from 'libaddon.so'
function createTable(table: string) { rdbStore.executeSql()... // OHOS 关系型数据库逻辑}
libAddon.JSBind.bindFunction('createTable', createTable); // 绑定JS函数
复制代码


● C/C++ Code

#include <aki/jsbind.h>
// C++逻辑bool DoSomethingFromNative() { if (auto createTable = aki::JSBind::GetJSFunction("createTable")) { createTable->Invoke<void>("MYSTORE"); // 入参类型 string }
复制代码


示例五:类型转换

Aki 支持丰富的类型转换,几乎所有 JS 的数据类型都可以通过 Aki 映射为同等的 C/C++数据类型,开发者无需处理类型转换,如上述示例用法,框架支持自动匹配类型转换,下表为当前支持的完整类型转换关系:



三、集成依赖 Aki

1.创建平台工程

DevEco Studio 创建包含 Native C++的工程

File > New > Create Project | Module


2.配置依赖并安装

● ohpm 三方组件依赖:@ohos/aki

指定模块路径下(如:项目根路径/entry),输入如下命令安装 ohpm har 包依赖:

cd entryohpm install @ohos/aki
复制代码


CMakeLists.txt 添加依赖:

...set(AKI_ROOT_PATH ${CMAKE_CURRENT_SOURCE_DIR}/../../../oh_modules/@ohos/aki) # 设置AKI根路径set(CMAKE_MODULE_PATH ${AKI_ROOT_PATH})find_package(Aki REQUIRED)...target_link_libraries(${YOUR_TARGET} PUBLIC Aki::libjsbind) # 链接二进制依赖...
复制代码


● 源码依赖

用户自定义路径下(如:项目根路径/entry/src/main/cpp),输入如下命令下载源码:

cd entry/src/main/cppgit clone https://gitee.com/openharmony-sig/aki.git
复制代码


CMakeLists.txt 添加依赖:

...add_subdirectory(aki)target_link_libraries(entry PUBLIC aki_jsbind) // entry 为编译目标...
复制代码


3.编译工程 &运行

完成!!!


相关链接

《Aki 使用指导》

https://gitee.com/openharmony-sig/aki

《Aki example》

https://gitee.com/openharmony-sig/aki/tree/master/example/ohos

OpenHarmony 三方库中心仓

https://ohpm.openharmony.cn/#/cn/home

DevEco Studio

https://developer.harmonyos.com/cn/develop/deveco-studio/

Native API 使用指导

https://docs.openharmony.cn/pages/v4.0/zh-cn/application-dev/napi/napi-guidelines.md/


点击关注阅读原文,了解更多资讯

用户头像

OpenHarmony开发者官方账号 2021-12-15 加入

OpenHarmony是由开放原子开源基金会(OpenAtom Foundation)孵化及运营的开源项目,目标是面向全场景、全连接、全智能时代,基于开源的方式,搭建一个智能终端设备操作系统的框架和平台,促进万物互联产业的繁荣发展

评论

发布
暂无评论
【开源三方库】Aki:一行代码极简体验JS&C++跨语言交互_OpenHarmony_OpenHarmony开发者_InfoQ写作社区