callArkTSFunction 接口文档
目录
一、概述
1.1 简介
在 OpenHarmony Electron 适配层中,业务层(JS/TS)需要调用 ArkTS 侧的系统能力或自定义功能。systemPreferences.callArkTSFunction() 接口提供了一条从 Electron JS → ArkTS 的通用跨语言调用通道,支持多种参数类型和返回值类型的双向传递。
systemPreferences.callArkTSFunction()
底层通过 AKI 框架将 ArkTS 函数桥接到 C++,再由 C++ 层暴露给 Electron 主进程的 V8。C++ 通过 base::ThreadPool 将调用投递到工作线程执行,ArkTS 函数本身必须同步返回结果(不支持 async/Promise 返回值,详见第五章已知限制)。
1.2 功能特性
- 在
systemPreferences上提供callArkTSFunction方法 - 支持调用任意通过 AKI 绑定注册的 ArkTS 函数
- 支持 6 种返回值类型:
void/number/boolean/string/string[]/number[] - 支持 5 种参数类型:
number(int32/float/double)/boolean/string/Array<string>/Array<number> - JS 端返回
Promise(非阻塞主线程),但被调用的 ArkTS 函数必须同步执行 - 调用过程保持参数类型信息(不退化为字符串)
二、接口定义
2.1 JS 端签名
systemPreferences.callArkTSFunction(
functionName: string,
returnType?: string,
paramArray?: any[]
): Promise<{ type: string, value: any }>
2.2 参数说明
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
functionName |
string |
是 | AKI 注册的函数名,格式为 "模块名.方法名",如 "EtsBridge.TestReturnString" |
returnType |
string |
否 | 期望的返回值类型,默认 "void"。可选值:"void" / "number" / "boolean" / "string" / "string[]" / "number[]" |
paramArray |
any[] |
否 | 参数数组,每个元素为一个独立参数。数组类型参数需嵌套传入:[[1,2,3]] 表示传递一个数组参数 |
2.3 返回值
返回 Promise<{ type: string, value: any }>:
| 字段 | 类型 | 说明 |
|---|---|---|
type |
string |
返回值类型标识,与传入的 returnType 一致 |
value |
any |
实际返回值。void 类型固定返回 0 |
2.4 错误处理
接口在以下情况会 reject Promise:
functionName缺失或非字符串类型paramArray非数组类型- 参数数组中包含不支持的类型(如
Function) - ArkTS 函数执行抛出异常
三、类型映射表
3.1 参数类型映射表
| JS 类型 | V8 判断 | C++ TypedValue | ArkTS 类型 | 说明 |
|---|---|---|---|---|
| 整数 | IsInt32() |
int32_t |
number |
JS Int32 范围内的整数 |
| 浮点数 | IsNumber() |
double |
number |
JS Number 类型 |
| 布尔值 | IsBoolean() |
bool |
boolean |
true / false |
| 字符串 | IsString() |
std::string |
string |
UTF-8 字符串 |
| 数字数组 | IsArray() + 首元素 IsNumber() |
std::vector<double> |
Array<number> |
首元素为数字的数组 |
| 字符串数组 | IsArray() + 其他 |
std::vector<std::string> |
Array<string> |
其他数组默认按字符串数组处理 |
注:
Object(非数组、非函数)会被 JSON 序列化为字符串,但 ArkTS 侧无对应反序列化逻辑,不建议作为参数类型使用。
3.2 返回值类型映射表
| returnType | C++ 模板参数 | JS 返回值类型 | 说明 |
|---|---|---|---|
"void" |
void |
number |
固定返回 0 |
"number" |
double |
number |
双精度浮点数 |
"boolean" |
bool |
boolean |
布尔值 |
"string" |
std::string |
string |
UTF-8 字符串 |
"string[]" |
std::vector<std::string> |
string[] |
字符串数组 |
"number[]" |
std::vector<double> |
number[] |
数字数组 |
四、使用示例
4.1 JS 端调用示例
无参数调用
const { systemPreferences } = require('electron');
// 返回字符串
const res = await systemPreferences.callArkTSFunction(
'EtsBridge.TestReturnString', 'string');
// res = { type: "string", value: "ets bridge adapter" }
// 返回数字
const res2 = await systemPreferences.callArkTSFunction(
'EtsBridge.TestReturnNumber', 'number');
// res2 = { type: "number", value: 42 }
// 返回布尔值
const res3 = await systemPreferences.callArkTSFunction(
'EtsBridge.TestReturnBoolean', 'boolean');
// res3 = { type: "boolean", value: true }
// void 调用
const res4 = await systemPreferences.callArkTSFunction(
'EtsBridge.TestVoidReturn', 'void');
// res4 = { type: "void", value: 0 }
// 返回字符串数组
const res5 = await systemPreferences.callArkTSFunction(
'EtsBridge.TestReturnArrayString', 'string[]');
// res5 = { type: "string[]", value: ["ets", "bridge", "adapter"] }
// 返回数字数组
const res6 = await systemPreferences.callArkTSFunction(
'EtsBridge.TestReturnArrayNumber', 'number[]');
// res6 = { type: "number[]", value: [1, 2, 3] }
带参数调用
// 单个字符串参数
const res = await systemPreferences.callArkTSFunction(
'EtsBridge.TestReturnByStringParam', 'string', ['Hello ArkTS']);
// res = { type: "string", value: "Received param: Hello ArkTS" }
// 单个数字参数
const res2 = await systemPreferences.callArkTSFunction(
'EtsBridge.TestReturnByNumberParam', 'number', [123456]);
// res2 = { type: "number", value: 246912 }
// 单个布尔参数
const res3 = await systemPreferences.callArkTSFunction(
'EtsBridge.TestReturnByBooleanParam', 'boolean', [true]);
// res3 = { type: "boolean", value: false }
// 数组参数 —— 注意外层数组是 paramArray,内层数组才是实际参数
const res4 = await systemPreferences.callArkTSFunction(
'EtsBridge.TestReturnByStringArrayParam', 'string[]', [['a', 'b', 'c']]);
// res4 = { type: "string[]", value: ["a", "b", "c"] }
const res5 = await systemPreferences.callArkTSFunction(
'EtsBridge.TestReturnByNumberArrayParam', 'number[]', [[10, 20, 30]]);
// res5 = { type: "number[]", value: [10, 20, 30] }
多参数调用
// 2 个参数:(string, number) -> string
const res = await systemPreferences.callArkTSFunction(
'EtsBridge.TestTwoParams', 'string', ['hello', 42]);
// res = { type: "string", value: "hello_42" }
// 3 个参数:(string, number, boolean) -> string
const res2 = await systemPreferences.callArkTSFunction(
'EtsBridge.TestMultipleParams', 'string', ['test', 100, true]);
// res2 = { type: "string", value: "Combined: test_100_true" }
// 3 个同类型参数:(number, number, number) -> number
const res3 = await systemPreferences.callArkTSFunction(
'EtsBridge.TestThreeNumbers', 'number', [10, 20, 30]);
// res3 = { type: "number", value: 60 }
4.2 ArkTS 端注册新函数
要新增一个可被 callArkTSFunction 调用的 ArkTS 函数,需要完成以下步骤:
步骤 1:在 Adapter 中实现业务方法
在 EtsBridgeAdapter.ets(或自定义 Adapter)中添加业务方法。Adapter 类继承自 BaseAdapter 并通过 @injectable() 装饰:
// ets/adapter/EtsBridgeAdapter.ets
import { injectable } from 'inversify';
import { BaseAdapter } from '../common/BaseAdapter';
import LogMethod from '../common/LogDecorator';
@injectable()
export class EtsBridgeAdapter extends BaseAdapter {
@LogMethod
myCustomFunction(param1: string, param2: number): string {
return `Result: ${param1} - ${param2}`;
}
}
步骤 2:在 Bind 文件中创建包装函数并通过 AKI 注册
在 EtsBridgeAdapterBind.ets 中创建顶层包装函数(签名必须与 Adapter 方法一致),并通过 JsBindingUtils.bindFunction() 注册到 AKI:
// ets/jsbindings/EtsBridgeAdapterBind.ets
import JsBindingUtils from '../utils/JsBindingUtils';
import Inject from '../common/InjectModule';
import lazy { EtsBridgeAdapter } from '../adapter/EtsBridgeAdapter';
function implEtsBridgeAdapter(): EtsBridgeAdapter {
return Inject.getOrCreate(EtsBridgeAdapter);
}
// 包装函数 —— 签名必须与 Adapter 方法完全一致,AKI 会在 C++ 侧校验类型
function myCustomFunction(param1: string, param2: number): string {
return implEtsBridgeAdapter().myCustomFunction(param1, param2);
}
export class EtsBridgeAdapterBind {
static bind() {
// 注册到 AKI,C++ 通过 GetJSFunction("EtsBridge.MyCustomFunction") 检索
JsBindingUtils.bindFunction("EtsBridge.MyCustomFunction", myCustomFunction);
}
}
步骤 3:在 JsBindingMethod.ets 中调用 bind()
确保 EtsBridgeAdapterBind.bind() 在 ArkTS 启动阶段被调用:
// ets/jsbindings/JsBindingMethod.ets
import { EtsBridgeAdapterBind } from '../jsbindings/EtsBridgeAdapterBind';
export class JsBindingMethod {
static bindAll() {
// ... 其他 Adapter 的 bind()
EtsBridgeAdapterBind.bind();
// ...
}
}
步骤 4:JS 端调用
const res = await systemPreferences.callArkTSFunction(
'EtsBridge.MyCustomFunction', 'string', ['hello', 42]);
// res = { type: "string", value: "Result: hello - 42" }
4.3 命名规范
| 项目 | 规范 | 示例 |
|---|---|---|
| AKI 绑定名 | 模块名.PascalCase方法名 |
"EtsBridge.TestReturnString" |
| ArkTS 方法名 | camelCase |
testReturnString() |
| 包装函数名 | 与 ArkTS 方法名一致 | function testReturnString() |
五、已知限制
| 限制 | 说明 | 影响范围 |
|---|---|---|
| 暂不支持异步调用 | AKI 的 JSFunction::Invoke<R>() 直接读取同步返回值,无法 await Promise。ArkTS 函数若声明为 async 或返回 Promise<T>,AKI 类型校验会失败。JS 端的 Promise 仅来自 C++ 线程池包装,不代表 ArkTS 函数本身支持异步 |
业务层异步逻辑需在 ArkTS 端封装为同步调用;真正的异步通知能力见 第六章后续计划 |
| 暂不支持传入 Function 类型参数 | JS Function 在 C++ 层走 IsObject() && !IsFunction() 反向条件,落入 else 分支直接 reject |
无法把 JS 回调函数传给 ArkTS;后续将通过回调方案支持,见 第六章后续计划 |
| 暂不支持结构化 Object 参数 | C++ 侧检测到 Object 后会 JSON.stringify 降级为字符串透传,ArkTS 侧收到的是 JSON 字符串,需自行 JSON.parse,且类型信息丢失 |
业务层需自行约定 JSON schema 并在 ArkTS 侧手动反序列化 |
| 4+ 参数退化为字符串传递 | 超过 3 个参数时所有参数被转为 string(InvokeWithStringArgs 回退路径) |
需 ArkTS 侧自行 parse |
| 数组参数仅支持单参数场景 | 多参数(2-3 个)场景下 DispatchSimpleArg 仅支持 number/boolean/string 三种简单类型 |
多参数场景不能传数组 |
| 数组类型推断依赖首元素 | 空数组默认为 string[];混合类型数组可能推断错误 |
需保证数组元素类型一致 |
六、注意事项
-
数组参数的嵌套:
paramArray的每个元素对应一个 ArkTS 函数参数。传递数组类型参数时,需在外层再包一层数组:// 错误:[1,2,3] 会被解析为 3 个独立的 number 参数 callArkTSFunction('fn', 'number[]', [1, 2, 3]) // 正确:[[1,2,3]] 会被解析为 1 个 Array<number> 参数 callArkTSFunction('fn', 'number[]', [[1, 2, 3]]) -
AKI 绑定名必须精确匹配:JS 调用的
functionName必须与JsBindingUtils.bindFunction()注册的名称完全一致(区分大小写)。 -
函数签名一致性:AKI Bind 包装函数的参数类型和返回类型必须与 Adapter 方法一致。AKI 通过
JSFunction::Invoke<R>(P... args)在 C++ 侧做模板类型校验,类型不匹配会导致NapiValue<R>::CheckType断言失败。 -
Promise 不等于 ArkTS 异步:
callArkTSFunction在 JS 端返回Promise,是因为 C++ 通过base::ThreadPool::PostTaskAndReplyWithResult把调用投递到工作线程以避免阻塞主线程;但 ArkTS 侧的函数本身仍是同步执行——AKI 的Invoke<R>直接拿同步返回值,不会等待Promise。因此 ArkTS 函数不能声明为async,也不能返回Promise<T>。若需异步语义,请使用方案二的回调机制。 -
returnType 必须准确:
returnType必须与 ArkTS 函数实际返回类型一致。C++ 层根据returnType选择function_handler_中的处理器,错误的 returnType 会导致 AKI 类型校验失败。 -
返回值需取
.value:返回的{type, value}对象包含类型标识,业务层使用时通常取.value。