mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
react-native code-gen > Add a C++ only TurboModule example (for Android/iOS/macOS/Windows) (#35138)
Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/35138 Changelog: [General][Added] - Add a C++ only TurboModule example (for Android/iOS/macOS/Windows) react-native@0.69 introduced a new bridging layer to ease integration for pure C++ TurboModules using C++ std:: types directly instead of the lower level jsi:: types: https://github.com/facebook/react-native/tree/v0.69.0/ReactCommon/react/bridging This bridging layer can be used in JSI functions or more conveniently in C++ TurboModules. Here is a example of an C++ only TurboModule which will work on Android and iOS and macOS/Windows (using microsoft/react-native-macos|windows) only using flow/TypeScript and standard C++ types. C++ only TurboModules are very handy as they do not require to work with JSI APIs - instead std:: or custom C++ can by used. Reviewed By: javache Differential Revision: D39011736 fbshipit-source-id: 84c833d8540671fde8505f1aeb0265074b248730
This commit is contained in:
committed by
Facebook GitHub Bot
parent
bbb3a6146c
commit
d07575b1c6
@@ -1,3 +1,4 @@
|
||||
load("@fbsource//tools/build_defs:glob_defs.bzl", "subdir_glob")
|
||||
load("@fbsource//xplat/hermes/defs:hermes.bzl", "HERMES_BYTECODE_VERSION")
|
||||
load("//tools/build_defs:fb_native_wrapper.bzl", "fb_native")
|
||||
load("//tools/build_defs:fb_xplat_platform_specific_rule.bzl", "fb_xplat_platform_specific_rule")
|
||||
@@ -10,6 +11,7 @@ load("//tools/build_defs/apple:flag_defs.bzl", "get_objc_arc_preprocessor_flags"
|
||||
load("//tools/build_defs/oss:metro_defs.bzl", "rn_library")
|
||||
load(
|
||||
"//tools/build_defs/oss:rn_defs.bzl",
|
||||
"ANDROID",
|
||||
"APPLE",
|
||||
"YOGA_APPLE_TARGET",
|
||||
"js_library_glob",
|
||||
@@ -49,6 +51,7 @@ rn_library(
|
||||
srcs = js_library_glob(
|
||||
[
|
||||
"js",
|
||||
"NativeCxxModuleExample",
|
||||
"NativeModuleExample",
|
||||
"NativeComponentExample",
|
||||
"RCTTest",
|
||||
@@ -61,10 +64,13 @@ rn_library(
|
||||
],
|
||||
),
|
||||
codegen_components = True,
|
||||
codegen_modules = True,
|
||||
labels = [
|
||||
"pfh:ReactNative_CommonInfrastructurePlaceholder",
|
||||
],
|
||||
native_component_spec_name = "AppSpecs",
|
||||
native_module_android_package_name = "com.facebook.fbreact.specs",
|
||||
native_module_spec_name = "AppSpecs",
|
||||
skip_processors = True,
|
||||
visibility = ["PUBLIC"],
|
||||
deps = [
|
||||
@@ -319,3 +325,24 @@ rn_xplat_cxx_library2(
|
||||
"//xplat/js/react-native-github:RCTFabricComponentViewsBase",
|
||||
],
|
||||
)
|
||||
|
||||
rn_xplat_cxx_library2(
|
||||
name = "NativeCxxModuleExample",
|
||||
srcs = glob(["NativeCxxModuleExample/*.cpp"]),
|
||||
header_namespace = "",
|
||||
exported_headers = subdir_glob(
|
||||
[
|
||||
("NativeCxxModuleExample", "*.h"),
|
||||
],
|
||||
prefix = "NativeCxxModuleExample",
|
||||
),
|
||||
fbandroid_compiler_flags = [
|
||||
"-fexceptions",
|
||||
"-frtti",
|
||||
],
|
||||
platforms = (ANDROID, APPLE),
|
||||
visibility = ["PUBLIC"],
|
||||
deps = [
|
||||
":AppSpecsJSI",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
# 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.
|
||||
|
||||
cmake_minimum_required(VERSION 3.13)
|
||||
set(CMAKE_VERBOSE_MAKEFILE on)
|
||||
|
||||
add_compile_options(
|
||||
-fexceptions
|
||||
-frtti
|
||||
-std=c++17
|
||||
-Wall
|
||||
-Wpedantic
|
||||
-Wno-gnu-zero-variadic-macro-arguments
|
||||
-DFOLLY_NO_CONFIG=1
|
||||
-DLOG_TAG=\"ReactNative\")
|
||||
|
||||
file(GLOB nativecxxmoduleexample_SRC CONFIGURE_DEPENDS *.cpp)
|
||||
add_library(nativecxxmoduleexample STATIC ${nativecxxmoduleexample_SRC})
|
||||
|
||||
target_include_directories(nativecxxmoduleexample PUBLIC .)
|
||||
target_include_directories(react_codegen_AppSpecs PUBLIC .)
|
||||
|
||||
target_link_libraries(nativecxxmoduleexample
|
||||
fbjni
|
||||
jsi
|
||||
react_nativemodule_core
|
||||
react_codegen_AppSpecs)
|
||||
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* 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 "NativeCxxModuleExample.h"
|
||||
|
||||
namespace facebook::react {
|
||||
|
||||
NativeCxxModuleExample::NativeCxxModuleExample(
|
||||
std::shared_ptr<CallInvoker> jsInvoker)
|
||||
: NativeCxxModuleExampleCxxSpec(std::move(jsInvoker)) {}
|
||||
|
||||
void NativeCxxModuleExample::getValueWithCallback(
|
||||
jsi::Runtime &rt,
|
||||
AsyncCallback<std::string> callback) {
|
||||
callback({"value from callback!"});
|
||||
}
|
||||
|
||||
std::vector<std::optional<ObjectStruct>> NativeCxxModuleExample::getArray(
|
||||
jsi::Runtime &rt,
|
||||
std::vector<std::optional<ObjectStruct>> arg) {
|
||||
return arg;
|
||||
}
|
||||
|
||||
bool NativeCxxModuleExample::getBool(jsi::Runtime &rt, bool arg) {
|
||||
return arg;
|
||||
}
|
||||
|
||||
ConstantsStruct NativeCxxModuleExample::getConstants(jsi::Runtime &rt) {
|
||||
return ConstantsStruct{true, 69, "react-native"};
|
||||
}
|
||||
|
||||
int32_t NativeCxxModuleExample::getEnum(jsi::Runtime &rt, int32_t arg) {
|
||||
return arg;
|
||||
}
|
||||
|
||||
std::map<std::string, std::optional<int32_t>> NativeCxxModuleExample::getMap(
|
||||
jsi::Runtime &rt,
|
||||
std::map<std::string, std::optional<int32_t>> arg) {
|
||||
return arg;
|
||||
}
|
||||
|
||||
double NativeCxxModuleExample::getNumber(jsi::Runtime &rt, double arg) {
|
||||
return arg;
|
||||
}
|
||||
|
||||
ObjectStruct NativeCxxModuleExample::getObject(
|
||||
jsi::Runtime &rt,
|
||||
ObjectStruct arg) {
|
||||
return arg;
|
||||
}
|
||||
|
||||
std::set<float> NativeCxxModuleExample::getSet(
|
||||
jsi::Runtime &rt,
|
||||
std::set<float> arg) {
|
||||
return arg;
|
||||
}
|
||||
|
||||
std::string NativeCxxModuleExample::getString(
|
||||
jsi::Runtime &rt,
|
||||
std::string arg) {
|
||||
return arg;
|
||||
}
|
||||
|
||||
std::string NativeCxxModuleExample::getUnion(
|
||||
jsi::Runtime &rt,
|
||||
float x,
|
||||
std::string y,
|
||||
jsi::Object z) {
|
||||
std::string result = "x: " + std::to_string(x) + ", y: " + y + ", z: { ";
|
||||
if (z.hasProperty(rt, "value")) {
|
||||
result += "value: ";
|
||||
result += std::to_string(z.getProperty(rt, "value").getNumber());
|
||||
} else if (z.hasProperty(rt, "low")) {
|
||||
result += "low: ";
|
||||
result += z.getProperty(rt, "low").getString(rt).utf8(rt);
|
||||
}
|
||||
result += " }";
|
||||
return result;
|
||||
}
|
||||
|
||||
ValueStruct NativeCxxModuleExample::getValue(
|
||||
jsi::Runtime &rt,
|
||||
double x,
|
||||
std::string y,
|
||||
ObjectStruct z) {
|
||||
ValueStruct result{x, y, z};
|
||||
return result;
|
||||
}
|
||||
|
||||
AsyncPromise<std::string> NativeCxxModuleExample::getValueWithPromise(
|
||||
jsi::Runtime &rt,
|
||||
bool error) {
|
||||
auto promise = AsyncPromise<std::string>(rt, jsInvoker_);
|
||||
if (error) {
|
||||
promise.reject("intentional promise rejection");
|
||||
} else {
|
||||
promise.resolve("result!");
|
||||
}
|
||||
return promise;
|
||||
}
|
||||
|
||||
void NativeCxxModuleExample::voidFunc(jsi::Runtime &rt) {
|
||||
// Nothing to do
|
||||
}
|
||||
|
||||
} // namespace facebook::react
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* 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
|
||||
|
||||
#if __has_include(<React-Codegen/AppSpecsJSI.h>) // CocoaPod headers on Apple
|
||||
#include <React-Codegen/AppSpecsJSI.h>
|
||||
#elif __has_include("AppSpecsJSI.h") // Cmake headers on Android
|
||||
#include "AppSpecsJSI.h"
|
||||
#else // BUCK headers
|
||||
#include <AppSpecs/AppSpecsJSI.h>
|
||||
#endif
|
||||
#include <memory>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "NativeCxxModuleExample_ConstantsStruct.h"
|
||||
#include "NativeCxxModuleExample_ObjectStruct.h"
|
||||
#include "NativeCxxModuleExample_ValueStruct.h"
|
||||
|
||||
namespace facebook::react {
|
||||
|
||||
class NativeCxxModuleExample
|
||||
: public NativeCxxModuleExampleCxxSpec<NativeCxxModuleExample> {
|
||||
public:
|
||||
NativeCxxModuleExample(std::shared_ptr<CallInvoker> jsInvoker);
|
||||
|
||||
void getValueWithCallback(
|
||||
jsi::Runtime &rt,
|
||||
AsyncCallback<std::string> callback);
|
||||
|
||||
std::vector<std::optional<ObjectStruct>> getArray(
|
||||
jsi::Runtime &rt,
|
||||
std::vector<std::optional<ObjectStruct>> arg);
|
||||
|
||||
bool getBool(jsi::Runtime &rt, bool arg);
|
||||
|
||||
ConstantsStruct getConstants(jsi::Runtime &rt);
|
||||
|
||||
int32_t getEnum(jsi::Runtime &rt, int32_t arg);
|
||||
|
||||
std::map<std::string, std::optional<int32_t>> getMap(
|
||||
jsi::Runtime &rt,
|
||||
std::map<std::string, std::optional<int32_t>> arg);
|
||||
|
||||
double getNumber(jsi::Runtime &rt, double arg);
|
||||
|
||||
ObjectStruct getObject(jsi::Runtime &rt, ObjectStruct arg);
|
||||
|
||||
std::set<float> getSet(jsi::Runtime &rt, std::set<float> arg);
|
||||
|
||||
std::string getString(jsi::Runtime &rt, std::string arg);
|
||||
|
||||
std::string getUnion(jsi::Runtime &rt, float x, std::string y, jsi::Object z);
|
||||
|
||||
ValueStruct
|
||||
getValue(jsi::Runtime &rt, double x, std::string y, ObjectStruct z);
|
||||
|
||||
AsyncPromise<std::string> getValueWithPromise(jsi::Runtime &rt, bool error);
|
||||
|
||||
void voidFunc(jsi::Runtime &rt);
|
||||
};
|
||||
|
||||
} // namespace facebook::react
|
||||
@@ -0,0 +1,64 @@
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @flow strict-local
|
||||
* @format
|
||||
*/
|
||||
|
||||
import type {TurboModule} from 'react-native/Libraries/TurboModule/RCTExport';
|
||||
|
||||
import {TurboModuleRegistry} from 'react-native';
|
||||
|
||||
/** FIXME: Enable flow-enum support
|
||||
export enum EnumInt {
|
||||
A = 23,
|
||||
B = 42,
|
||||
}
|
||||
*/
|
||||
|
||||
export type UnionFloat = 1.44 | 2.88 | 5.76;
|
||||
export type UnionString = 'One' | 'Two' | 'Three';
|
||||
export type UnionObject = {value: number} | {low: string};
|
||||
|
||||
export type ConstantsStruct = {|
|
||||
const1: boolean,
|
||||
const2: number,
|
||||
const3: string,
|
||||
|};
|
||||
|
||||
export type ObjectStruct = {|
|
||||
a: number,
|
||||
b: string,
|
||||
c?: ?string,
|
||||
|};
|
||||
|
||||
export type ValueStruct = {|
|
||||
x: number,
|
||||
y: string,
|
||||
z: ObjectStruct,
|
||||
|};
|
||||
|
||||
export interface Spec extends TurboModule {
|
||||
+getArray: (arg: Array<ObjectStruct | null>) => Array<ObjectStruct | null>;
|
||||
+getBool: (arg: boolean) => boolean;
|
||||
+getConstants: () => ConstantsStruct;
|
||||
// FIXME: Enable flow-enum support
|
||||
+getEnum: (arg: number /*EnumInt*/) => number /*EnumInt*/;
|
||||
+getMap: (arg: {[key: string]: ?number}) => {[key: string]: ?number};
|
||||
+getNumber: (arg: number) => number;
|
||||
+getObject: (arg: ObjectStruct) => ObjectStruct;
|
||||
+getSet: (arg: Array<number>) => Array<number>;
|
||||
+getString: (arg: string) => string;
|
||||
+getUnion: (x: UnionFloat, y: UnionString, z: UnionObject) => string;
|
||||
+getValue: (x: number, y: string, z: ObjectStruct) => ValueStruct;
|
||||
+getValueWithCallback: (callback: (value: string) => void) => void;
|
||||
+getValueWithPromise: (error: boolean) => Promise<string>;
|
||||
+voidFunc: () => void;
|
||||
}
|
||||
|
||||
export default (TurboModuleRegistry.get<Spec>(
|
||||
'NativeCxxModuleExampleCxx',
|
||||
): ?Spec);
|
||||
@@ -0,0 +1,31 @@
|
||||
# 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.
|
||||
|
||||
require "json"
|
||||
|
||||
package = JSON.parse(File.read(File.join(__dir__, "../package.json")))
|
||||
|
||||
Pod::Spec.new do |s|
|
||||
s.name = "NativeCxxModuleExample"
|
||||
s.version = package["version"]
|
||||
s.summary = package["description"]
|
||||
s.description = "NativeCxxModuleExample"
|
||||
s.homepage = "https://github.com/facebook/react-native.git"
|
||||
s.license = "MIT"
|
||||
s.platforms = { :ios => "12.4" }
|
||||
s.compiler_flags = '-Wno-nullability-completeness'
|
||||
s.author = "Meta Platforms, Inc. and its affiliates"
|
||||
s.source = { :git => "https://github.com/facebook/react-native.git", :tag => "#{s.version}" }
|
||||
s.source_files = "**/*.{h,cpp}"
|
||||
s.requires_arc = true
|
||||
s.pod_target_xcconfig = {
|
||||
"USE_HEADERMAP" => "YES",
|
||||
"CLANG_CXX_LANGUAGE_STANDARD" => "c++17"
|
||||
}
|
||||
|
||||
install_modules_dependencies(s)
|
||||
|
||||
s.dependency "ReactCommon/turbomodule/core"
|
||||
end
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* 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/Bridging.h>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
|
||||
namespace facebook::react {
|
||||
|
||||
struct ConstantsStruct {
|
||||
bool const1;
|
||||
int32_t const2;
|
||||
std::string const3;
|
||||
bool operator==(const ConstantsStruct &other) const {
|
||||
return const1 == other.const1 && const2 == other.const2 &&
|
||||
const3 == other.const3;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Bridging<ConstantsStruct> {
|
||||
static jsi::Object toJs(jsi::Runtime &rt, const ConstantsStruct &value) {
|
||||
auto result = facebook::jsi::Object(rt);
|
||||
result.setProperty(rt, "const1", bridging::toJs(rt, value.const1));
|
||||
result.setProperty(rt, "const2", bridging::toJs(rt, value.const2));
|
||||
result.setProperty(rt, "const3", bridging::toJs(rt, value.const3));
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace facebook::react
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* 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/Bridging.h>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
|
||||
namespace facebook::react {
|
||||
|
||||
struct ObjectStruct {
|
||||
int32_t a;
|
||||
std::string b;
|
||||
std::optional<std::string> c;
|
||||
bool operator==(const ObjectStruct &other) const {
|
||||
return a == other.a && b == other.b && c == other.c;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Bridging<ObjectStruct> {
|
||||
static ObjectStruct fromJs(
|
||||
jsi::Runtime &rt,
|
||||
const jsi::Object &value,
|
||||
const std::shared_ptr<CallInvoker> &jsInvoker) {
|
||||
ObjectStruct result{
|
||||
bridging::fromJs<int32_t>(rt, value.getProperty(rt, "a"), jsInvoker),
|
||||
bridging::fromJs<std::string>(
|
||||
rt, value.getProperty(rt, "b"), jsInvoker),
|
||||
bridging::fromJs<std::optional<std::string>>(
|
||||
rt, value.getProperty(rt, "c"), jsInvoker)};
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static jsi::Object toJs(jsi::Runtime &rt, const ObjectStruct &value) {
|
||||
auto result = facebook::jsi::Object(rt);
|
||||
result.setProperty(rt, "a", bridging::toJs(rt, value.a));
|
||||
result.setProperty(rt, "b", bridging::toJs(rt, value.b));
|
||||
if (value.c) {
|
||||
result.setProperty(rt, "c", bridging::toJs(rt, value.c.value()));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace facebook::react
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* 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/Bridging.h>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include "NativeCxxModuleExample_ObjectStruct.h"
|
||||
|
||||
namespace facebook::react {
|
||||
|
||||
struct ValueStruct {
|
||||
double x;
|
||||
std::string y;
|
||||
ObjectStruct z;
|
||||
bool operator==(const ValueStruct &other) const {
|
||||
return x == other.x && y == other.y && z == other.z;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Bridging<ValueStruct> {
|
||||
static ValueStruct fromJs(
|
||||
jsi::Runtime &rt,
|
||||
const jsi::Object &value,
|
||||
const std::shared_ptr<CallInvoker> &jsInvoker) {
|
||||
ValueStruct result{
|
||||
bridging::fromJs<double>(rt, value.getProperty(rt, "x"), jsInvoker),
|
||||
bridging::fromJs<std::string>(
|
||||
rt, value.getProperty(rt, "y"), jsInvoker),
|
||||
bridging::fromJs<ObjectStruct>(
|
||||
rt, value.getProperty(rt, "z"), jsInvoker)};
|
||||
return result;
|
||||
}
|
||||
|
||||
static jsi::Object toJs(jsi::Runtime &rt, const ValueStruct &value) {
|
||||
auto result = facebook::jsi::Object(rt);
|
||||
result.setProperty(rt, "x", bridging::toJs(rt, value.x));
|
||||
result.setProperty(rt, "y", bridging::toJs(rt, value.y));
|
||||
result.setProperty(rt, "z", bridging::toJs(rt, value.z));
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace facebook::react
|
||||
@@ -48,6 +48,9 @@ def pods(target_name, options = {}, use_flipper: !IN_CI && !USE_FRAMEWORKS)
|
||||
|
||||
# RNTester native modules and components
|
||||
pod 'ScreenshotManager', :path => "NativeModuleExample"
|
||||
if ENV['RCT_NEW_ARCH_ENABLED'] == '1'
|
||||
pod 'NativeCxxModuleExample', :path => "NativeCxxModuleExample"
|
||||
end
|
||||
end
|
||||
|
||||
target 'RNTester' do
|
||||
|
||||
@@ -7,6 +7,9 @@
|
||||
|
||||
#import "RNTesterTurboModuleProvider.h"
|
||||
|
||||
#ifdef RCT_NEW_ARCH_ENABLED
|
||||
#import <NativeCxxModuleExample/NativeCxxModuleExample.h>
|
||||
#endif
|
||||
#import <React/CoreModulesPlugins.h>
|
||||
#import <ReactCommon/RCTSampleTurboModule.h>
|
||||
#import <ReactCommon/SampleTurboCxxModule.h>
|
||||
@@ -28,7 +31,11 @@ std::shared_ptr<TurboModule> RNTesterTurboModuleProvider(
|
||||
if (name == "SampleTurboCxxModule") {
|
||||
return std::make_shared<SampleTurboCxxModule>(jsInvoker);
|
||||
}
|
||||
|
||||
#ifdef RCT_NEW_ARCH_ENABLED
|
||||
if (name == "NativeCxxModuleExampleCxx") {
|
||||
return std::make_shared<NativeCxxModuleExample>(jsInvoker);
|
||||
}
|
||||
#endif
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
@@ -11,7 +11,11 @@ project(appmodules)
|
||||
include(${REACT_ANDROID_DIR}/cmake-utils/ReactNative-application.cmake)
|
||||
|
||||
add_subdirectory(${REACT_COMMON_DIR}/react/nativemodule/samples/platform/android/ sampleturbomodule_build)
|
||||
add_subdirectory(${REACT_COMMON_DIR}/../packages/rn-tester/NativeCxxModuleExample/ nativecxxmoduleexample_build)
|
||||
|
||||
# RN Tester needs to link against the sample turbomobule
|
||||
target_link_libraries(${CMAKE_PROJECT_NAME}
|
||||
sampleturbomodule)
|
||||
# RN Tester needs to link against the NativeCxxModuleExample
|
||||
target_link_libraries(${CMAKE_PROJECT_NAME}
|
||||
nativecxxmoduleexample)
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include <AppSpecs.h>
|
||||
#include <DefaultComponentsRegistry.h>
|
||||
#include <DefaultTurboModuleManagerDelegate.h>
|
||||
#include <NativeCxxModuleExample.h>
|
||||
#include <ReactCommon/SampleTurboModuleSpec.h>
|
||||
#include <fbjni/fbjni.h>
|
||||
#include <react/renderer/componentregistry/ComponentDescriptorProviderRegistry.h>
|
||||
@@ -26,6 +27,9 @@ void registerComponents(
|
||||
std::shared_ptr<TurboModule> cxxModuleProvider(
|
||||
const std::string &name,
|
||||
const std::shared_ptr<CallInvoker> &jsInvoker) {
|
||||
if (name == "NativeCxxModuleExampleCxx") {
|
||||
return std::make_shared<NativeCxxModuleExample>(jsInvoker);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,222 @@
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @format
|
||||
* @flow strict-local
|
||||
*/
|
||||
|
||||
import type {RootTag} from 'react-native/Libraries/ReactNative/RootTag';
|
||||
|
||||
import {
|
||||
StyleSheet,
|
||||
Text,
|
||||
View,
|
||||
FlatList,
|
||||
Platform,
|
||||
TouchableOpacity,
|
||||
RootTagContext,
|
||||
} from 'react-native';
|
||||
import * as React from 'react';
|
||||
import NativeCxxModuleExample /*EnumInt,*/ from '../../../NativeCxxModuleExample/NativeCxxModuleExample';
|
||||
|
||||
type State = {|
|
||||
testResults: {
|
||||
[string]: {
|
||||
type: string,
|
||||
value: mixed,
|
||||
...
|
||||
},
|
||||
...
|
||||
},
|
||||
|};
|
||||
|
||||
type Examples =
|
||||
| 'callback'
|
||||
| 'getArray'
|
||||
| 'getBool'
|
||||
| 'getConstants'
|
||||
| 'getEnum'
|
||||
| 'getMap'
|
||||
| 'getNumber'
|
||||
| 'getObject'
|
||||
| 'getSet'
|
||||
| 'getString'
|
||||
| 'getUnion'
|
||||
| 'getValue'
|
||||
| 'promise'
|
||||
| 'rejectPromise'
|
||||
| 'voidFunc';
|
||||
|
||||
class NativeCxxModuleExampleExample extends React.Component<{||}, State> {
|
||||
static contextType: React$Context<RootTag> = RootTagContext;
|
||||
|
||||
state: State = {
|
||||
testResults: {},
|
||||
};
|
||||
|
||||
// Add calls to methods in TurboModule here
|
||||
// $FlowFixMe[missing-local-annot]
|
||||
_tests = {
|
||||
callback: () =>
|
||||
NativeCxxModuleExample?.getValueWithCallback(callbackValue =>
|
||||
this._setResult('callback', callbackValue),
|
||||
),
|
||||
getArray: () =>
|
||||
NativeCxxModuleExample?.getArray([
|
||||
{a: 1, b: 'foo'},
|
||||
{a: 2, b: 'bar'},
|
||||
null,
|
||||
]),
|
||||
getBool: () => NativeCxxModuleExample?.getBool(true),
|
||||
getConstants: () => NativeCxxModuleExample?.getConstants(),
|
||||
getEnum: () => NativeCxxModuleExample?.getEnum(/*EnumInt.A*/ 2),
|
||||
getMap: () => NativeCxxModuleExample?.getMap({a: 1, b: null, c: 3}),
|
||||
getNumber: () => NativeCxxModuleExample?.getNumber(99.95),
|
||||
getObject: () =>
|
||||
NativeCxxModuleExample?.getObject({a: 1, b: 'foo', c: null}),
|
||||
getSet: () => NativeCxxModuleExample?.getSet([1, 1.1, 1.1, 1.1, 2]),
|
||||
getString: () => NativeCxxModuleExample?.getString('Hello'),
|
||||
getUnion: () => NativeCxxModuleExample?.getUnion(1.44, 'Two', {low: '12'}),
|
||||
getValue: () =>
|
||||
NativeCxxModuleExample?.getValue(5, 'test', {a: 1, b: 'foo'}),
|
||||
promise: () =>
|
||||
NativeCxxModuleExample?.getValueWithPromise(false).then(valuePromise =>
|
||||
this._setResult('promise', valuePromise),
|
||||
),
|
||||
rejectPromise: () =>
|
||||
NativeCxxModuleExample?.getValueWithPromise(true)
|
||||
.then(() => {})
|
||||
.catch(e => this._setResult('rejectPromise', e.message)),
|
||||
voidFunc: () => NativeCxxModuleExample?.voidFunc(),
|
||||
};
|
||||
|
||||
_setResult(
|
||||
name: string | Examples,
|
||||
result:
|
||||
| $FlowFixMe
|
||||
| void
|
||||
| Array<$FlowFixMe>
|
||||
| boolean
|
||||
| {const1: boolean, const2: number, const3: string}
|
||||
| number
|
||||
| {[key: string]: ?number}
|
||||
| Promise<mixed>
|
||||
| number
|
||||
| string,
|
||||
) {
|
||||
this.setState(({testResults}) => ({
|
||||
testResults: {
|
||||
...testResults,
|
||||
/* $FlowFixMe[invalid-computed-prop] (>=0.111.0 site=react_native_fb)
|
||||
* This comment suppresses an error found when Flow v0.111 was
|
||||
* deployed. To see the error, delete this comment and run Flow. */
|
||||
[name]: {value: result, type: typeof result},
|
||||
},
|
||||
}));
|
||||
}
|
||||
|
||||
_renderResult(name: Examples): React.Node {
|
||||
const result = this.state.testResults[name] || {};
|
||||
return (
|
||||
<View style={styles.result}>
|
||||
<Text style={[styles.value]}>{JSON.stringify(result.value)}</Text>
|
||||
<Text style={[styles.type]}>{result.type}</Text>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
componentDidMount(): void {
|
||||
if (global.__turboModuleProxy == null) {
|
||||
throw new Error(
|
||||
'Cannot load this example because TurboModule is not configured.',
|
||||
);
|
||||
}
|
||||
Object.keys(this._tests).forEach(item =>
|
||||
this._setResult(item, this._tests[item]()),
|
||||
);
|
||||
}
|
||||
|
||||
render(): React.Node {
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<View style={styles.item}>
|
||||
<TouchableOpacity
|
||||
style={[styles.column, styles.button]}
|
||||
onPress={() =>
|
||||
Object.keys(this._tests).forEach(item =>
|
||||
this._setResult(item, this._tests[item]()),
|
||||
)
|
||||
}>
|
||||
<Text style={styles.buttonTextLarge}>Run all tests</Text>
|
||||
</TouchableOpacity>
|
||||
<TouchableOpacity
|
||||
onPress={() => this.setState({testResults: {}})}
|
||||
style={[styles.column, styles.button]}>
|
||||
<Text style={styles.buttonTextLarge}>Clear results</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
<FlatList
|
||||
data={Object.keys(this._tests)}
|
||||
keyExtractor={item => item}
|
||||
renderItem={({item}) => (
|
||||
<View style={styles.item}>
|
||||
<TouchableOpacity
|
||||
style={[styles.column, styles.button]}
|
||||
onPress={e => this._setResult(item, this._tests[item]())}>
|
||||
<Text style={styles.buttonText}>{item}</Text>
|
||||
</TouchableOpacity>
|
||||
<View style={[styles.column]}>{this._renderResult(item)}</View>
|
||||
</View>
|
||||
)}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
},
|
||||
item: {
|
||||
flexDirection: 'row',
|
||||
margin: 6,
|
||||
},
|
||||
column: {
|
||||
flex: 2,
|
||||
justifyContent: 'center',
|
||||
padding: 3,
|
||||
},
|
||||
result: {
|
||||
alignItems: 'stretch',
|
||||
justifyContent: 'space-between',
|
||||
},
|
||||
value: {
|
||||
fontFamily: Platform.OS === 'ios' ? 'Menlo' : 'monospace',
|
||||
fontSize: 12,
|
||||
},
|
||||
type: {
|
||||
color: '#333',
|
||||
fontSize: 10,
|
||||
},
|
||||
button: {
|
||||
borderColor: '#444',
|
||||
padding: 3,
|
||||
flex: 1,
|
||||
},
|
||||
buttonTextLarge: {
|
||||
textAlign: 'center',
|
||||
color: 'rgb(0,122,255)',
|
||||
fontSize: 16,
|
||||
padding: 6,
|
||||
},
|
||||
buttonText: {
|
||||
color: 'rgb(0,122,255)',
|
||||
textAlign: 'center',
|
||||
},
|
||||
});
|
||||
|
||||
module.exports = NativeCxxModuleExampleExample;
|
||||
@@ -0,0 +1,27 @@
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @format
|
||||
* @flow
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const React = require('react');
|
||||
const NativeCxxModuleExampleExample = require('./NativeCxxModuleExampleExample');
|
||||
|
||||
exports.displayName = (undefined: ?string);
|
||||
exports.title = 'Cxx TurboModule';
|
||||
exports.category = 'Basic';
|
||||
exports.description = 'Usage of Cxx TurboModule';
|
||||
exports.examples = [
|
||||
{
|
||||
title: 'TurboCxxModuleExample',
|
||||
render: function (): React.Element<any> {
|
||||
return <NativeCxxModuleExampleExample />;
|
||||
},
|
||||
},
|
||||
];
|
||||
@@ -288,6 +288,11 @@ const APIs: Array<RNTesterModuleInfo> = [
|
||||
category: 'Basic',
|
||||
module: require('../examples/TurboModule/TurboModuleExample'),
|
||||
},
|
||||
{
|
||||
key: 'TurboCxxModuleExample',
|
||||
category: 'Basic',
|
||||
module: require('../examples/TurboModule/TurboCxxModuleExample'),
|
||||
},
|
||||
];
|
||||
|
||||
if (ReactNativeFeatureFlags.shouldEmitW3CPointerEvents()) {
|
||||
|
||||
@@ -258,6 +258,10 @@ const APIs: Array<RNTesterModuleInfo> = [
|
||||
key: 'TurboModuleExample',
|
||||
module: require('../examples/TurboModule/TurboModuleExample'),
|
||||
},
|
||||
{
|
||||
key: 'TurboCxxModuleExample',
|
||||
module: require('../examples/TurboModule/TurboCxxModuleExample'),
|
||||
},
|
||||
{
|
||||
key: 'VibrationExample',
|
||||
module: require('../examples/Vibration/VibrationExample'),
|
||||
|
||||
Reference in New Issue
Block a user