代码目录:
packages/react-native/ReactCommon/react/bridging/Class.h
源代码:
cpp
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#pragma once
#include <react/bridging/Base.h>
namespace facebook::react::bridging {
template <typename JSReturnT, typename ClassT, typename ReturnT, typename... ArgsT, typename... JSArgsT>
JSReturnT callFromJs(
jsi::Runtime &rt,
ReturnT (ClassT::*method)(jsi::Runtime &, ArgsT...),
const std::shared_ptr<CallInvoker> &jsInvoker,
ClassT *instance,
JSArgsT &&...args)
{
static_assert(sizeof...(ArgsT) == sizeof...(JSArgsT), "Incorrect arguments length");
static_assert((supportsFromJs<ArgsT, JSArgsT> && ...), "Incompatible arguments");
if constexpr (std::is_void_v<JSReturnT>) {
static_assert(std::is_void_v<ReturnT>, "Method must return void when JSReturnT is void");
}
if constexpr (std::is_void_v<JSReturnT>) {
(instance->*method)(rt, fromJs<ArgsT>(rt, std::forward<JSArgsT>(args), jsInvoker)...);
} else if constexpr (std::is_void_v<ReturnT>) {
static_assert(std::is_same_v<JSReturnT, jsi::Value>, "Void functions may only return undefined");
(instance->*method)(rt, fromJs<ArgsT>(rt, std::forward<JSArgsT>(args), jsInvoker)...);
return jsi::Value();
} else if constexpr (is_jsi_v<JSReturnT> || supportsToJs<ReturnT, JSReturnT>) {
static_assert(supportsToJs<ReturnT, JSReturnT>, "Incompatible return type");
return toJs(rt, (instance->*method)(rt, fromJs<ArgsT>(rt, std::forward<JSArgsT>(args), jsInvoker)...), jsInvoker);
} else if constexpr (is_optional_jsi_v<JSReturnT>) {
static_assert(
is_optional_v<ReturnT> ? supportsToJs<typename ReturnT::value_type, typename JSReturnT::value_type>
: supportsToJs<ReturnT, typename JSReturnT::value_type>,
"Incompatible return type");
auto result =
toJs(rt, (instance->*method)(rt, fromJs<ArgsT>(rt, std::forward<JSArgsT>(args), jsInvoker)...), jsInvoker);
if constexpr (std::is_same_v<decltype(result), jsi::Value>) {
if (result.isNull() || result.isUndefined()) {
return std::nullopt;
}
}
return convert(rt, std::move(result));
} else {
static_assert(std::is_convertible_v<ReturnT, JSReturnT>, "Incompatible return type");
return (instance->*method)(rt, fromJs<ArgsT>(rt, std::forward<JSArgsT>(args), jsInvoker)...);
}
}
template <typename ReturnT, typename... ArgsT>
constexpr size_t getParameterCount(ReturnT (* /*unused*/)(ArgsT...))
{
return sizeof...(ArgsT);
}
template <typename Class, typename ReturnT, typename... ArgsT>
constexpr size_t getParameterCount(ReturnT (Class::* /*unused*/)(ArgsT...))
{
return sizeof...(ArgsT);
}
} // namespace facebook::react::bridging
概述
该头文件隶属于 facebook::react::bridging 命名空间,提供了两大核心功能:一是 callFromJs 模板函数,用于从 JavaScript(JSI)层安全调用 C++ 类成员方法,自动完成参数类型转换(JS→C++)与返回值类型转换(C++→JS);二是 getParameterCount 模板函数,用于在编译期获取普通函数 / 类成员函数的参数个数。该工具是 React Native 跨端框架中 JS 层与 C++ 层方法交互的核心支撑,保证了跨语言方法调用的类型安全与便捷性。
核心命名空间
cpp
facebook::react::bridging
所有工具函数均位于该命名空间下,与 React 桥接体系的其他组件(如类型转换、集合桥接)保持统一规范。
1. callFromJs 模板函数:JS 调用 C++ 类成员方法的核心桥接
1.1 模板定义
cpp
template <typename JSReturnT, typename ClassT, typename ReturnT, typename... ArgsT, typename... JSArgsT>
JSReturnT callFromJs(
jsi::Runtime &rt,
ReturnT (ClassT::*method)(jsi::Runtime &, ArgsT...),
const std::shared_ptr<CallInvoker> &jsInvoker,
ClassT *instance,
JSArgsT &&...args);
1.2 功能描述
作为 JS 层调用 C++ 类成员方法的统一入口,自动完成以下核心流程:
- 编译期类型校验:校验参数个数匹配性、参数类型兼容性、返回值类型兼容性。
- 参数转换 :将 JS 层传入的参数(
JSArgsT类型)通过fromJs方法批量转换为 C++ 成员方法所需的参数类型(ArgsT类型)。 - 方法调用:通过类实例指针调用目标成员方法。
- 返回值转换 :根据
JSReturnT(JS 层期望返回类型)与ReturnT(C++ 方法返回类型)的类型特性,自动选择最优转换逻辑,将 C++ 方法返回值转换为 JS 层可识别的类型。
1.3 参数说明
| 参数名 | 类型 | 必选 | 说明 |
|---|---|---|---|
rt |
jsi::Runtime & |
是 | JSI 运行时环境引用,提供 JS 层执行上下文,用于类型转换与方法执行。 |
method |
ReturnT (ClassT::*)(jsi::Runtime &, ArgsT...) |
是 | 指向 C++ 类 ClassT 成员方法的指针,该方法第一个参数固定为 jsi::Runtime &,后续为业务参数 ArgsT...。 |
jsInvoker |
const std::shared_ptr<CallInvoker> & |
是 | JS 调用器智能指针,用于支撑转换过程中可能的同步 / 异步 JS 方法调用,传递给底层 fromJs/toJs 方法。 |
instance |
ClassT * |
是 | C++ 类 ClassT 的实例指针,用于调用目标成员方法((instance->*method)(...))。 |
args |
JSArgsT &&... |
是 | 可变参数模板,JS 层传入的原始参数(右值引用,支持完美转发,减少拷贝开销)。 |
1.4 编译期静态断言(类型安全校验)
该函数内置 3 个核心静态断言,在编译期拦截非法调用,避免运行时错误:
static_assert(sizeof...(ArgsT) == sizeof...(JSArgsT), "Incorrect arguments length")- 功能:校验 C++ 成员方法的业务参数个数与 JS 传入的参数个数完全一致,不一致则编译失败。
static_assert((supportsFromJs<ArgsT, JSArgsT> && ...), "Incompatible arguments")- 功能:校验每一组
JSArgsT(JS 参数类型)都能通过fromJs转换为对应的ArgsT(C++ 参数类型),存在不兼容类型则编译失败。
- 功能:校验每一组
- 分支内静态断言(如返回值类型校验)
- 功能:针对不同返回值场景,校验
JSReturnT与ReturnT的兼容性,如 "当JSReturnT为void时,ReturnT必须也为void"。
- 功能:针对不同返回值场景,校验
1.5 核心分支逻辑(按返回值类型划分)
函数通过 if constexpr(C++17 编译期条件判断)实现不同返回值场景的分支处理,无运行时条件判断开销:
| 分支场景 | 适用条件 | 核心逻辑 | ||
|---|---|---|---|---|
| 1. 无返回值(JS/C++ 均为 void) | std::is_void_v<JSReturnT> |
1. 断言 ReturnT 也为 void(否则编译失败)2. 转换所有 JS 参数为 C++ 参数,调用类成员方法(无返回值,直接执行)3. 无返回值返回 |
||
| 2. C++ 无返回值,JS 期望 jsi::Value | std::is_void_v<ReturnT> && !std::is_void_v<JSReturnT> |
1. 断言 JSReturnT 为 jsi::Value(否则编译失败,因为无返回值方法仅能返回 JS undefined)2. 执行类成员方法3. 返回 jsi::Value()(对应 JS 层 undefined) |
||
| 3. 普通返回值转换(JSI 类型 / 支持 toJs 转换) | `is_jsi_v<JSReturnT> | supportsToJs<ReturnT, JSReturnT>` | 1. 断言 ReturnT 可转换为 JSReturnT(否则编译失败)2. 执行类成员方法,获取 C++ 返回值3. 调用 toJs 方法将返回值转换为 JSReturnT 类型并返回 |
|
| 4. 可选类型返回值转换(optional JSI 类型) | is_optional_jsi_v<JSReturnT> |
1. 断言 ReturnT(或可选类型的内部值类型)可转换为 JSReturnT 的内部值类型2. 执行类成员方法,通过 toJs 转换返回值3. 若转换结果为 jsi::Value 且是 null/undefined,返回 std::nullopt4. 否则通过 convert 函数转换为 JSReturnT 类型并返回 |
||
| 5. 直接类型转换(无桥接工具依赖) | 以上场景均不满足 | 1. 断言 ReturnT 可隐式转换为 JSReturnT(否则编译失败)2. 执行类成员方法,直接返回转换后的结果(无额外桥接转换逻辑) |
1.6 返回值
- 类型:
JSReturnT(模板参数指定,JS 层期望的返回类型,通常为jsi::Value或可选 JSI 类型) - 说明:根据不同分支场景,返回经过类型转换后的结果,与 JS 层类型完全兼容,可直接在 JS 层使用。
2. getParameterCount 模板函数:编译期获取函数参数个数
2.1 函数重载定义
重载 1:普通函数指针
cpp
template <typename ReturnT, typename... ArgsT>
constexpr size_t getParameterCount(ReturnT (* /*unused*/)(ArgsT...));
重载 2:类成员函数指针
cpp
template <typename Class, typename ReturnT, typename... ArgsT>
constexpr size_t getParameterCount(ReturnT (Class::* /*unused*/)(ArgsT...));
2.2 功能描述
在编译期(constexpr 函数)获取普通函数或 C++ 类成员函数的参数个数,无运行时开销,适用于模板元编程场景下的参数个数判断。
2.3 参数说明
| 参数名 | 类型 | 必选 | 说明 |
|---|---|---|---|
| (匿名参数) | 函数指针 / 类成员函数指针 | 是 | 目标函数的指针(仅用于推导模板参数 ArgsT...,无需实际传入值,标注为 /*unused*/) |
2.4 返回值
- 类型:
constexpr size_t(编译期常量,无符号整数) - 说明:返回函数的参数个数,即
sizeof...(ArgsT),其中ArgsT...是目标函数的参数类型列表。
2.5 适用场景
- 模板元编程中,根据函数参数个数进行条件分支选择。
- 跨语言方法绑定中,校验 JS 传入参数个数与 C++ 函数参数个数的一致性(与
callFromJs中的静态断言功能互补)。 - 自动生成方法绑定代码时,获取函数参数信息。
3. 核心特性总结
- 类型安全:通过静态断言与编译期类型推导,在编译期拦截参数个数不匹配、参数 / 返回值类型不兼容等问题,避免运行时异常。
- 自动转换 :无缝集成
fromJs/toJs类型转换工具,无需手动处理 JS 与 C++ 之间的类型映射,降低使用成本。 - 编译期优化 :使用
if constexpr、constexpr等 C++17 特性,所有条件判断与参数个数计算均在编译期完成,无运行时额外开销。 - 灵活适配:支持无返回值、普通返回值、可选类型返回值等多种场景,兼容 JSI 类型与普通 C++ 类型的转换需求。
- 完美转发 :对 JS 传入参数使用右值引用(
JSArgsT &&...)与std::forward,实现参数完美转发,减少不必要的内存拷贝。
4. 注意事项
- 依赖 C++17 及以上标准:需支持
if constexpr、constexpr函数、可变参数模板、完美转发等特性。 - 依赖 React 桥接组件:依赖
fromJs/toJs转换方法、supportsFromJs/supportsToJs兼容性判断常量、CallInvoker类、JSI 库(jsi::Runtime、jsi::Value)等,使用时需引入对应头文件与依赖。 - 类成员方法约束:目标类成员方法的第一个参数必须为
jsi::Runtime &,否则无法匹配callFromJs的方法指针参数类型。 - 可选类型支持:仅支持满足
is_optional_jsi_v特性的可选类型,通常为std::optional包裹的 JSI 类型。