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 种参数类型:numberint32/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 个参数时所有参数被转为 stringInvokeWithStringArgs 回退路径) 需 ArkTS 侧自行 parse
数组参数仅支持单参数场景 多参数(2-3 个)场景下 DispatchSimpleArg 仅支持 number/boolean/string 三种简单类型 多参数场景不能传数组
数组类型推断依赖首元素 空数组默认为 string[];混合类型数组可能推断错误 需保证数组元素类型一致

六、注意事项

  1. 数组参数的嵌套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]])
    
  2. AKI 绑定名必须精确匹配:JS 调用的 functionName 必须与 JsBindingUtils.bindFunction() 注册的名称完全一致(区分大小写)。

  3. 函数签名一致性:AKI Bind 包装函数的参数类型和返回类型必须与 Adapter 方法一致。AKI 通过 JSFunction::Invoke<R>(P... args) 在 C++ 侧做模板类型校验,类型不匹配会导致 NapiValue<R>::CheckType 断言失败。

  4. Promise 不等于 ArkTS 异步callArkTSFunction 在 JS 端返回 Promise,是因为 C++ 通过 base::ThreadPool::PostTaskAndReplyWithResult 把调用投递到工作线程以避免阻塞主线程;但 ArkTS 侧的函数本身仍是同步执行——AKI 的 Invoke<R> 直接拿同步返回值,不会等待 Promise。因此 ArkTS 函数不能声明为 async,也不能返回 Promise<T>。若需异步语义,请使用方案二的回调机制。

  5. returnType 必须准确returnType 必须与 ArkTS 函数实际返回类型一致。C++ 层根据 returnType 选择 function_handler_ 中的处理器,错误的 returnType 会导致 AKI 类型校验失败。

  6. 返回值需取 .value:返回的 {type, value} 对象包含类型标识,业务层使用时通常取 .value


七、Demo


相关文档