Skip to content

Commit d07575b

Browse files
react-native code-gen > Add a C++ only TurboModule example (for Android/iOS/macOS/Windows) (#35138)
Summary: Pull Request resolved: #35138 Changelog: [General][Added] - Add a C++ only TurboModule example (for Android/iOS/macOS/Windows) [email protected] 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
1 parent bbb3a61 commit d07575b

17 files changed

+745
-1
lines changed

packages/rn-tester/BUCK

+27
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
load("@fbsource//tools/build_defs:glob_defs.bzl", "subdir_glob")
12
load("@fbsource//xplat/hermes/defs:hermes.bzl", "HERMES_BYTECODE_VERSION")
23
load("//tools/build_defs:fb_native_wrapper.bzl", "fb_native")
34
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"
1011
load("//tools/build_defs/oss:metro_defs.bzl", "rn_library")
1112
load(
1213
"//tools/build_defs/oss:rn_defs.bzl",
14+
"ANDROID",
1315
"APPLE",
1416
"YOGA_APPLE_TARGET",
1517
"js_library_glob",
@@ -49,6 +51,7 @@ rn_library(
4951
srcs = js_library_glob(
5052
[
5153
"js",
54+
"NativeCxxModuleExample",
5255
"NativeModuleExample",
5356
"NativeComponentExample",
5457
"RCTTest",
@@ -61,10 +64,13 @@ rn_library(
6164
],
6265
),
6366
codegen_components = True,
67+
codegen_modules = True,
6468
labels = [
6569
"pfh:ReactNative_CommonInfrastructurePlaceholder",
6670
],
6771
native_component_spec_name = "AppSpecs",
72+
native_module_android_package_name = "com.facebook.fbreact.specs",
73+
native_module_spec_name = "AppSpecs",
6874
skip_processors = True,
6975
visibility = ["PUBLIC"],
7076
deps = [
@@ -319,3 +325,24 @@ rn_xplat_cxx_library2(
319325
"//xplat/js/react-native-github:RCTFabricComponentViewsBase",
320326
],
321327
)
328+
329+
rn_xplat_cxx_library2(
330+
name = "NativeCxxModuleExample",
331+
srcs = glob(["NativeCxxModuleExample/*.cpp"]),
332+
header_namespace = "",
333+
exported_headers = subdir_glob(
334+
[
335+
("NativeCxxModuleExample", "*.h"),
336+
],
337+
prefix = "NativeCxxModuleExample",
338+
),
339+
fbandroid_compiler_flags = [
340+
"-fexceptions",
341+
"-frtti",
342+
],
343+
platforms = (ANDROID, APPLE),
344+
visibility = ["PUBLIC"],
345+
deps = [
346+
":AppSpecsJSI",
347+
],
348+
)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# Copyright (c) Meta Platforms, Inc. and affiliates.
2+
#
3+
# This source code is licensed under the MIT license found in the
4+
# LICENSE file in the root directory of this source tree.
5+
6+
cmake_minimum_required(VERSION 3.13)
7+
set(CMAKE_VERBOSE_MAKEFILE on)
8+
9+
add_compile_options(
10+
-fexceptions
11+
-frtti
12+
-std=c++17
13+
-Wall
14+
-Wpedantic
15+
-Wno-gnu-zero-variadic-macro-arguments
16+
-DFOLLY_NO_CONFIG=1
17+
-DLOG_TAG=\"ReactNative\")
18+
19+
file(GLOB nativecxxmoduleexample_SRC CONFIGURE_DEPENDS *.cpp)
20+
add_library(nativecxxmoduleexample STATIC ${nativecxxmoduleexample_SRC})
21+
22+
target_include_directories(nativecxxmoduleexample PUBLIC .)
23+
target_include_directories(react_codegen_AppSpecs PUBLIC .)
24+
25+
target_link_libraries(nativecxxmoduleexample
26+
fbjni
27+
jsi
28+
react_nativemodule_core
29+
react_codegen_AppSpecs)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
/*
2+
* Copyright (c) Meta Platforms, Inc. and affiliates.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*/
7+
8+
#include "NativeCxxModuleExample.h"
9+
10+
namespace facebook::react {
11+
12+
NativeCxxModuleExample::NativeCxxModuleExample(
13+
std::shared_ptr<CallInvoker> jsInvoker)
14+
: NativeCxxModuleExampleCxxSpec(std::move(jsInvoker)) {}
15+
16+
void NativeCxxModuleExample::getValueWithCallback(
17+
jsi::Runtime &rt,
18+
AsyncCallback<std::string> callback) {
19+
callback({"value from callback!"});
20+
}
21+
22+
std::vector<std::optional<ObjectStruct>> NativeCxxModuleExample::getArray(
23+
jsi::Runtime &rt,
24+
std::vector<std::optional<ObjectStruct>> arg) {
25+
return arg;
26+
}
27+
28+
bool NativeCxxModuleExample::getBool(jsi::Runtime &rt, bool arg) {
29+
return arg;
30+
}
31+
32+
ConstantsStruct NativeCxxModuleExample::getConstants(jsi::Runtime &rt) {
33+
return ConstantsStruct{true, 69, "react-native"};
34+
}
35+
36+
int32_t NativeCxxModuleExample::getEnum(jsi::Runtime &rt, int32_t arg) {
37+
return arg;
38+
}
39+
40+
std::map<std::string, std::optional<int32_t>> NativeCxxModuleExample::getMap(
41+
jsi::Runtime &rt,
42+
std::map<std::string, std::optional<int32_t>> arg) {
43+
return arg;
44+
}
45+
46+
double NativeCxxModuleExample::getNumber(jsi::Runtime &rt, double arg) {
47+
return arg;
48+
}
49+
50+
ObjectStruct NativeCxxModuleExample::getObject(
51+
jsi::Runtime &rt,
52+
ObjectStruct arg) {
53+
return arg;
54+
}
55+
56+
std::set<float> NativeCxxModuleExample::getSet(
57+
jsi::Runtime &rt,
58+
std::set<float> arg) {
59+
return arg;
60+
}
61+
62+
std::string NativeCxxModuleExample::getString(
63+
jsi::Runtime &rt,
64+
std::string arg) {
65+
return arg;
66+
}
67+
68+
std::string NativeCxxModuleExample::getUnion(
69+
jsi::Runtime &rt,
70+
float x,
71+
std::string y,
72+
jsi::Object z) {
73+
std::string result = "x: " + std::to_string(x) + ", y: " + y + ", z: { ";
74+
if (z.hasProperty(rt, "value")) {
75+
result += "value: ";
76+
result += std::to_string(z.getProperty(rt, "value").getNumber());
77+
} else if (z.hasProperty(rt, "low")) {
78+
result += "low: ";
79+
result += z.getProperty(rt, "low").getString(rt).utf8(rt);
80+
}
81+
result += " }";
82+
return result;
83+
}
84+
85+
ValueStruct NativeCxxModuleExample::getValue(
86+
jsi::Runtime &rt,
87+
double x,
88+
std::string y,
89+
ObjectStruct z) {
90+
ValueStruct result{x, y, z};
91+
return result;
92+
}
93+
94+
AsyncPromise<std::string> NativeCxxModuleExample::getValueWithPromise(
95+
jsi::Runtime &rt,
96+
bool error) {
97+
auto promise = AsyncPromise<std::string>(rt, jsInvoker_);
98+
if (error) {
99+
promise.reject("intentional promise rejection");
100+
} else {
101+
promise.resolve("result!");
102+
}
103+
return promise;
104+
}
105+
106+
void NativeCxxModuleExample::voidFunc(jsi::Runtime &rt) {
107+
// Nothing to do
108+
}
109+
110+
} // namespace facebook::react
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
/*
2+
* Copyright (c) Meta Platforms, Inc. and affiliates.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*/
7+
8+
#pragma once
9+
10+
#if __has_include(<React-Codegen/AppSpecsJSI.h>) // CocoaPod headers on Apple
11+
#include <React-Codegen/AppSpecsJSI.h>
12+
#elif __has_include("AppSpecsJSI.h") // Cmake headers on Android
13+
#include "AppSpecsJSI.h"
14+
#else // BUCK headers
15+
#include <AppSpecs/AppSpecsJSI.h>
16+
#endif
17+
#include <memory>
18+
#include <set>
19+
#include <string>
20+
#include <vector>
21+
#include "NativeCxxModuleExample_ConstantsStruct.h"
22+
#include "NativeCxxModuleExample_ObjectStruct.h"
23+
#include "NativeCxxModuleExample_ValueStruct.h"
24+
25+
namespace facebook::react {
26+
27+
class NativeCxxModuleExample
28+
: public NativeCxxModuleExampleCxxSpec<NativeCxxModuleExample> {
29+
public:
30+
NativeCxxModuleExample(std::shared_ptr<CallInvoker> jsInvoker);
31+
32+
void getValueWithCallback(
33+
jsi::Runtime &rt,
34+
AsyncCallback<std::string> callback);
35+
36+
std::vector<std::optional<ObjectStruct>> getArray(
37+
jsi::Runtime &rt,
38+
std::vector<std::optional<ObjectStruct>> arg);
39+
40+
bool getBool(jsi::Runtime &rt, bool arg);
41+
42+
ConstantsStruct getConstants(jsi::Runtime &rt);
43+
44+
int32_t getEnum(jsi::Runtime &rt, int32_t arg);
45+
46+
std::map<std::string, std::optional<int32_t>> getMap(
47+
jsi::Runtime &rt,
48+
std::map<std::string, std::optional<int32_t>> arg);
49+
50+
double getNumber(jsi::Runtime &rt, double arg);
51+
52+
ObjectStruct getObject(jsi::Runtime &rt, ObjectStruct arg);
53+
54+
std::set<float> getSet(jsi::Runtime &rt, std::set<float> arg);
55+
56+
std::string getString(jsi::Runtime &rt, std::string arg);
57+
58+
std::string getUnion(jsi::Runtime &rt, float x, std::string y, jsi::Object z);
59+
60+
ValueStruct
61+
getValue(jsi::Runtime &rt, double x, std::string y, ObjectStruct z);
62+
63+
AsyncPromise<std::string> getValueWithPromise(jsi::Runtime &rt, bool error);
64+
65+
void voidFunc(jsi::Runtime &rt);
66+
};
67+
68+
} // namespace facebook::react
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
/**
2+
* Copyright (c) Meta Platforms, Inc. and affiliates.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*
7+
* @flow strict-local
8+
* @format
9+
*/
10+
11+
import type {TurboModule} from 'react-native/Libraries/TurboModule/RCTExport';
12+
13+
import {TurboModuleRegistry} from 'react-native';
14+
15+
/** FIXME: Enable flow-enum support
16+
export enum EnumInt {
17+
A = 23,
18+
B = 42,
19+
}
20+
*/
21+
22+
export type UnionFloat = 1.44 | 2.88 | 5.76;
23+
export type UnionString = 'One' | 'Two' | 'Three';
24+
export type UnionObject = {value: number} | {low: string};
25+
26+
export type ConstantsStruct = {|
27+
const1: boolean,
28+
const2: number,
29+
const3: string,
30+
|};
31+
32+
export type ObjectStruct = {|
33+
a: number,
34+
b: string,
35+
c?: ?string,
36+
|};
37+
38+
export type ValueStruct = {|
39+
x: number,
40+
y: string,
41+
z: ObjectStruct,
42+
|};
43+
44+
export interface Spec extends TurboModule {
45+
+getArray: (arg: Array<ObjectStruct | null>) => Array<ObjectStruct | null>;
46+
+getBool: (arg: boolean) => boolean;
47+
+getConstants: () => ConstantsStruct;
48+
// FIXME: Enable flow-enum support
49+
+getEnum: (arg: number /*EnumInt*/) => number /*EnumInt*/;
50+
+getMap: (arg: {[key: string]: ?number}) => {[key: string]: ?number};
51+
+getNumber: (arg: number) => number;
52+
+getObject: (arg: ObjectStruct) => ObjectStruct;
53+
+getSet: (arg: Array<number>) => Array<number>;
54+
+getString: (arg: string) => string;
55+
+getUnion: (x: UnionFloat, y: UnionString, z: UnionObject) => string;
56+
+getValue: (x: number, y: string, z: ObjectStruct) => ValueStruct;
57+
+getValueWithCallback: (callback: (value: string) => void) => void;
58+
+getValueWithPromise: (error: boolean) => Promise<string>;
59+
+voidFunc: () => void;
60+
}
61+
62+
export default (TurboModuleRegistry.get<Spec>(
63+
'NativeCxxModuleExampleCxx',
64+
): ?Spec);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# Copyright (c) Meta Platforms, Inc. and affiliates.
2+
#
3+
# This source code is licensed under the MIT license found in the
4+
# LICENSE file in the root directory of this source tree.
5+
6+
require "json"
7+
8+
package = JSON.parse(File.read(File.join(__dir__, "../package.json")))
9+
10+
Pod::Spec.new do |s|
11+
s.name = "NativeCxxModuleExample"
12+
s.version = package["version"]
13+
s.summary = package["description"]
14+
s.description = "NativeCxxModuleExample"
15+
s.homepage = "https://github.com/facebook/react-native.git"
16+
s.license = "MIT"
17+
s.platforms = { :ios => "12.4" }
18+
s.compiler_flags = '-Wno-nullability-completeness'
19+
s.author = "Meta Platforms, Inc. and its affiliates"
20+
s.source = { :git => "https://github.com/facebook/react-native.git", :tag => "#{s.version}" }
21+
s.source_files = "**/*.{h,cpp}"
22+
s.requires_arc = true
23+
s.pod_target_xcconfig = {
24+
"USE_HEADERMAP" => "YES",
25+
"CLANG_CXX_LANGUAGE_STANDARD" => "c++17"
26+
}
27+
28+
install_modules_dependencies(s)
29+
30+
s.dependency "ReactCommon/turbomodule/core"
31+
end

0 commit comments

Comments
 (0)