React Native bridging 源码分析--ClassTest.cpp

源码目录:

cpp 复制代码
packages/react-native/ReactCommon/react/bridging/tests/ClassTest.cpp

源码:

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.
 */

#include "BridgingTest.h"

#include <utility>

namespace facebook::react {

using namespace std::literals;

struct TestClass {
  explicit TestClass(std::shared_ptr<CallInvoker> invoker)
      : invoker_(std::move(invoker)) {}

  double add(jsi::Runtime& /*unused*/, int a, float b) {
    return a + b;
  }

  jsi::Object getObject(jsi::Runtime& /*unused*/, jsi::Object obj) {
    return obj;
  }

  AsyncPromise<std::string> getPromise(jsi::Runtime& rt, std::string result) {
    auto promise = AsyncPromise<std::string>(rt, invoker_);
    promise.resolve(std::move(result));
    return promise;
  }

  std::string callFunc(
      jsi::Runtime& /*unused*/,
      SyncCallback<std::string(int)> func,
      int num) {
    return func(num);
  }

  void callAsync(jsi::Runtime& /*unused*/, const AsyncCallback<>& callback) {
    callback();
  }

 private:
  std::shared_ptr<CallInvoker> invoker_;
};

TEST_F(BridgingTest, callFromJsTest) {
  auto instance = TestClass(invoker);

  EXPECT_EQ(
      3.0,
      bridging::callFromJs<double>(
          rt, &TestClass::add, invoker, &instance, 1, 2.0));

  auto object = jsi::Object(rt);

  EXPECT_TRUE(
      jsi::Object::strictEquals(
          rt,
          object,
          bridging::callFromJs<jsi::Object>(
              rt, &TestClass::getObject, invoker, &instance, object)));

  auto promise = bridging::callFromJs<jsi::Object>(
      rt,
      &TestClass::getPromise,
      invoker,
      &instance,
      jsi::String::createFromAscii(rt, "hi"));
  auto then = promise.getPropertyAsFunction(rt, "then");

  std::string result;
  then.callWithThis(
      rt,
      promise,
      bridging::toJs(
          rt, [&](std::string res) { result = std::move(res); }, invoker));

  flushQueue();
  EXPECT_EQ("hi"s, result);

  auto func = function("(num) => String(num)");

  EXPECT_EQ(
      "1"s,
      bridging::callFromJs<jsi::String>(
          rt, &TestClass::callFunc, invoker, &instance, func, 1)
          .utf8(rt));

  bool called = false;
  func = bridging::toJs(rt, [&] { called = true; }, invoker);

  bridging::callFromJs<void>(
      rt, &TestClass::callAsync, invoker, &instance, func);

  flushQueue();
  EXPECT_TRUE(called);
}

struct MethodReturnTypeCastingTestObject {
 public:
  explicit MethodReturnTypeCastingTestObject(int value) : value_(value) {}

  int toInteger() const {
    return value_;
  }

 private:
  int value_;
};

template <>
struct Bridging<MethodReturnTypeCastingTestObject> {
  static MethodReturnTypeCastingTestObject fromJs(
      jsi::Runtime& /*rt*/,
      const jsi::Value& value) {
    return MethodReturnTypeCastingTestObject(
        static_cast<int>(value.asNumber()));
  }

  static int toJs(
      jsi::Runtime& /*rt*/,
      const MethodReturnTypeCastingTestObject& value) {
    return value.toInteger();
  }
};

struct MethodReturnTypeCastingTestClass {
  explicit MethodReturnTypeCastingTestClass(
      std::shared_ptr<CallInvoker> invoker)
      : invoker_(std::move(invoker)) {}

  // This is the key, return type is not a primitive, but an object with defined
  // bridging template.
  MethodReturnTypeCastingTestObject
  add(jsi::Runtime& /*unused*/, int a, int b) {
    return MethodReturnTypeCastingTestObject(a + b);
  }

 private:
  std::shared_ptr<CallInvoker> invoker_;
};

TEST_F(BridgingTest, methodReturnTypeCastingTest) {
  auto instance = MethodReturnTypeCastingTestClass(invoker);

  EXPECT_EQ(
      2,
      bridging::callFromJs<int>(
          rt,
          &MethodReturnTypeCastingTestClass::add,
          invoker,
          &instance,
          1,
          1));
}

} // namespace facebook::react

概述

本文档是 BridgingTest 测试套件的补充说明,聚焦验证 bridging::callFromJs 接口的功能正确性 ,覆盖两类核心场景:一是类成员方法的跨语言调用(支持基础类型、JSI 对象、Promise、同步 / 异步回调等参数与返回值);二是自定义桥接类型的返回值自动转换能力。该测试基于 Google Test(GTest)框架,继承 BridgingTest 基类提供的 JS 运行时与测试工具,确保 C++ 类成员方法通过桥接接口被正确调度,且类型转换符合预期。

测试环境与依赖

核心依赖

  1. 基础测试框架:Google Test(GTest)
  2. 父类测试环境BridgingTest(提供 Hermes JS 运行时 rt、测试用调用器 invokerflushQueue 异步任务刷新等能力)
  3. 桥接核心接口bridging::callFromJs(核心测试对象,用于跨语言调用 C++ 类成员方法)
  4. 辅助类型jsi::Runtime/jsi::Object/jsi::Function/AsyncPromise 等 JSI 与 React 桥接核心类型

继承关系

所有测试用例均继承 BridgingTest 基类,直接复用其初始化的 JS 运行时、调用器及辅助方法(如 function 用于创建 JS 函数实例)。

自定义辅助类型说明

测试中定义了 3 个自定义结构体 / 类及 1 个桥接模板特化,用于支撑测试场景,其详细信息如下:

1. 测试类:TestClass

类概述

cpp 复制代码
struct TestClass;

用于提供各类待测试的成员方法,覆盖不同参数类型、返回值类型的场景,构造函数接收 std::shared_ptr<CallInvoker> 用于初始化 AsyncPromise

核心成员方法

方法签名 返回值类型 功能描述 适用测试场景
double add(jsi::Runtime&, int a, float b) double 返回 a + b 的计算结果 基础类型参数与返回值测试
jsi::Object getObject(jsi::Runtime&, jsi::Object obj) jsi::Object 直接返回传入的 JSI 对象 JSI 对象参数与返回值测试
AsyncPromise<std::string> getPromise(jsi::Runtime&, std::string result) AsyncPromise<std::string> 创建并立即 resolve 的 Promise,返回指定字符串结果 Promise 类型返回值测试
std::string callFunc(jsi::Runtime&, SyncCallback<std::string(int)> func, int num) std::string 调用同步回调并返回其执行结果 同步回调参数测试
void callAsync(jsi::Runtime&, const AsyncCallback<>& callback) void 调用异步回调 异步回调参数测试

私有成员

成员名称 类型 功能描述
invoker_ std::shared_ptr<CallInvoker> 存储调用器实例,用于创建 AsyncPromise

2. 自定义桥接类型:MethodReturnTypeCastingTestObject

结构体概述

cpp 复制代码
struct MethodReturnTypeCastingTestObject;

自定义值对象,用于验证「非基础类型返回值」的桥接转换能力,内部存储一个 int 类型值。

核心成员

成员 / 方法 类型 / 签名 功能描述
value_ int(私有) 存储核心整数值
构造函数 explicit MethodReturnTypeCastingTestObject(int value) 初始化 value_
toInteger() const int 返回 value_,用于桥接转换为 JS 可识别类型

3. 桥接模板特化:Bridging<MethodReturnTypeCastingTestObject>

模板概述

cpp 复制代码
template <>
struct Bridging<MethodReturnTypeCastingTestObject>;

MethodReturnTypeCastingTestObject 提供自定义桥接逻辑,支持 JS→C++ 与 C++→JS 的类型转换,是返回值自动转换的核心依赖。

核心静态方法

方法签名 功能描述
static MethodReturnTypeCastingTestObject fromJs(jsi::Runtime&, const jsi::Value& value) JS 数值类型转自定义对象:将 jsi::Value 转为 int 后初始化 MethodReturnTypeCastingTestObject
static int toJs(jsi::Runtime&, const MethodReturnTypeCastingTestObject& value) 自定义对象转 JS 基础类型:调用 toInteger() 返回内部 int

4. 测试类:MethodReturnTypeCastingTestClass

类概述

cpp 复制代码
struct MethodReturnTypeCastingTestClass;

用于提供返回 MethodReturnTypeCastingTestObject 类型的成员方法,验证自定义桥接类型的返回值转换能力。

核心成员

成员 / 方法 类型 / 签名 功能描述
invoker_ std::shared_ptr<CallInvoker>(私有) 存储调用器实例(构造函数初始化)
add(jsi::Runtime&, int a, int b) MethodReturnTypeCastingTestObject 返回 a + b 初始化后的 MethodReturnTypeCastingTestObject 实例

测试用例详情

1. 类成员方法跨语言调用测试(callFromJsTest

测试目标

验证 bridging::callFromJs 接口能正确调度 TestClass 的各类成员方法,支持:

  1. 基础类型(int/float/double)的参数传递与返回值接收
  2. JSI 对象(jsi::Object)的参数传递与返回值一致性校验
  3. AsyncPromise 类型返回值的桥接与 JS 端 then 回调的执行
  4. 同步回调(SyncCallback)的参数传递与结果返回
  5. 异步回调(AsyncCallback)的参数传递与异步执行

测试场景与预期结果

测试场景 操作步骤 预期结果
基础类型方法调用(add 1. 创建 TestClass 实例 instance2. 调用 bridging::callFromJs<double>(rt, &TestClass::add, invoker, &instance, 1, 2.0) 返回值为 3.0,与 1 + 2.0 计算结果一致
JSI 对象方法调用(getObject 1. 创建 jsi::Object 实例 object2. 调用 bridging::callFromJs<jsi::Object>(rt, &TestClass::getObject, invoker, &instance, object)3. 通过 jsi::Object::strictEquals 校验返回值与原始对象 返回值与原始 object 严格相等,无对象拷贝异常
Promise 方法调用(getPromise 1. 调用 bridging::callFromJs<jsi::Object> 获取 JS Promise 实例 promise2. 获取 Promise 的 then 方法,传入自定义回调(存储结果到 std::string result)3. 调用 flushQueue 刷新异步任务队列 result 值为 "hi",与 getPromise 传入的参数一致
同步回调方法调用(callFunc 1. 创建 JS 函数 func(功能:接收 num 并返回其字符串形式)2. 调用 bridging::callFromJs<jsi::String>(rt, &TestClass::callFunc, invoker, &instance, func, 1)3. 转换返回值为 std::string 返回值为 "1",与 JS 函数执行结果一致
异步回调方法调用(callAsync 1. 创建异步回调 func(功能:将 bool called 设为 true)2. 调用 bridging::callFromJs<void>(rt, &TestClass::callAsync, invoker, &instance, func)3. 调用 flushQueue 刷新异步任务队列 called 值为 true,说明异步回调已执行

2. 自定义桥接类型返回值转换测试(methodReturnTypeCastingTest

测试目标

验证 bridging::callFromJs 支持「自定义桥接类型返回值」到指定基础类型的自动转换,即 MethodReturnTypeCastingTestClass::add 返回 MethodReturnTypeCastingTestObject,通过 Bridging<MethodReturnTypeCastingTestObject> 模板,自动转换为 int 类型返回值。

测试场景与预期结果

测试场景 操作步骤 预期结果
自定义类型返回值转换 1. 创建 MethodReturnTypeCastingTestClass 实例 instance2. 调用 bridging::callFromJs<int>(rt, &MethodReturnTypeCastingTestClass::add, invoker, &instance, 1, 1)3. 校验返回值 返回值为 2,与 1 + 1 计算结果一致,说明 MethodReturnTypeCastingTestObject 已通过自定义桥接模板转换为 int

核心原理

  1. MethodReturnTypeCastingTestClass::add 返回 MethodReturnTypeCastingTestObject(1+1)(内部 value_2
  2. bridging::callFromJs 检测到目标返回类型为 int,自动调用 Bridging<MethodReturnTypeCastingTestObject>::toJs 方法
  3. 该方法调用 toInteger() 返回 2,最终作为 bridging::callFromJs 的返回值

核心测试点总结

测试维度 覆盖场景 核心验证目标
方法调度正确性 基础类型、JSI 对象、Promise、同步 / 异步回调参数的成员方法 bridging::callFromJs 能正确传递参数并调度类成员方法
类型转换完整性 基础类型、自定义桥接类型的返回值 支持基础类型直接返回,支持自定义桥接类型到指定类型的自动转换
异步逻辑可靠性 异步回调、Promise 异步任务能通过 flushQueue 正常执行,结果符合预期
对象一致性 JSI 对象参数传递 JSI 对象跨方法调用后保持一致性,无非法拷贝或修改

注意事项

  1. 异步任务必须刷新队列 :涉及 AsyncPromiseAsyncCallback 的测试场景,需调用 flushQueue() 执行待调度的异步任务,否则断言会因结果未更新而失败。
  2. 自定义类型需提供桥接模板 :若需支持 bridging::callFromJs 对自定义类型的参数 / 返回值转换,必须特化 Bridging 模板,实现 fromJs(JS→C++)与 toJs(C++→JS)方法。
  3. 成员方法参数约束bridging::callFromJs 要求成员方法的第一个参数必须为 jsi::Runtime&,后续参数为业务参数,否则会触发编译错误。
  4. 返回值类型匹配bridging::callFromJs 的模板参数需与目标返回类型一致(或可通过自定义桥接模板转换为该类型),否则会触发类型不匹配错误。
相关推荐
小高0072 小时前
2026 年,只会写 div 和 css 的前端将彻底失业
前端·javascript·vue.js
www_stdio2 小时前
Git 提交AI神器:用大模型帮你写出规范的 Commit Message
前端·javascript·react.js
三月微暖寻春笋2 小时前
【和春笋一起学C++】(五十三)使用指向对象的指针
c++·初始化·指向对象的指针
摘星编程2 小时前
Flutter for OpenHarmony 实战:SliverList 滑动列表详解
android·javascript·flutter
凡大来啦2 小时前
Element plus的Select选择器点击不出现下拉列表
javascript·vue.js·elementui
lili-felicity2 小时前
React Native for Harmony 分类筛选页面多级菜单开发
react native·react.js·harmonyos
DEMO派2 小时前
CSS优先级规则以及如何提升优先级方案详解
前端·javascript·css·vue.js·reactjs·html5·angular.js
小夏卷编程2 小时前
ant-design-vue 2.0 a-table 中实现特殊行样式,选中样式,鼠标悬浮样式不一样
前端·javascript·vue.js
又见野草2 小时前
C++入门基础(初阶)
开发语言·c++