mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
efee2595c5 |
@@ -23,8 +23,8 @@ jobs:
|
||||
id: restore-ios-slice
|
||||
uses: actions/cache/restore@v4
|
||||
with:
|
||||
key: v3-ios-core-${{ matrix.slice }}-${{ matrix.flavor }}-${{ hashFiles('packages/react-native/Package.swift') }}-${{ hashFiles('packages/react-native/scripts/ios-prebuild/setup.js') }}
|
||||
path: packages/react-native/
|
||||
path: packages/react-native/third-party/
|
||||
key: v2-ios-core-${{ matrix.slice }}-${{ matrix.flavor }}-${{ hashFiles('packages/react-native/Package.swift') }}-${{ hashFiles('packages/react-native/scripts/ios-prebuild/setup.js') }}
|
||||
- name: Setup node.js
|
||||
if: steps.restore-ios-slice.outputs.cache-hit != 'true'
|
||||
uses: ./.github/actions/setup-node
|
||||
@@ -101,12 +101,6 @@ jobs:
|
||||
# This is going to be replaced by a CLI script
|
||||
cd packages/react-native
|
||||
node scripts/ios-prebuild -b -f "${{ matrix.flavor }}" -p "${{ matrix.slice }}"
|
||||
- name: Upload headers
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: prebuild-ios-core-headers-${{ matrix.flavor }}-${{ matrix.slice }}
|
||||
path:
|
||||
packages/react-native/.build/headers
|
||||
- name: Upload artifacts
|
||||
uses: actions/upload-artifact@v4.3.4
|
||||
with:
|
||||
@@ -117,10 +111,10 @@ jobs:
|
||||
uses: actions/cache/save@v4
|
||||
if: ${{ github.ref == 'refs/heads/main' }} # To avoid that the cache explode
|
||||
with:
|
||||
key: v3-ios-core-${{ matrix.slice }}-${{ matrix.flavor }}-${{ hashFiles('packages/react-native/Package.swift') }}-${{ hashFiles('packages/react-native/scripts/ios-prebuild/setup.js') }}
|
||||
key: v2-ios-core-${{ matrix.slice }}-${{ matrix.flavor }}-${{ hashFiles('packages/react-native/Package.swift') }}-${{ hashFiles('packages/react-native/scripts/ios-prebuild/setup.js') }}
|
||||
enableCrossOsArchive: true
|
||||
path: |
|
||||
packages/react-native/.build/output/spm/${{ matrix.flavor }}/Build/Products
|
||||
packages/react-native/.build/headers
|
||||
|
||||
compose-xcframework:
|
||||
runs-on: macos-14
|
||||
@@ -159,13 +153,6 @@ jobs:
|
||||
pattern: prebuild-ios-core-slice-${{ matrix.flavor }}-*
|
||||
path: packages/react-native/.build/output/spm/${{ matrix.flavor }}/Build/Products
|
||||
merge-multiple: true
|
||||
- name: Download headers
|
||||
if: steps.restore-ios-xcframework.outputs.cache-hit != 'true'
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
pattern: prebuild-ios-core-headers-${{ matrix.flavor }}-*
|
||||
path: packages/react-native/.build/headers
|
||||
merge-multiple: true
|
||||
- name: Setup Keychain
|
||||
if: ${{ steps.restore-ios-xcframework.outputs.cache-hit != 'true' && env.REACT_ORG_CODE_SIGNING_P12_CERT != '' }}
|
||||
uses: apple-actions/import-codesign-certs@v3 # https://github.com/marketplace/actions/import-code-signing-certificates
|
||||
|
||||
@@ -55,8 +55,6 @@ nexusPublishing {
|
||||
sonatype {
|
||||
username.set(sonatypeUsername)
|
||||
password.set(sonatypePassword)
|
||||
nexusUrl.set(uri("https://ossrh-staging-api.central.sonatype.com/service/local/"))
|
||||
snapshotRepositoryUrl.set(uri("https://central.sonatype.com/repository/maven-snapshots/"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -74,6 +74,7 @@
|
||||
"eslint-plugin-jest": "^27.9.0",
|
||||
"eslint-plugin-jsx-a11y": "^6.6.0",
|
||||
"eslint-plugin-react": "^7.30.1",
|
||||
"eslint-plugin-react-hooks": "^5.2.0",
|
||||
"eslint-plugin-react-native": "^4.0.0",
|
||||
"eslint-plugin-redundant-undefined": "^0.4.0",
|
||||
"eslint-plugin-relay": "^1.8.3",
|
||||
@@ -110,7 +111,6 @@
|
||||
"ws": "^6.2.3"
|
||||
},
|
||||
"resolutions": {
|
||||
"eslint-plugin-react-hooks": "6.1.0-canary-12bc60f5-20250613",
|
||||
"react-is": "19.1.0"
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -37,7 +37,7 @@ internal object DependencyUtils {
|
||||
}
|
||||
}
|
||||
// We add the snapshot for users on nightlies.
|
||||
mavenRepoFromUrl("https://central.sonatype.com/repository/maven-snapshots/") { repo ->
|
||||
mavenRepoFromUrl("https://oss.sonatype.org/content/repositories/snapshots/") { repo ->
|
||||
repo.content { it.excludeGroup("org.webkit") }
|
||||
}
|
||||
repositories.mavenCentral { repo ->
|
||||
|
||||
+2
-2
@@ -45,7 +45,7 @@ class DependencyUtilsTest {
|
||||
|
||||
@Test
|
||||
fun configureRepositories_containsSnapshotRepo() {
|
||||
val repositoryURI = URI.create("https://central.sonatype.com/repository/maven-snapshots/")
|
||||
val repositoryURI = URI.create("https://oss.sonatype.org/content/repositories/snapshots/")
|
||||
val project = createProject()
|
||||
|
||||
configureRepositories(project)
|
||||
@@ -176,7 +176,7 @@ class DependencyUtilsTest {
|
||||
|
||||
@Test
|
||||
fun configureRepositories_snapshotRepoHasHigherPriorityThanMavenCentral() {
|
||||
val repositoryURI = URI.create("https://central.sonatype.com/repository/maven-snapshots/")
|
||||
val repositoryURI = URI.create("https://oss.sonatype.org/content/repositories/snapshots/")
|
||||
val mavenCentralURI = URI.create("https://repo.maven.apache.org/maven2/")
|
||||
val project = createProject()
|
||||
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
export type PlatformType = 'iOS' | 'android';
|
||||
|
||||
export type SchemaType = $ReadOnly<{
|
||||
libraryName?: string,
|
||||
modules: $ReadOnly<{
|
||||
[hasteModuleName: string]: ComponentSchema | NativeModuleSchema,
|
||||
}>,
|
||||
|
||||
@@ -28,11 +28,6 @@ const argv = yargs
|
||||
alias: 'exclude',
|
||||
default: null,
|
||||
})
|
||||
.option('l', {
|
||||
describe: 'Library name to use for schema generation',
|
||||
alias: 'libraryName',
|
||||
default: null,
|
||||
})
|
||||
.parseSync();
|
||||
|
||||
const [outfile, ...fileList] = argv._;
|
||||
@@ -40,12 +35,10 @@ const platform: ?string = argv.platform;
|
||||
const exclude: string = argv.exclude;
|
||||
const excludeRegExp: ?RegExp =
|
||||
exclude != null && exclude !== '' ? new RegExp(exclude) : null;
|
||||
const libraryName: ?string = argv.libraryName;
|
||||
|
||||
combineSchemasInFileListAndWriteToFile(
|
||||
fileList,
|
||||
platform != null ? platform.toLowerCase() : platform,
|
||||
outfile,
|
||||
excludeRegExp,
|
||||
libraryName,
|
||||
);
|
||||
|
||||
@@ -21,11 +21,8 @@ const path = require('path');
|
||||
const flowParser = new FlowParser();
|
||||
const typescriptParser = new TypeScriptParser();
|
||||
|
||||
function combineSchemas(
|
||||
files: Array<string>,
|
||||
libraryName: ?string,
|
||||
): SchemaType {
|
||||
const combined = files.reduce(
|
||||
function combineSchemas(files: Array<string>): SchemaType {
|
||||
return files.reduce(
|
||||
(merged, filename) => {
|
||||
const contents = fs.readFileSync(filename, 'utf8');
|
||||
|
||||
@@ -49,11 +46,6 @@ function combineSchemas(
|
||||
},
|
||||
{modules: {}},
|
||||
);
|
||||
|
||||
return {
|
||||
libraryName: libraryName || '',
|
||||
modules: combined.modules,
|
||||
};
|
||||
}
|
||||
|
||||
function expandDirectoriesIntoFiles(
|
||||
@@ -82,14 +74,13 @@ function combineSchemasInFileList(
|
||||
fileList: Array<string>,
|
||||
platform: ?string,
|
||||
exclude: ?RegExp,
|
||||
libraryName: ?string,
|
||||
): SchemaType {
|
||||
const expandedFileList = expandDirectoriesIntoFiles(
|
||||
fileList,
|
||||
platform,
|
||||
exclude,
|
||||
);
|
||||
const combined = combineSchemas(expandedFileList, libraryName);
|
||||
const combined = combineSchemas(expandedFileList);
|
||||
if (Object.keys(combined.modules).length === 0) {
|
||||
console.error(
|
||||
'No modules to process in combine-js-to-schema-cli. If this is unexpected, please check if you set up your NativeComponent correctly. See combine-js-to-schema.js for how codegen finds modules.',
|
||||
@@ -103,14 +94,8 @@ function combineSchemasInFileListAndWriteToFile(
|
||||
platform: ?string,
|
||||
outfile: string,
|
||||
exclude: ?RegExp,
|
||||
libraryName: ?string,
|
||||
): void {
|
||||
const combined = combineSchemasInFileList(
|
||||
fileList,
|
||||
platform,
|
||||
exclude,
|
||||
libraryName,
|
||||
);
|
||||
const combined = combineSchemasInFileList(fileList, platform, exclude);
|
||||
const formattedSchema = JSON.stringify(combined);
|
||||
fs.writeFileSync(outfile, formattedSchema);
|
||||
}
|
||||
|
||||
@@ -99,15 +99,8 @@ for (const file of schemaFiles) {
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
module.type === 'Component' &&
|
||||
schema.libraryName === 'FBReactNativeSpec'
|
||||
) {
|
||||
continue;
|
||||
} else {
|
||||
modules[specName] = module;
|
||||
specNameToFile[specName] = file;
|
||||
}
|
||||
modules[specName] = module;
|
||||
specNameToFile[specName] = file;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+4
-18
@@ -73,20 +73,6 @@ const ALL_GENERATORS = {
|
||||
generateViewConfigJs: generateViewConfigJs.generate,
|
||||
};
|
||||
|
||||
type FilesOutput = Map<string, string>;
|
||||
|
||||
type GenerateFunction = (
|
||||
libraryName: string,
|
||||
schema: SchemaType,
|
||||
packageName?: string,
|
||||
assumeNonnull: boolean,
|
||||
headerPrefix?: string,
|
||||
) => FilesOutput;
|
||||
|
||||
type LibraryGeneratorsFunctions = $ReadOnly<{
|
||||
[string]: Array<GenerateFunction>,
|
||||
}>;
|
||||
|
||||
type LibraryOptions = $ReadOnly<{
|
||||
libraryName: string,
|
||||
schema: SchemaType,
|
||||
@@ -94,7 +80,6 @@ type LibraryOptions = $ReadOnly<{
|
||||
packageName?: string, // Some platforms have a notion of package, which should be configurable.
|
||||
assumeNonnull: boolean,
|
||||
useLocalIncludePaths?: boolean,
|
||||
libraryGenerators?: LibraryGeneratorsFunctions,
|
||||
}>;
|
||||
|
||||
type SchemasOptions = $ReadOnly<{
|
||||
@@ -128,7 +113,7 @@ type SchemasConfig = $ReadOnly<{
|
||||
test?: boolean,
|
||||
}>;
|
||||
|
||||
const LIBRARY_GENERATORS: LibraryGeneratorsFunctions = {
|
||||
const LIBRARY_GENERATORS = {
|
||||
descriptors: [
|
||||
generateComponentDescriptorCpp.generate,
|
||||
generateComponentDescriptorH.generate,
|
||||
@@ -246,6 +231,8 @@ function checkOrWriteFiles(
|
||||
|
||||
module.exports = {
|
||||
allGenerators: ALL_GENERATORS,
|
||||
libraryGenerators: LIBRARY_GENERATORS,
|
||||
schemaGenerators: SCHEMAS_GENERATORS,
|
||||
|
||||
generate(
|
||||
{
|
||||
@@ -255,7 +242,6 @@ module.exports = {
|
||||
packageName,
|
||||
assumeNonnull,
|
||||
useLocalIncludePaths,
|
||||
libraryGenerators = LIBRARY_GENERATORS,
|
||||
}: LibraryOptions,
|
||||
{generators, test}: LibraryConfig,
|
||||
): boolean {
|
||||
@@ -292,7 +278,7 @@ module.exports = {
|
||||
const generatedFiles: Array<CodeGenFile> = [];
|
||||
|
||||
for (const name of generators) {
|
||||
for (const generator of libraryGenerators[name]) {
|
||||
for (const generator of LIBRARY_GENERATORS[name]) {
|
||||
generator(
|
||||
libraryName,
|
||||
schema,
|
||||
|
||||
@@ -13,13 +13,15 @@
|
||||
|
||||
#import <memory>
|
||||
|
||||
#if USE_THIRD_PARTY_JSC != 1
|
||||
#if USE_HERMES
|
||||
#if __has_include(<jsireact/HermesExecutorFactory.h>)
|
||||
#import <jsireact/HermesExecutorFactory.h>
|
||||
#elif __has_include(<reacthermes/HermesExecutorFactory.h>)
|
||||
#import <reacthermes/HermesExecutorFactory.h>
|
||||
#endif
|
||||
#endif
|
||||
#elif USE_THIRD_PARTY_JSC != 1
|
||||
#import <React/JSCExecutorFactory.h>
|
||||
#endif // USE_HERMES
|
||||
|
||||
#import <ReactCommon/RCTTurboModuleManager.h>
|
||||
#import <jsireact/JSIExecutor.h>
|
||||
|
||||
@@ -145,10 +145,16 @@ std::unique_ptr<facebook::react::JSExecutorFactory> RCTAppSetupDefaultJsExecutor
|
||||
}
|
||||
[turboModuleManager installJSBindings:runtime];
|
||||
};
|
||||
#if USE_THIRD_PARTY_JSC != 1
|
||||
#if USE_HERMES
|
||||
return std::make_unique<facebook::react::HermesExecutorFactory>(
|
||||
facebook::react::RCTJSIExecutorRuntimeInstaller(runtimeInstallerLambda));
|
||||
#endif
|
||||
#elif USE_THIRD_PARTY_JSC != 1
|
||||
return std::make_unique<facebook::react::JSCExecutorFactory>(
|
||||
facebook::react::RCTJSIExecutorRuntimeInstaller(runtimeInstallerLambda));
|
||||
#else
|
||||
throw std::runtime_error("No JSExecutorFactory specified.");
|
||||
return nullptr;
|
||||
#endif // USE_HERMES
|
||||
}
|
||||
|
||||
std::unique_ptr<facebook::react::JSExecutorFactory> RCTAppSetupJsExecutorFactoryForOldArch(
|
||||
@@ -163,8 +169,14 @@ std::unique_ptr<facebook::react::JSExecutorFactory> RCTAppSetupJsExecutorFactory
|
||||
facebook::react::RuntimeSchedulerBinding::createAndInstallIfNeeded(runtime, runtimeScheduler);
|
||||
}
|
||||
};
|
||||
#if USE_THIRD_PARTY_JSC != 1
|
||||
#if USE_HERMES
|
||||
return std::make_unique<facebook::react::HermesExecutorFactory>(
|
||||
facebook::react::RCTJSIExecutorRuntimeInstaller(runtimeInstallerLambda));
|
||||
#endif
|
||||
#elif USE_THIRD_PARTY_JSC != 1
|
||||
return std::make_unique<facebook::react::JSCExecutorFactory>(
|
||||
facebook::react::RCTJSIExecutorRuntimeInstaller(runtimeInstallerLambda));
|
||||
#else
|
||||
throw std::runtime_error("No JSExecutorFactory specified.");
|
||||
return nullptr;
|
||||
#endif // USE_HERMES
|
||||
}
|
||||
|
||||
@@ -9,8 +9,10 @@
|
||||
#import <ReactCommon/RCTHost.h>
|
||||
#import "RCTAppSetupUtils.h"
|
||||
#import "RCTDependencyProvider.h"
|
||||
#if USE_THIRD_PARTY_JSC != 1
|
||||
#if USE_HERMES
|
||||
#import <React/RCTHermesInstanceFactory.h>
|
||||
#elif USE_THIRD_PARTY_JSC != 1
|
||||
#import <React/RCTJscInstanceFactory.h>
|
||||
#endif
|
||||
|
||||
#import <react/nativemodule/defaults/DefaultTurboModules.h>
|
||||
@@ -43,8 +45,12 @@
|
||||
|
||||
- (JSRuntimeFactoryRef)createJSRuntimeFactory
|
||||
{
|
||||
#if USE_THIRD_PARTY_JSC != 1
|
||||
#if USE_HERMES
|
||||
return jsrt_create_hermes_factory();
|
||||
#elif USE_THIRD_PARTY_JSC != 1
|
||||
return jsrt_create_jsc_factory();
|
||||
#else
|
||||
return nullptr;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -17,8 +17,12 @@ else
|
||||
end
|
||||
|
||||
is_new_arch_enabled = ENV["RCT_NEW_ARCH_ENABLED"] != "0"
|
||||
use_hermes = ENV['USE_HERMES'] == nil || ENV['USE_HERMES'] == '1'
|
||||
|
||||
new_arch_enabled_flag = (is_new_arch_enabled ? " -DRCT_NEW_ARCH_ENABLED=1" : "")
|
||||
other_cflags = "$(inherited) " + new_arch_enabled_flag + js_engine_flags()
|
||||
hermes_flag = (use_hermes ? " -DUSE_HERMES=1" : "")
|
||||
use_third_party_jsc_flag = ENV['USE_THIRD_PARTY_JSC'] == '1' ? " -DUSE_THIRD_PARTY_JSC=1" : ""
|
||||
other_cflags = "$(inherited) " + new_arch_enabled_flag + hermes_flag + use_third_party_jsc_flag
|
||||
|
||||
header_search_paths = [
|
||||
"$(PODS_TARGET_SRCROOT)/../../ReactCommon",
|
||||
@@ -27,7 +31,7 @@ header_search_paths = [
|
||||
"$(PODS_ROOT)/Headers/Public/ReactCommon",
|
||||
"$(PODS_ROOT)/Headers/Public/React-RCTFabric",
|
||||
"$(PODS_ROOT)/Headers/Private/Yoga",
|
||||
].concat(use_hermes() ? [
|
||||
].concat(use_hermes ? [
|
||||
"$(PODS_ROOT)/Headers/Public/React-hermes",
|
||||
"$(PODS_ROOT)/Headers/Public/hermes-engine"
|
||||
] : [])
|
||||
@@ -62,7 +66,7 @@ Pod::Spec.new do |s|
|
||||
s.dependency "React-CoreModules"
|
||||
s.dependency "React-RCTFBReactNativeSpec"
|
||||
s.dependency "React-defaultsnativemodule"
|
||||
if use_hermes()
|
||||
if use_hermes
|
||||
s.dependency 'React-hermes'
|
||||
end
|
||||
|
||||
|
||||
@@ -50,7 +50,7 @@ Pod::Spec.new do |s|
|
||||
add_dependency(s, "React-jsinspectorcdp", :framework_name => 'jsinspector_moderncdp')
|
||||
add_dependency(s, "ReactCommon", :subspec => "turbomodule/core", :additional_framework_paths => ["react/nativemodule/core"])
|
||||
|
||||
if use_hermes()
|
||||
if ENV["USE_HERMES"] == nil || ENV["USE_HERMES"] == "1"
|
||||
s.dependency "hermes-engine"
|
||||
end
|
||||
|
||||
|
||||
@@ -72,8 +72,3 @@ export interface ImageURISource {
|
||||
}
|
||||
|
||||
export type ImageRequireSource = number;
|
||||
|
||||
export type ImageSource =
|
||||
| ImageRequireSource
|
||||
| ImageURISource
|
||||
| ReadonlyArray<ImageURISource>;
|
||||
|
||||
@@ -336,10 +336,7 @@ let reactRuntime = RNTarget(
|
||||
name: .reactRuntime,
|
||||
path: "ReactCommon/react/runtime",
|
||||
excludedPaths: ["tests", "iostests", "platform"],
|
||||
dependencies: [.reactNativeDependencies, .jsi, .reactJsiExecutor, .reactCxxReact, .reactJsErrorHandler, .reactPerformanceTimeline, .reactUtils, .reactFeatureFlags, .reactJsInspector, .reactJsiTooling, .reactHermes, .reactRuntimeScheduler, .hermesPrebuilt],
|
||||
defines: [
|
||||
CXXSetting.define("HERMES_ENABLE_DEBUGGER", to: "1", .when(configuration: BuildConfiguration.debug))
|
||||
]
|
||||
dependencies: [.reactNativeDependencies, .jsi, .reactJsiExecutor, .reactCxxReact, .reactJsErrorHandler, .reactPerformanceTimeline, .reactUtils, .reactFeatureFlags, .reactJsInspector, .reactJsiTooling, .reactHermes, .reactRuntimeScheduler, .hermesPrebuilt]
|
||||
)
|
||||
|
||||
/// React-runtimeApple.podspec
|
||||
|
||||
@@ -16,6 +16,10 @@ else
|
||||
source[:tag] = "v#{version}"
|
||||
end
|
||||
|
||||
use_hermes = ENV['USE_HERMES'] == nil || ENV['USE_HERMES'] == '1'
|
||||
use_hermes_flag = use_hermes ? "-DUSE_HERMES=1" : ""
|
||||
use_third_party_jsc_flag = ENV['USE_THIRD_PARTY_JSC'] == '1' ? "-DUSE_THIRD_PARTY_JSC=1" : ""
|
||||
|
||||
header_subspecs = {
|
||||
'CoreModulesHeaders' => 'React/CoreModules/**/*.h',
|
||||
'RCTActionSheetHeaders' => 'Libraries/ActionSheetIOS/*.h',
|
||||
@@ -31,7 +35,7 @@ header_subspecs = {
|
||||
}
|
||||
|
||||
frameworks_search_paths = []
|
||||
frameworks_search_paths << "\"$(PODS_CONFIGURATION_BUILD_DIR)/React-hermes\"" if use_hermes()
|
||||
frameworks_search_paths << "\"$(PODS_CONFIGURATION_BUILD_DIR)/React-hermes\"" if use_hermes
|
||||
|
||||
header_search_paths = [
|
||||
"$(PODS_TARGET_SRCROOT)/ReactCommon",
|
||||
@@ -52,7 +56,7 @@ Pod::Spec.new do |s|
|
||||
s.platforms = min_supported_versions
|
||||
s.source = source
|
||||
s.resource_bundle = { "RCTI18nStrings" => ["React/I18n/strings/*.lproj"]}
|
||||
s.compiler_flags = js_engine_flags()
|
||||
s.compiler_flags = use_hermes_flag + ' ' + use_third_party_jsc_flag
|
||||
s.header_dir = "React"
|
||||
s.weak_framework = "JavaScriptCore"
|
||||
s.pod_target_xcconfig = {
|
||||
@@ -76,9 +80,13 @@ Pod::Spec.new do |s|
|
||||
"React/Inspector/**/*",
|
||||
"React/Runtime/**/*",
|
||||
]
|
||||
|
||||
# The default is use hermes, we don't have jsc installed
|
||||
exclude_files = exclude_files.append("React/CxxBridge/JSCExecutorFactory.{h,mm}")
|
||||
# If we are using Hermes (the default is use hermes, so USE_HERMES can be nil), we don't have jsc installed
|
||||
# So we have to exclude the JSCExecutorFactory
|
||||
if use_hermes
|
||||
exclude_files = exclude_files.append("React/CxxBridge/JSCExecutorFactory.{h,mm}")
|
||||
elsif ENV['USE_THIRD_PARTY_JSC'] == '1'
|
||||
exclude_files = exclude_files.append("React/CxxBridge/JSCExecutorFactory.{h,mm}")
|
||||
end
|
||||
|
||||
ss.exclude_files = exclude_files
|
||||
ss.private_header_files = "React/Cxx*/*.h"
|
||||
@@ -115,7 +123,7 @@ Pod::Spec.new do |s|
|
||||
s.dependency "React-runtimescheduler"
|
||||
s.dependency "Yoga"
|
||||
|
||||
if use_hermes()
|
||||
if use_hermes
|
||||
s.dependency "React-hermes"
|
||||
end
|
||||
|
||||
@@ -128,6 +136,7 @@ Pod::Spec.new do |s|
|
||||
add_dependency(s, "React-utils", :additional_framework_paths => ["react/utils/platform/ios"])
|
||||
add_dependency(s, "RCTDeprecation")
|
||||
|
||||
|
||||
depend_on_js_engine(s)
|
||||
add_rn_third_party_dependencies(s)
|
||||
end
|
||||
|
||||
@@ -19,12 +19,9 @@
|
||||
#import <CommonCrypto/CommonCrypto.h>
|
||||
|
||||
#import <React/RCTUtilsUIOverride.h>
|
||||
#import <ReactCommon/RuntimeExecutorSyncUIThreadUtils.h>
|
||||
#import "RCTAssert.h"
|
||||
#import "RCTLog.h"
|
||||
|
||||
using namespace facebook::react;
|
||||
|
||||
NSString *const RCTErrorUnspecified = @"EUNSPECIFIED";
|
||||
|
||||
// Returns the Path of Home directory
|
||||
@@ -317,12 +314,7 @@ void RCTUnsafeExecuteOnMainQueueSyncWithError(dispatch_block_t block, NSString *
|
||||
return;
|
||||
}
|
||||
|
||||
if (ReactNativeFeatureFlags::enableMainQueueCoordinatorOnIOS()) {
|
||||
unsafeExecuteOnMainThreadSync(block);
|
||||
return;
|
||||
}
|
||||
|
||||
if (ReactNativeFeatureFlags::disableMainQueueSyncDispatchIOS()) {
|
||||
if (facebook::react::ReactNativeFeatureFlags::disableMainQueueSyncDispatchIOS()) {
|
||||
RCTLogError(@"RCTUnsafeExecuteOnMainQueueSync: %@", context);
|
||||
}
|
||||
|
||||
@@ -349,12 +341,7 @@ static void RCTUnsafeExecuteOnMainQueueOnceSync(dispatch_once_t *onceToken, disp
|
||||
return;
|
||||
}
|
||||
|
||||
if (ReactNativeFeatureFlags::enableMainQueueCoordinatorOnIOS()) {
|
||||
unsafeExecuteOnMainThreadSync(block);
|
||||
return;
|
||||
}
|
||||
|
||||
if (ReactNativeFeatureFlags::disableMainQueueSyncDispatchIOS()) {
|
||||
if (facebook::react::ReactNativeFeatureFlags::disableMainQueueSyncDispatchIOS()) {
|
||||
RCTLogError(@"RCTUnsafeExecuteOnMainQueueOnceSync: Sync dispatches to the main queue can deadlock React Native.");
|
||||
}
|
||||
|
||||
|
||||
@@ -45,8 +45,10 @@
|
||||
#import <react/utils/FollyConvert.h>
|
||||
#import <reactperflogger/BridgeNativeModulePerfLogger.h>
|
||||
|
||||
#if !defined(USE_HERMES) || USE_HERMES == 1
|
||||
#if USE_HERMES
|
||||
#import <reacthermes/HermesExecutorFactory.h>
|
||||
#elif USE_THIRD_PARTY_JSC != 1
|
||||
#import "JSCExecutorFactory.h"
|
||||
#endif
|
||||
#import "RCTJSIExecutorRuntimeInstaller.h"
|
||||
|
||||
@@ -469,8 +471,12 @@ struct RCTInstanceCallback : public InstanceCallback {
|
||||
}
|
||||
if (!executorFactory) {
|
||||
auto installBindings = RCTJSIExecutorRuntimeInstaller(nullptr);
|
||||
#if !defined(USE_HERMES) || USE_HERMES == 1
|
||||
#if USE_HERMES
|
||||
executorFactory = std::make_shared<HermesExecutorFactory>(installBindings);
|
||||
#elif USE_THIRD_PARTY_JSC != 1
|
||||
executorFactory = std::make_shared<JSCExecutorFactory>(installBindings);
|
||||
#else
|
||||
throw std::runtime_error("No JSExecutorFactory specified.");
|
||||
#endif
|
||||
}
|
||||
} else {
|
||||
@@ -1138,9 +1144,7 @@ RCT_NOT_IMPLEMENTED(-(instancetype)initWithBundleURL
|
||||
/**
|
||||
* Prevent super from calling setUp (that'd create another batchedBridge)
|
||||
*/
|
||||
- (void)setUp
|
||||
{
|
||||
}
|
||||
- (void)setUp {}
|
||||
|
||||
- (Class)executorClass
|
||||
{
|
||||
|
||||
@@ -58,14 +58,15 @@ Pod::Spec.new do |s|
|
||||
add_dependency(s, "React-RuntimeCore")
|
||||
add_dependency(s, "React-RuntimeApple")
|
||||
|
||||
if use_third_party_jsc()
|
||||
s.exclude_files = ["RCTHermesInstanceFactory.{mm,h}", "RCTJscInstanceFactory.{mm,h}"]
|
||||
else
|
||||
if ENV["USE_HERMES"] == nil || ENV["USE_HERMES"] == "1"
|
||||
s.dependency "hermes-engine"
|
||||
add_dependency(s, "React-RuntimeHermes")
|
||||
s.exclude_files = "RCTJscInstanceFactory.{h,mm}"
|
||||
elsif ENV['USE_THIRD_PARTY_JSC'] == '1'
|
||||
s.exclude_files = ["RCTHermesInstanceFactory.{mm,h}", "RCTJscInstanceFactory.{mm,h}"]
|
||||
else
|
||||
s.exclude_files = ["RCTHermesInstanceFactory.{mm,h}"]
|
||||
end
|
||||
|
||||
depend_on_js_engine(s)
|
||||
add_rn_third_party_dependencies(s)
|
||||
end
|
||||
|
||||
@@ -35,11 +35,6 @@ typedef struct {
|
||||
UIColor *right;
|
||||
} RCTBorderColors;
|
||||
|
||||
/**
|
||||
* Determine the largest border inset value.
|
||||
*/
|
||||
RCT_EXTERN CGFloat RCTMaxBorderInset(UIEdgeInsets borderInsets);
|
||||
|
||||
/**
|
||||
* Determine if the border widths, colors and radii are all equal.
|
||||
*/
|
||||
|
||||
@@ -10,11 +10,6 @@
|
||||
|
||||
static const CGFloat RCTViewBorderThreshold = 0.001;
|
||||
|
||||
CGFloat RCTMaxBorderInset(UIEdgeInsets borderInsets)
|
||||
{
|
||||
return MAX(MAX(borderInsets.top, borderInsets.left), MAX(borderInsets.bottom, borderInsets.right));
|
||||
}
|
||||
|
||||
BOOL RCTBorderInsetsAreEqual(UIEdgeInsets borderInsets)
|
||||
{
|
||||
return ABS(borderInsets.left - borderInsets.right) < RCTViewBorderThreshold &&
|
||||
@@ -420,8 +415,8 @@ static UIImage *RCTGetSolidBorderImage(
|
||||
return image;
|
||||
}
|
||||
|
||||
// Currently, the dashed / dotted implementation only supports a single colour,
|
||||
// as that's currently required and supported on Android.
|
||||
// Currently, the dashed / dotted implementation only supports a single colour +
|
||||
// single width, as that's currently required and supported on Android.
|
||||
//
|
||||
// Supporting individual widths + colours on each side is possible by modifying
|
||||
// the current implementation. The idea is that we will draw four different lines
|
||||
@@ -491,12 +486,12 @@ static UIImage *RCTGetDashedOrDottedBorderImage(
|
||||
{
|
||||
NSCParameterAssert(borderStyle == RCTBorderStyleDashed || borderStyle == RCTBorderStyleDotted);
|
||||
|
||||
if (!RCTBorderColorsAreEqual(borderColors)) {
|
||||
if (!RCTBorderColorsAreEqual(borderColors) || !RCTBorderInsetsAreEqual(borderInsets)) {
|
||||
RCTLogWarn(@"Unsupported dashed / dotted border style");
|
||||
return nil;
|
||||
}
|
||||
|
||||
const CGFloat lineWidth = RCTMaxBorderInset(borderInsets);
|
||||
const CGFloat lineWidth = borderInsets.top;
|
||||
if (lineWidth <= 0.0) {
|
||||
return nil;
|
||||
}
|
||||
@@ -524,34 +519,6 @@ static UIImage *RCTGetDashedOrDottedBorderImage(
|
||||
CGPathRef path =
|
||||
RCTPathCreateWithRoundedRect(pathRect, RCTGetCornerInsets(cornerRadii, UIEdgeInsetsZero), NULL, NO);
|
||||
|
||||
if (!RCTBorderInsetsAreEqual(borderInsets)) {
|
||||
CGContextSaveGState(context);
|
||||
{
|
||||
// Create a path representing the full rect
|
||||
CGMutablePathRef outerPath = CGPathCreateMutable();
|
||||
CGPathAddRect(outerPath, NULL, rect);
|
||||
|
||||
CGRect insetRect = CGRectMake(
|
||||
rect.origin.x + borderInsets.left,
|
||||
rect.origin.y + borderInsets.top,
|
||||
rect.size.width - borderInsets.left - borderInsets.right,
|
||||
rect.size.height - borderInsets.top - borderInsets.bottom);
|
||||
|
||||
// The padding edge (inner border) radius is the outer border radius minus the corresponding border thickness
|
||||
CGPathRef innerRoundedRect =
|
||||
RCTPathCreateWithRoundedRect(insetRect, RCTGetCornerInsets(cornerRadii, borderInsets), NULL, NO);
|
||||
|
||||
// Add both paths to outerPath
|
||||
CGPathAddPath(outerPath, NULL, innerRoundedRect);
|
||||
|
||||
// Clip using even-odd
|
||||
CGContextAddPath(context, outerPath);
|
||||
CGContextEOClip(context);
|
||||
CGPathRelease(outerPath);
|
||||
CGPathRelease(innerRoundedRect);
|
||||
}
|
||||
}
|
||||
|
||||
CGFloat dashLengths[2];
|
||||
dashLengths[0] = dashLengths[1] = (borderStyle == RCTBorderStyleDashed ? 3 : 1) * lineWidth;
|
||||
|
||||
|
||||
@@ -950,16 +950,16 @@ public abstract interface class com/facebook/react/bridge/MemoryPressureListener
|
||||
public abstract fun handleMemoryPressure (I)V
|
||||
}
|
||||
|
||||
public final class com/facebook/react/bridge/ModuleHolder {
|
||||
public class com/facebook/react/bridge/ModuleHolder {
|
||||
public fun <init> (Lcom/facebook/react/bridge/NativeModule;)V
|
||||
public fun <init> (Lcom/facebook/react/module/model/ReactModuleInfo;Ljavax/inject/Provider;)V
|
||||
public final fun destroy ()V
|
||||
public final fun getCanOverrideExistingModule ()Z
|
||||
public final fun getClassName ()Ljava/lang/String;
|
||||
public final fun getModule ()Lcom/facebook/react/bridge/NativeModule;
|
||||
public final fun getName ()Ljava/lang/String;
|
||||
public final fun isCxxModule ()Z
|
||||
public final fun isTurboModule ()Z
|
||||
public fun destroy ()V
|
||||
public fun getCanOverrideExistingModule ()Z
|
||||
public fun getClassName ()Ljava/lang/String;
|
||||
public fun getModule ()Lcom/facebook/react/bridge/NativeModule;
|
||||
public fun getName ()Ljava/lang/String;
|
||||
public fun isCxxModule ()Z
|
||||
public fun isTurboModule ()Z
|
||||
}
|
||||
|
||||
public final class com/facebook/react/bridge/ModuleSpec {
|
||||
@@ -2747,6 +2747,36 @@ public final class com/facebook/react/modules/debug/DevSettingsModule : com/face
|
||||
public final class com/facebook/react/modules/debug/DevSettingsModule$Companion {
|
||||
}
|
||||
|
||||
public final class com/facebook/react/modules/debug/FpsDebugFrameCallback : android/view/Choreographer$FrameCallback {
|
||||
public fun <init> (Lcom/facebook/react/bridge/ReactContext;)V
|
||||
public fun doFrame (J)V
|
||||
public final fun get4PlusFrameStutters ()I
|
||||
public final fun getExpectedNumFrames ()I
|
||||
public final fun getFps ()D
|
||||
public final fun getFpsInfo (J)Lcom/facebook/react/modules/debug/FpsDebugFrameCallback$FpsInfo;
|
||||
public final fun getJsFPS ()D
|
||||
public final fun getNumFrames ()I
|
||||
public final fun getNumJSFrames ()I
|
||||
public final fun getTotalTimeMS ()I
|
||||
public final fun reset ()V
|
||||
public final fun start ()V
|
||||
public final fun start (D)V
|
||||
public static synthetic fun start$default (Lcom/facebook/react/modules/debug/FpsDebugFrameCallback;DILjava/lang/Object;)V
|
||||
public final fun startAndRecordFpsAtEachFrame ()V
|
||||
public final fun stop ()V
|
||||
}
|
||||
|
||||
public final class com/facebook/react/modules/debug/FpsDebugFrameCallback$FpsInfo {
|
||||
public fun <init> (IIIIDDI)V
|
||||
public final fun getFps ()D
|
||||
public final fun getJsFps ()D
|
||||
public final fun getTotal4PlusFrameStutters ()I
|
||||
public final fun getTotalExpectedFrames ()I
|
||||
public final fun getTotalFrames ()I
|
||||
public final fun getTotalJsFrames ()I
|
||||
public final fun getTotalTimeMs ()I
|
||||
}
|
||||
|
||||
public final class com/facebook/react/modules/debug/SourceCodeModule : com/facebook/fbreact/specs/NativeSourceCodeSpec {
|
||||
public static final field Companion Lcom/facebook/react/modules/debug/SourceCodeModule$Companion;
|
||||
public static final field NAME Ljava/lang/String;
|
||||
@@ -6417,6 +6447,37 @@ public final class com/facebook/react/views/text/TextAttributes {
|
||||
public fun toString ()Ljava/lang/String;
|
||||
}
|
||||
|
||||
public class com/facebook/react/views/text/TextLayoutManager {
|
||||
public static final field AS_KEY_BASE_ATTRIBUTES S
|
||||
public static final field AS_KEY_CACHE_ID S
|
||||
public static final field AS_KEY_FRAGMENTS S
|
||||
public static final field AS_KEY_HASH S
|
||||
public static final field AS_KEY_STRING S
|
||||
public static final field FR_KEY_HEIGHT S
|
||||
public static final field FR_KEY_IS_ATTACHMENT S
|
||||
public static final field FR_KEY_REACT_TAG S
|
||||
public static final field FR_KEY_STRING S
|
||||
public static final field FR_KEY_TEXT_ATTRIBUTES S
|
||||
public static final field FR_KEY_WIDTH S
|
||||
public static final field PA_KEY_ADJUST_FONT_SIZE_TO_FIT S
|
||||
public static final field PA_KEY_ELLIPSIZE_MODE S
|
||||
public static final field PA_KEY_HYPHENATION_FREQUENCY S
|
||||
public static final field PA_KEY_INCLUDE_FONT_PADDING S
|
||||
public static final field PA_KEY_MAXIMUM_FONT_SIZE S
|
||||
public static final field PA_KEY_MAX_NUMBER_OF_LINES S
|
||||
public static final field PA_KEY_MINIMUM_FONT_SIZE S
|
||||
public static final field PA_KEY_TEXT_ALIGN_VERTICAL S
|
||||
public static final field PA_KEY_TEXT_BREAK_STRATEGY S
|
||||
public fun <init> ()V
|
||||
public static fun deleteCachedSpannableForTag (I)V
|
||||
public static fun getOrCreateSpannableForText (Landroid/content/Context;Lcom/facebook/react/common/mapbuffer/MapBuffer;Lcom/facebook/react/views/text/ReactTextViewManagerCallback;)Landroid/text/Spannable;
|
||||
public static fun getTextGravity (Lcom/facebook/react/common/mapbuffer/MapBuffer;Landroid/text/Spannable;I)I
|
||||
public static fun isRTL (Lcom/facebook/react/common/mapbuffer/MapBuffer;)Z
|
||||
public static fun measureLines (Landroid/content/Context;Lcom/facebook/react/common/mapbuffer/MapBuffer;Lcom/facebook/react/common/mapbuffer/MapBuffer;FF)Lcom/facebook/react/bridge/WritableArray;
|
||||
public static fun measureText (Landroid/content/Context;Lcom/facebook/react/common/mapbuffer/MapBuffer;Lcom/facebook/react/common/mapbuffer/MapBuffer;FLcom/facebook/yoga/YogaMeasureMode;FLcom/facebook/yoga/YogaMeasureMode;Lcom/facebook/react/views/text/ReactTextViewManagerCallback;[F)J
|
||||
public static fun setCachedSpannableForTag (ILandroid/text/Spannable;)V
|
||||
}
|
||||
|
||||
public abstract interface class com/facebook/react/views/textinput/ContentSizeWatcher {
|
||||
public abstract fun onLayout ()V
|
||||
}
|
||||
|
||||
+1
-1
@@ -111,7 +111,7 @@ public class NativeAnimatedModule(reactContext: ReactApplicationContext?) :
|
||||
private var valueMap: Array<BatchExecutionOpCodes>? = null
|
||||
|
||||
@JvmStatic
|
||||
fun fromId(id: Int): BatchExecutionOpCodes {
|
||||
public fun fromId(id: Int): BatchExecutionOpCodes {
|
||||
val valueMapNonnull: Array<BatchExecutionOpCodes> =
|
||||
valueMap ?: BatchExecutionOpCodes.values()
|
||||
if (valueMap == null) {
|
||||
|
||||
+413
@@ -0,0 +1,413 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package com.facebook.react.bridge;
|
||||
|
||||
import static com.facebook.infer.annotation.Assertions.assertNotNull;
|
||||
import static com.facebook.systrace.Systrace.TRACE_TAG_REACT;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import com.facebook.debug.holder.PrinterHolder;
|
||||
import com.facebook.debug.tags.ReactDebugOverlayTags;
|
||||
import com.facebook.infer.annotation.Assertions;
|
||||
import com.facebook.react.common.annotations.internal.LegacyArchitecture;
|
||||
import com.facebook.react.common.annotations.internal.LegacyArchitectureLogLevel;
|
||||
import com.facebook.react.common.annotations.internal.LegacyArchitectureLogger;
|
||||
import com.facebook.systrace.SystraceMessage;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
@LegacyArchitecture(logLevel = LegacyArchitectureLogLevel.ERROR)
|
||||
class JavaMethodWrapper implements JavaModuleWrapper.NativeMethod {
|
||||
static {
|
||||
LegacyArchitectureLogger.assertLegacyArchitecture(
|
||||
"JavaMethodWrapper", LegacyArchitectureLogLevel.ERROR);
|
||||
}
|
||||
|
||||
private abstract static class ArgumentExtractor<T> {
|
||||
public int getJSArgumentsNeeded() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
public abstract @Nullable T extractArgument(
|
||||
JSInstance jsInstance, ReadableArray jsArguments, int atIndex);
|
||||
}
|
||||
|
||||
private static final ArgumentExtractor<Boolean> ARGUMENT_EXTRACTOR_BOOLEAN =
|
||||
new ArgumentExtractor<Boolean>() {
|
||||
@Override
|
||||
public Boolean extractArgument(
|
||||
JSInstance jsInstance, ReadableArray jsArguments, int atIndex) {
|
||||
return jsArguments.getBoolean(atIndex);
|
||||
}
|
||||
};
|
||||
|
||||
private static final ArgumentExtractor<Double> ARGUMENT_EXTRACTOR_DOUBLE =
|
||||
new ArgumentExtractor<Double>() {
|
||||
@Override
|
||||
public Double extractArgument(
|
||||
JSInstance jsInstance, ReadableArray jsArguments, int atIndex) {
|
||||
return jsArguments.getDouble(atIndex);
|
||||
}
|
||||
};
|
||||
|
||||
private static final ArgumentExtractor<Float> ARGUMENT_EXTRACTOR_FLOAT =
|
||||
new ArgumentExtractor<Float>() {
|
||||
@Override
|
||||
public Float extractArgument(
|
||||
JSInstance jsInstance, ReadableArray jsArguments, int atIndex) {
|
||||
return (float) jsArguments.getDouble(atIndex);
|
||||
}
|
||||
};
|
||||
|
||||
private static final ArgumentExtractor<Integer> ARGUMENT_EXTRACTOR_INTEGER =
|
||||
new ArgumentExtractor<Integer>() {
|
||||
@Override
|
||||
public Integer extractArgument(
|
||||
JSInstance jsInstance, ReadableArray jsArguments, int atIndex) {
|
||||
return (int) jsArguments.getDouble(atIndex);
|
||||
}
|
||||
};
|
||||
|
||||
private static final ArgumentExtractor<String> ARGUMENT_EXTRACTOR_STRING =
|
||||
new ArgumentExtractor<String>() {
|
||||
@Override
|
||||
public String extractArgument(
|
||||
JSInstance jsInstance, ReadableArray jsArguments, int atIndex) {
|
||||
return jsArguments.getString(atIndex);
|
||||
}
|
||||
};
|
||||
|
||||
private static final ArgumentExtractor<ReadableArray> ARGUMENT_EXTRACTOR_ARRAY =
|
||||
new ArgumentExtractor<ReadableArray>() {
|
||||
@Override
|
||||
public ReadableArray extractArgument(
|
||||
JSInstance jsInstance, ReadableArray jsArguments, int atIndex) {
|
||||
return jsArguments.getArray(atIndex);
|
||||
}
|
||||
};
|
||||
|
||||
private static final ArgumentExtractor<Dynamic> ARGUMENT_EXTRACTOR_DYNAMIC =
|
||||
new ArgumentExtractor<Dynamic>() {
|
||||
@Override
|
||||
public Dynamic extractArgument(
|
||||
JSInstance jsInstance, ReadableArray jsArguments, int atIndex) {
|
||||
return DynamicFromArray.create(jsArguments, atIndex);
|
||||
}
|
||||
};
|
||||
|
||||
private static final ArgumentExtractor<ReadableMap> ARGUMENT_EXTRACTOR_MAP =
|
||||
new ArgumentExtractor<ReadableMap>() {
|
||||
@Override
|
||||
public ReadableMap extractArgument(
|
||||
JSInstance jsInstance, ReadableArray jsArguments, int atIndex) {
|
||||
return jsArguments.getMap(atIndex);
|
||||
}
|
||||
};
|
||||
|
||||
private static final ArgumentExtractor<Callback> ARGUMENT_EXTRACTOR_CALLBACK =
|
||||
new ArgumentExtractor<Callback>() {
|
||||
@Override
|
||||
public @Nullable Callback extractArgument(
|
||||
JSInstance jsInstance, ReadableArray jsArguments, int atIndex) {
|
||||
if (jsArguments.isNull(atIndex)) {
|
||||
return null;
|
||||
} else {
|
||||
int id = (int) jsArguments.getDouble(atIndex);
|
||||
return new com.facebook.react.bridge.CallbackImpl(jsInstance, id);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
private static final ArgumentExtractor<Promise> ARGUMENT_EXTRACTOR_PROMISE =
|
||||
new ArgumentExtractor<Promise>() {
|
||||
@Override
|
||||
public int getJSArgumentsNeeded() {
|
||||
return 2;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Promise extractArgument(
|
||||
JSInstance jsInstance, ReadableArray jsArguments, int atIndex) {
|
||||
Callback resolve =
|
||||
ARGUMENT_EXTRACTOR_CALLBACK.extractArgument(jsInstance, jsArguments, atIndex);
|
||||
Callback reject =
|
||||
ARGUMENT_EXTRACTOR_CALLBACK.extractArgument(jsInstance, jsArguments, atIndex + 1);
|
||||
return new PromiseImpl(resolve, reject);
|
||||
}
|
||||
};
|
||||
|
||||
private static final boolean DEBUG =
|
||||
PrinterHolder.getPrinter().shouldDisplayLogMessage(ReactDebugOverlayTags.BRIDGE_CALLS);
|
||||
|
||||
private static char paramTypeToChar(Class paramClass) {
|
||||
char tryCommon = commonTypeToChar(paramClass);
|
||||
if (tryCommon != '\0') {
|
||||
return tryCommon;
|
||||
}
|
||||
if (paramClass == Callback.class) {
|
||||
return 'X';
|
||||
} else if (paramClass == Promise.class) {
|
||||
return 'P';
|
||||
} else if (paramClass == ReadableMap.class) {
|
||||
return 'M';
|
||||
} else if (paramClass == ReadableArray.class) {
|
||||
return 'A';
|
||||
} else if (paramClass == Dynamic.class) {
|
||||
return 'Y';
|
||||
} else {
|
||||
throw new RuntimeException("Got unknown param class: " + paramClass.getSimpleName());
|
||||
}
|
||||
}
|
||||
|
||||
private static char returnTypeToChar(Class returnClass) {
|
||||
// Keep this in sync with MethodInvoker
|
||||
char tryCommon = commonTypeToChar(returnClass);
|
||||
if (tryCommon != '\0') {
|
||||
return tryCommon;
|
||||
}
|
||||
if (returnClass == void.class) {
|
||||
return 'v';
|
||||
} else if (returnClass == WritableMap.class) {
|
||||
return 'M';
|
||||
} else if (returnClass == WritableArray.class) {
|
||||
return 'A';
|
||||
} else {
|
||||
throw new RuntimeException("Got unknown return class: " + returnClass.getSimpleName());
|
||||
}
|
||||
}
|
||||
|
||||
private static char commonTypeToChar(Class typeClass) {
|
||||
if (typeClass == boolean.class) {
|
||||
return 'z';
|
||||
} else if (typeClass == Boolean.class) {
|
||||
return 'Z';
|
||||
} else if (typeClass == int.class) {
|
||||
return 'i';
|
||||
} else if (typeClass == Integer.class) {
|
||||
return 'I';
|
||||
} else if (typeClass == double.class) {
|
||||
return 'd';
|
||||
} else if (typeClass == Double.class) {
|
||||
return 'D';
|
||||
} else if (typeClass == float.class) {
|
||||
return 'f';
|
||||
} else if (typeClass == Float.class) {
|
||||
return 'F';
|
||||
} else if (typeClass == String.class) {
|
||||
return 'S';
|
||||
} else {
|
||||
return '\0';
|
||||
}
|
||||
}
|
||||
|
||||
private final Method mMethod;
|
||||
private final Class[] mParameterTypes;
|
||||
private final int mParamLength;
|
||||
private final JavaModuleWrapper mModuleWrapper;
|
||||
private String mType = BaseJavaModule.METHOD_TYPE_ASYNC;
|
||||
private boolean mArgumentsProcessed = false;
|
||||
private @Nullable ArgumentExtractor[] mArgumentExtractors;
|
||||
private @Nullable String mSignature;
|
||||
private @Nullable Object[] mArguments;
|
||||
private @Nullable int mJSArgumentsNeeded;
|
||||
|
||||
public JavaMethodWrapper(JavaModuleWrapper module, Method method, boolean isSync) {
|
||||
mModuleWrapper = module;
|
||||
mMethod = method;
|
||||
mMethod.setAccessible(true);
|
||||
mParameterTypes = mMethod.getParameterTypes();
|
||||
mParamLength = mParameterTypes.length;
|
||||
|
||||
if (isSync) {
|
||||
mType = BaseJavaModule.METHOD_TYPE_SYNC;
|
||||
} else if (mParamLength > 0 && (mParameterTypes[mParamLength - 1] == Promise.class)) {
|
||||
mType = BaseJavaModule.METHOD_TYPE_PROMISE;
|
||||
}
|
||||
}
|
||||
|
||||
private void processArguments() {
|
||||
if (mArgumentsProcessed) {
|
||||
return;
|
||||
}
|
||||
SystraceMessage.beginSection(TRACE_TAG_REACT, "processArguments")
|
||||
.arg("method", mModuleWrapper.getName() + "." + mMethod.getName())
|
||||
.flush();
|
||||
try {
|
||||
mArgumentsProcessed = true;
|
||||
mArgumentExtractors = buildArgumentExtractors(mParameterTypes);
|
||||
mSignature =
|
||||
buildSignature(mMethod, mParameterTypes, (mType.equals(BaseJavaModule.METHOD_TYPE_SYNC)));
|
||||
// Since native methods are invoked from a message queue executed on a single thread, it is
|
||||
// safe to allocate only one arguments object per method that can be reused across calls
|
||||
mArguments = new Object[mParameterTypes.length];
|
||||
mJSArgumentsNeeded = calculateJSArgumentsNeeded();
|
||||
} finally {
|
||||
SystraceMessage.endSection(TRACE_TAG_REACT).flush();
|
||||
}
|
||||
}
|
||||
|
||||
public Method getMethod() {
|
||||
return mMethod;
|
||||
}
|
||||
|
||||
public String getSignature() {
|
||||
if (!mArgumentsProcessed) {
|
||||
processArguments();
|
||||
}
|
||||
return assertNotNull(mSignature);
|
||||
}
|
||||
|
||||
private String buildSignature(Method method, Class[] paramTypes, boolean isSync) {
|
||||
StringBuilder builder = new StringBuilder(paramTypes.length + 2);
|
||||
|
||||
if (isSync) {
|
||||
builder.append(returnTypeToChar(method.getReturnType()));
|
||||
builder.append('.');
|
||||
} else {
|
||||
builder.append("v.");
|
||||
}
|
||||
|
||||
for (int i = 0; i < paramTypes.length; i++) {
|
||||
Class paramClass = paramTypes[i];
|
||||
if (paramClass == Promise.class) {
|
||||
Assertions.assertCondition(
|
||||
i == paramTypes.length - 1, "Promise must be used as last parameter only");
|
||||
}
|
||||
builder.append(paramTypeToChar(paramClass));
|
||||
}
|
||||
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
private ArgumentExtractor[] buildArgumentExtractors(Class[] paramTypes) {
|
||||
ArgumentExtractor[] argumentExtractors = new ArgumentExtractor[paramTypes.length];
|
||||
for (int i = 0; i < paramTypes.length; i += argumentExtractors[i].getJSArgumentsNeeded()) {
|
||||
Class argumentClass = paramTypes[i];
|
||||
if (argumentClass == Boolean.class || argumentClass == boolean.class) {
|
||||
argumentExtractors[i] = ARGUMENT_EXTRACTOR_BOOLEAN;
|
||||
} else if (argumentClass == Integer.class || argumentClass == int.class) {
|
||||
argumentExtractors[i] = ARGUMENT_EXTRACTOR_INTEGER;
|
||||
} else if (argumentClass == Double.class || argumentClass == double.class) {
|
||||
argumentExtractors[i] = ARGUMENT_EXTRACTOR_DOUBLE;
|
||||
} else if (argumentClass == Float.class || argumentClass == float.class) {
|
||||
argumentExtractors[i] = ARGUMENT_EXTRACTOR_FLOAT;
|
||||
} else if (argumentClass == String.class) {
|
||||
argumentExtractors[i] = ARGUMENT_EXTRACTOR_STRING;
|
||||
} else if (argumentClass == Callback.class) {
|
||||
argumentExtractors[i] = ARGUMENT_EXTRACTOR_CALLBACK;
|
||||
} else if (argumentClass == Promise.class) {
|
||||
argumentExtractors[i] = ARGUMENT_EXTRACTOR_PROMISE;
|
||||
Assertions.assertCondition(
|
||||
i == paramTypes.length - 1, "Promise must be used as last parameter only");
|
||||
} else if (argumentClass == ReadableMap.class) {
|
||||
argumentExtractors[i] = ARGUMENT_EXTRACTOR_MAP;
|
||||
} else if (argumentClass == ReadableArray.class) {
|
||||
argumentExtractors[i] = ARGUMENT_EXTRACTOR_ARRAY;
|
||||
} else if (argumentClass == Dynamic.class) {
|
||||
argumentExtractors[i] = ARGUMENT_EXTRACTOR_DYNAMIC;
|
||||
} else {
|
||||
throw new RuntimeException("Got unknown argument class: " + argumentClass.getSimpleName());
|
||||
}
|
||||
}
|
||||
return argumentExtractors;
|
||||
}
|
||||
|
||||
private int calculateJSArgumentsNeeded() {
|
||||
int n = 0;
|
||||
for (ArgumentExtractor extractor : assertNotNull(mArgumentExtractors)) {
|
||||
n += extractor.getJSArgumentsNeeded();
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
private String getAffectedRange(int startIndex, int jsArgumentsNeeded) {
|
||||
return jsArgumentsNeeded > 1
|
||||
? "" + startIndex + "-" + (startIndex + jsArgumentsNeeded - 1)
|
||||
: "" + startIndex;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invoke(JSInstance jsInstance, ReadableArray parameters) {
|
||||
String traceName = mModuleWrapper.getName() + "." + mMethod.getName();
|
||||
SystraceMessage.beginSection(TRACE_TAG_REACT, "callJavaModuleMethod")
|
||||
.arg("method", traceName)
|
||||
.flush();
|
||||
if (DEBUG) {
|
||||
PrinterHolder.getPrinter()
|
||||
.logMessage(
|
||||
ReactDebugOverlayTags.BRIDGE_CALLS,
|
||||
"JS->Java: %s.%s()",
|
||||
mModuleWrapper.getName(),
|
||||
mMethod.getName());
|
||||
}
|
||||
try {
|
||||
if (!mArgumentsProcessed) {
|
||||
processArguments();
|
||||
}
|
||||
if (mArguments == null || mArgumentExtractors == null) {
|
||||
throw new Error("processArguments failed");
|
||||
}
|
||||
if (mJSArgumentsNeeded != parameters.size()) {
|
||||
throw new NativeArgumentsParseException(
|
||||
traceName + " got " + parameters.size() + " arguments, expected " + mJSArgumentsNeeded);
|
||||
}
|
||||
|
||||
int i = 0, jsArgumentsConsumed = 0;
|
||||
try {
|
||||
for (; i < mArgumentExtractors.length; i++) {
|
||||
mArguments[i] =
|
||||
mArgumentExtractors[i].extractArgument(jsInstance, parameters, jsArgumentsConsumed);
|
||||
jsArgumentsConsumed += mArgumentExtractors[i].getJSArgumentsNeeded();
|
||||
}
|
||||
} catch (UnexpectedNativeTypeException | NullPointerException e) {
|
||||
throw new NativeArgumentsParseException(
|
||||
e.getMessage()
|
||||
+ " (constructing arguments for "
|
||||
+ traceName
|
||||
+ " at argument index "
|
||||
+ getAffectedRange(
|
||||
jsArgumentsConsumed, mArgumentExtractors[i].getJSArgumentsNeeded())
|
||||
+ ")",
|
||||
e);
|
||||
}
|
||||
|
||||
try {
|
||||
mMethod.invoke(mModuleWrapper.getModule(), mArguments);
|
||||
} catch (IllegalArgumentException | IllegalAccessException e) {
|
||||
throw new RuntimeException(createInvokeExceptionMessage(traceName), e);
|
||||
} catch (InvocationTargetException ite) {
|
||||
// Exceptions thrown from native module calls end up wrapped in InvocationTargetException
|
||||
// which just make traces harder to read and bump out useful information
|
||||
if (ite.getCause() instanceof RuntimeException) {
|
||||
throw (RuntimeException) ite.getCause();
|
||||
}
|
||||
throw new RuntimeException(createInvokeExceptionMessage(traceName), ite);
|
||||
}
|
||||
} finally {
|
||||
SystraceMessage.endSection(TRACE_TAG_REACT).flush();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes it easier to determine the cause of an error invoking a native method from Javascript
|
||||
* code by adding the function name.
|
||||
*/
|
||||
private static String createInvokeExceptionMessage(String traceName) {
|
||||
return "Could not invoke " + traceName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines how the method is exported in JavaScript: METHOD_TYPE_ASYNC for regular methods
|
||||
* METHOD_TYPE_PROMISE for methods that return a promise object to the caller. METHOD_TYPE_SYNC
|
||||
* for sync methods
|
||||
*/
|
||||
@Override
|
||||
public String getType() {
|
||||
return mType;
|
||||
}
|
||||
}
|
||||
-399
@@ -1,399 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package com.facebook.react.bridge
|
||||
|
||||
import com.facebook.debug.holder.PrinterHolder
|
||||
import com.facebook.debug.tags.ReactDebugOverlayTags
|
||||
import com.facebook.react.common.annotations.internal.LegacyArchitecture
|
||||
import com.facebook.react.common.annotations.internal.LegacyArchitectureLogLevel
|
||||
import com.facebook.react.common.annotations.internal.LegacyArchitectureLogger
|
||||
import com.facebook.systrace.Systrace.TRACE_TAG_REACT
|
||||
import com.facebook.systrace.SystraceMessage
|
||||
import java.lang.reflect.InvocationTargetException
|
||||
import java.lang.reflect.Method
|
||||
|
||||
@LegacyArchitecture(logLevel = LegacyArchitectureLogLevel.ERROR)
|
||||
internal class JavaMethodWrapper(
|
||||
private val moduleWrapper: JavaModuleWrapper,
|
||||
val method: Method,
|
||||
isSync: Boolean
|
||||
) : JavaModuleWrapper.NativeMethod {
|
||||
private abstract class ArgumentExtractor<T> {
|
||||
open fun getJSArgumentsNeeded(): Int = 1
|
||||
|
||||
abstract fun extractArgument(
|
||||
jsInstance: JSInstance,
|
||||
jsArguments: ReadableArray,
|
||||
atIndex: Int
|
||||
): T?
|
||||
}
|
||||
|
||||
private val parameterTypes: Array<Class<*>>
|
||||
private val paramLength: Int
|
||||
|
||||
/**
|
||||
* Determines how the method is exported in JavaScript: METHOD_TYPE_ASYNC for regular methods
|
||||
* METHOD_TYPE_PROMISE for methods that return a promise object to the caller. METHOD_TYPE_SYNC
|
||||
* for sync methods
|
||||
*/
|
||||
override var type: String = BaseJavaModule.METHOD_TYPE_ASYNC
|
||||
private var argumentsProcessed = false
|
||||
private var argumentExtractors: Array<ArgumentExtractor<*>>? = null
|
||||
private var internalSignature: String? = null
|
||||
private var arguments: Array<Any?>? = null
|
||||
private var jsArgumentsNeeded = 0
|
||||
|
||||
init {
|
||||
method.isAccessible = true
|
||||
parameterTypes = method.parameterTypes
|
||||
paramLength = parameterTypes.size
|
||||
|
||||
if (isSync) {
|
||||
type = BaseJavaModule.METHOD_TYPE_SYNC
|
||||
} else if (paramLength > 0 && (parameterTypes[paramLength - 1] == Promise::class.java)) {
|
||||
type = BaseJavaModule.METHOD_TYPE_PROMISE
|
||||
}
|
||||
}
|
||||
|
||||
private fun processArguments() {
|
||||
if (argumentsProcessed) {
|
||||
return
|
||||
}
|
||||
SystraceMessage.beginSection(TRACE_TAG_REACT, "processArguments")
|
||||
.arg("method", moduleWrapper.name + "." + method.name)
|
||||
.flush()
|
||||
try {
|
||||
argumentsProcessed = true
|
||||
argumentExtractors = buildArgumentExtractors(parameterTypes)
|
||||
internalSignature =
|
||||
buildSignature(method, parameterTypes, (type == BaseJavaModule.METHOD_TYPE_SYNC))
|
||||
// Since native methods are invoked from a message queue executed on a single thread, it is
|
||||
// safe to allocate only one arguments object per method that can be reused across calls
|
||||
arguments = arrayOfNulls(parameterTypes.size)
|
||||
jsArgumentsNeeded = calculateJSArgumentsNeeded()
|
||||
} finally {
|
||||
SystraceMessage.endSection(TRACE_TAG_REACT).flush()
|
||||
}
|
||||
}
|
||||
|
||||
val signature: String?
|
||||
get() {
|
||||
if (!argumentsProcessed) {
|
||||
processArguments()
|
||||
}
|
||||
return checkNotNull(internalSignature)
|
||||
}
|
||||
|
||||
private fun buildSignature(method: Method, paramTypes: Array<Class<*>>, isSync: Boolean): String =
|
||||
buildString(paramTypes.size + 2) {
|
||||
if (isSync) {
|
||||
append(returnTypeToChar(method.returnType))
|
||||
append('.')
|
||||
} else {
|
||||
append("v.")
|
||||
}
|
||||
|
||||
for (i in paramTypes.indices) {
|
||||
val paramClass = paramTypes[i]
|
||||
if (paramClass == Promise::class.java) {
|
||||
check(i == paramTypes.size - 1) { "Promise must be used as last parameter only" }
|
||||
}
|
||||
append(paramTypeToChar(paramClass))
|
||||
}
|
||||
}
|
||||
|
||||
private fun buildArgumentExtractors(paramTypes: Array<Class<*>>): Array<ArgumentExtractor<*>> {
|
||||
val argumentExtractors = arrayOfNulls<ArgumentExtractor<*>>(paramTypes.size)
|
||||
var i = 0
|
||||
while (i < paramTypes.size) {
|
||||
val argumentClass = paramTypes[i]
|
||||
val extractor: ArgumentExtractor<*> =
|
||||
when (argumentClass) {
|
||||
Boolean::class.javaObjectType,
|
||||
Boolean::class.javaPrimitiveType -> ARGUMENT_EXTRACTOR_BOOLEAN
|
||||
Int::class.javaObjectType,
|
||||
Int::class.javaPrimitiveType -> ARGUMENT_EXTRACTOR_INTEGER
|
||||
Double::class.javaObjectType,
|
||||
Double::class.javaPrimitiveType -> ARGUMENT_EXTRACTOR_DOUBLE
|
||||
Float::class.javaObjectType,
|
||||
Float::class.javaPrimitiveType -> ARGUMENT_EXTRACTOR_FLOAT
|
||||
String::class.java -> ARGUMENT_EXTRACTOR_STRING
|
||||
Callback::class.java -> ARGUMENT_EXTRACTOR_CALLBACK
|
||||
Promise::class.java -> {
|
||||
check(i == paramTypes.size - 1) { "Promise must be used as last parameter only" }
|
||||
ARGUMENT_EXTRACTOR_PROMISE
|
||||
}
|
||||
ReadableMap::class.java -> ARGUMENT_EXTRACTOR_MAP
|
||||
ReadableArray::class.java -> ARGUMENT_EXTRACTOR_ARRAY
|
||||
Dynamic::class.java -> ARGUMENT_EXTRACTOR_DYNAMIC
|
||||
else ->
|
||||
throw RuntimeException("Got unknown argument class: ${argumentClass.simpleName}")
|
||||
}
|
||||
|
||||
argumentExtractors[i] = extractor
|
||||
i += extractor.getJSArgumentsNeeded()
|
||||
}
|
||||
|
||||
return argumentExtractors.requireNoNulls()
|
||||
}
|
||||
|
||||
private fun calculateJSArgumentsNeeded(): Int {
|
||||
var n = 0
|
||||
for (extractor in checkNotNull(argumentExtractors)) {
|
||||
n += extractor.getJSArgumentsNeeded()
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
private fun getAffectedRange(startIndex: Int, jsArgumentsNeeded: Int): String =
|
||||
if (jsArgumentsNeeded > 1) {
|
||||
"$startIndex-${startIndex + jsArgumentsNeeded - 1}"
|
||||
} else {
|
||||
"$startIndex"
|
||||
}
|
||||
|
||||
override fun invoke(jsInstance: JSInstance, parameters: ReadableArray) {
|
||||
val traceName = moduleWrapper.name + "." + method.name
|
||||
SystraceMessage.beginSection(TRACE_TAG_REACT, "callJavaModuleMethod")
|
||||
.arg("method", traceName)
|
||||
.flush()
|
||||
if (DEBUG) {
|
||||
PrinterHolder.printer.logMessage(
|
||||
ReactDebugOverlayTags.BRIDGE_CALLS, "JS->Java: %s.%s()", moduleWrapper.name, method.name)
|
||||
}
|
||||
try {
|
||||
if (!argumentsProcessed) {
|
||||
processArguments()
|
||||
}
|
||||
|
||||
val validatedArguments =
|
||||
requireNotNull(arguments) { "processArguments failed: 'arguments' is null." }
|
||||
val validatedArgumentExtractors =
|
||||
requireNotNull(argumentExtractors) {
|
||||
"processArguments failed: 'argumentExtractors' is null."
|
||||
}
|
||||
|
||||
if (jsArgumentsNeeded != parameters.size()) {
|
||||
throw NativeArgumentsParseException(
|
||||
"$traceName got ${parameters.size()} arguments, expected $jsArgumentsNeeded")
|
||||
}
|
||||
|
||||
var i = 0
|
||||
var jsArgumentsConsumed = 0
|
||||
try {
|
||||
while (i < validatedArgumentExtractors.size) {
|
||||
validatedArguments[i] =
|
||||
validatedArgumentExtractors[i].extractArgument(
|
||||
jsInstance, parameters, jsArgumentsConsumed)
|
||||
jsArgumentsConsumed += validatedArgumentExtractors[i].getJSArgumentsNeeded()
|
||||
i++
|
||||
}
|
||||
} catch (e: UnexpectedNativeTypeException) {
|
||||
throw NativeArgumentsParseException(
|
||||
"${e.message} (constructing arguments for $traceName at argument index ${
|
||||
getAffectedRange(
|
||||
jsArgumentsConsumed,
|
||||
validatedArgumentExtractors[i].getJSArgumentsNeeded()
|
||||
)
|
||||
})",
|
||||
e)
|
||||
} catch (e: NullPointerException) {
|
||||
throw NativeArgumentsParseException(
|
||||
"${e.message} (constructing arguments for $traceName at argument index ${
|
||||
getAffectedRange(
|
||||
jsArgumentsConsumed,
|
||||
validatedArgumentExtractors[i].getJSArgumentsNeeded()
|
||||
)
|
||||
})",
|
||||
e)
|
||||
}
|
||||
|
||||
try {
|
||||
method.invoke(moduleWrapper.module, *validatedArguments)
|
||||
} catch (e: IllegalArgumentException) {
|
||||
throw RuntimeException(createInvokeExceptionMessage(traceName), e)
|
||||
} catch (e: IllegalAccessException) {
|
||||
throw RuntimeException(createInvokeExceptionMessage(traceName), e)
|
||||
} catch (e: InvocationTargetException) {
|
||||
// Exceptions thrown from native module calls end up wrapped in InvocationTargetException
|
||||
// which just make traces harder to read and bump out useful information
|
||||
if (e.cause is RuntimeException) {
|
||||
throw (e.cause as RuntimeException)
|
||||
}
|
||||
throw RuntimeException(createInvokeExceptionMessage(traceName), e)
|
||||
}
|
||||
} finally {
|
||||
SystraceMessage.endSection(TRACE_TAG_REACT).flush()
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
init {
|
||||
LegacyArchitectureLogger.assertLegacyArchitecture(
|
||||
"JavaMethodWrapper", LegacyArchitectureLogLevel.ERROR)
|
||||
}
|
||||
|
||||
private val ARGUMENT_EXTRACTOR_BOOLEAN: ArgumentExtractor<Boolean> =
|
||||
object : ArgumentExtractor<Boolean>() {
|
||||
override fun extractArgument(
|
||||
jsInstance: JSInstance,
|
||||
jsArguments: ReadableArray,
|
||||
atIndex: Int
|
||||
): Boolean = jsArguments.getBoolean(atIndex)
|
||||
}
|
||||
|
||||
private val ARGUMENT_EXTRACTOR_DOUBLE: ArgumentExtractor<Double> =
|
||||
object : ArgumentExtractor<Double>() {
|
||||
override fun extractArgument(
|
||||
jsInstance: JSInstance,
|
||||
jsArguments: ReadableArray,
|
||||
atIndex: Int
|
||||
): Double = jsArguments.getDouble(atIndex)
|
||||
}
|
||||
|
||||
private val ARGUMENT_EXTRACTOR_FLOAT: ArgumentExtractor<Float> =
|
||||
object : ArgumentExtractor<Float>() {
|
||||
override fun extractArgument(
|
||||
jsInstance: JSInstance,
|
||||
jsArguments: ReadableArray,
|
||||
atIndex: Int
|
||||
): Float = jsArguments.getDouble(atIndex).toFloat()
|
||||
}
|
||||
|
||||
private val ARGUMENT_EXTRACTOR_INTEGER: ArgumentExtractor<Int> =
|
||||
object : ArgumentExtractor<Int>() {
|
||||
override fun extractArgument(
|
||||
jsInstance: JSInstance,
|
||||
jsArguments: ReadableArray,
|
||||
atIndex: Int
|
||||
): Int = jsArguments.getDouble(atIndex).toInt()
|
||||
}
|
||||
|
||||
private val ARGUMENT_EXTRACTOR_STRING: ArgumentExtractor<String> =
|
||||
object : ArgumentExtractor<String>() {
|
||||
override fun extractArgument(
|
||||
jsInstance: JSInstance,
|
||||
jsArguments: ReadableArray,
|
||||
atIndex: Int
|
||||
): String? = jsArguments.getString(atIndex)
|
||||
}
|
||||
|
||||
private val ARGUMENT_EXTRACTOR_ARRAY: ArgumentExtractor<ReadableArray> =
|
||||
object : ArgumentExtractor<ReadableArray>() {
|
||||
override fun extractArgument(
|
||||
jsInstance: JSInstance,
|
||||
jsArguments: ReadableArray,
|
||||
atIndex: Int
|
||||
): ReadableArray? = jsArguments.getArray(atIndex)
|
||||
}
|
||||
|
||||
private val ARGUMENT_EXTRACTOR_DYNAMIC: ArgumentExtractor<Dynamic> =
|
||||
object : ArgumentExtractor<Dynamic>() {
|
||||
override fun extractArgument(
|
||||
jsInstance: JSInstance,
|
||||
jsArguments: ReadableArray,
|
||||
atIndex: Int
|
||||
): Dynamic = DynamicFromArray.create(jsArguments, atIndex)
|
||||
}
|
||||
|
||||
private val ARGUMENT_EXTRACTOR_MAP: ArgumentExtractor<ReadableMap> =
|
||||
object : ArgumentExtractor<ReadableMap>() {
|
||||
override fun extractArgument(
|
||||
jsInstance: JSInstance,
|
||||
jsArguments: ReadableArray,
|
||||
atIndex: Int
|
||||
): ReadableMap? = jsArguments.getMap(atIndex)
|
||||
}
|
||||
|
||||
private val ARGUMENT_EXTRACTOR_CALLBACK: ArgumentExtractor<Callback> =
|
||||
object : ArgumentExtractor<Callback>() {
|
||||
override fun extractArgument(
|
||||
jsInstance: JSInstance,
|
||||
jsArguments: ReadableArray,
|
||||
atIndex: Int
|
||||
): Callback? =
|
||||
if (jsArguments.isNull(atIndex)) {
|
||||
null
|
||||
} else {
|
||||
val id = jsArguments.getDouble(atIndex).toInt()
|
||||
CallbackImpl(jsInstance, id)
|
||||
}
|
||||
}
|
||||
|
||||
private val ARGUMENT_EXTRACTOR_PROMISE: ArgumentExtractor<Promise> =
|
||||
object : ArgumentExtractor<Promise>() {
|
||||
override fun getJSArgumentsNeeded(): Int = 2
|
||||
|
||||
override fun extractArgument(
|
||||
jsInstance: JSInstance,
|
||||
jsArguments: ReadableArray,
|
||||
atIndex: Int
|
||||
): Promise {
|
||||
val resolve =
|
||||
ARGUMENT_EXTRACTOR_CALLBACK.extractArgument(jsInstance, jsArguments, atIndex)
|
||||
val reject =
|
||||
ARGUMENT_EXTRACTOR_CALLBACK.extractArgument(jsInstance, jsArguments, atIndex + 1)
|
||||
return PromiseImpl(resolve, reject)
|
||||
}
|
||||
}
|
||||
|
||||
private val DEBUG =
|
||||
PrinterHolder.printer.shouldDisplayLogMessage(ReactDebugOverlayTags.BRIDGE_CALLS)
|
||||
|
||||
private fun paramTypeToChar(paramClass: Class<*>): Char {
|
||||
val tryCommon = commonTypeToChar(paramClass)
|
||||
if (tryCommon != '\u0000') {
|
||||
return tryCommon
|
||||
}
|
||||
return when (paramClass) {
|
||||
Callback::class.java -> 'X'
|
||||
Promise::class.java -> 'P'
|
||||
ReadableMap::class.java -> 'M'
|
||||
ReadableArray::class.java -> 'A'
|
||||
Dynamic::class.java -> 'Y'
|
||||
else -> throw RuntimeException("Got unknown param class: ${paramClass.simpleName}")
|
||||
}
|
||||
}
|
||||
|
||||
private fun returnTypeToChar(returnClass: Class<*>): Char {
|
||||
// Keep this in sync with MethodInvoker
|
||||
val tryCommon = commonTypeToChar(returnClass)
|
||||
if (tryCommon != '\u0000') {
|
||||
return tryCommon
|
||||
}
|
||||
return when (returnClass) {
|
||||
Void.TYPE -> 'v'
|
||||
WritableMap::class.java -> 'M'
|
||||
WritableArray::class.java -> 'A'
|
||||
else -> throw RuntimeException("Got unknown return class: ${returnClass.simpleName}")
|
||||
}
|
||||
}
|
||||
|
||||
private fun commonTypeToChar(typeClass: Class<*>): Char {
|
||||
return when (typeClass) {
|
||||
Boolean::class.javaPrimitiveType -> 'z'
|
||||
Boolean::class.javaObjectType -> 'Z'
|
||||
Int::class.javaPrimitiveType -> 'i'
|
||||
Int::class.javaObjectType -> 'I'
|
||||
Double::class.javaPrimitiveType -> 'd'
|
||||
Double::class.javaObjectType -> 'D'
|
||||
Float::class.javaPrimitiveType -> 'f'
|
||||
Float::class.javaObjectType -> 'F'
|
||||
String::class.java -> 'S'
|
||||
else -> '\u0000'
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes it easier to determine the cause of an error invoking a native method from Javascript
|
||||
* code by adding the function name.
|
||||
*/
|
||||
private fun createInvokeExceptionMessage(traceName: String): String =
|
||||
"Could not invoke $traceName"
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -67,7 +67,7 @@ public class JavaScriptModuleRegistry {
|
||||
return name ?: getJSModuleName(moduleInterface).also { name = it }
|
||||
}
|
||||
|
||||
override fun invoke(proxy: Any, method: Method, args: Array<Any?>?): Any? {
|
||||
public override fun invoke(proxy: Any, method: Method, args: Array<Any?>?): Any? {
|
||||
val jsArgs = if (args != null) Arguments.fromJavaArgs(args) else WritableNativeArray()
|
||||
catalystInstance.callFunction(getJSModuleName(), method.name, jsArgs)
|
||||
return null
|
||||
|
||||
+247
@@ -0,0 +1,247 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package com.facebook.react.bridge;
|
||||
|
||||
import static com.facebook.infer.annotation.Assertions.assertNotNull;
|
||||
import static com.facebook.react.bridge.ReactMarkerConstants.CREATE_MODULE_END;
|
||||
import static com.facebook.react.bridge.ReactMarkerConstants.CREATE_MODULE_START;
|
||||
import static com.facebook.systrace.Systrace.TRACE_TAG_REACT;
|
||||
|
||||
import androidx.annotation.GuardedBy;
|
||||
import androidx.annotation.Nullable;
|
||||
import com.facebook.common.logging.FLog;
|
||||
import com.facebook.debug.holder.PrinterHolder;
|
||||
import com.facebook.debug.tags.ReactDebugOverlayTags;
|
||||
import com.facebook.infer.annotation.Assertions;
|
||||
import com.facebook.infer.annotation.Nullsafe;
|
||||
import com.facebook.proguard.annotations.DoNotStrip;
|
||||
import com.facebook.react.common.ReactConstants;
|
||||
import com.facebook.react.module.model.ReactModuleInfo;
|
||||
import com.facebook.systrace.SystraceMessage;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import javax.inject.Provider;
|
||||
|
||||
/**
|
||||
* Holder to enable us to lazy create native modules.
|
||||
*
|
||||
* <p>This works by taking a provider instead of an instance, when it is first required we'll create
|
||||
* and initialize it. Initialization currently always happens on the UI thread but this is due to
|
||||
* change for performance reasons.
|
||||
*
|
||||
* <p>Lifecycle events via a {@link LifecycleEventListener} will still always happen on the UI
|
||||
* thread.
|
||||
*/
|
||||
@Nullsafe(Nullsafe.Mode.LOCAL)
|
||||
@DoNotStrip
|
||||
public class ModuleHolder {
|
||||
|
||||
private static final AtomicInteger sInstanceKeyCounter = new AtomicInteger(1);
|
||||
|
||||
private final int mInstanceKey = sInstanceKeyCounter.getAndIncrement();
|
||||
|
||||
private final String mName;
|
||||
private final ReactModuleInfo mReactModuleInfo;
|
||||
|
||||
private @Nullable Provider<? extends NativeModule> mProvider;
|
||||
// Outside of the constructor, these should only be checked or set when synchronized on this
|
||||
private @Nullable @GuardedBy("this") NativeModule mModule;
|
||||
|
||||
// These are used to communicate phases of creation and initialization across threads
|
||||
private @GuardedBy("this") boolean mInitializable;
|
||||
private @GuardedBy("this") boolean mIsCreating;
|
||||
private @GuardedBy("this") boolean mIsInitializing;
|
||||
|
||||
public ModuleHolder(ReactModuleInfo moduleInfo, Provider<? extends NativeModule> provider) {
|
||||
mName = moduleInfo.name();
|
||||
mProvider = provider;
|
||||
mReactModuleInfo = moduleInfo;
|
||||
if (moduleInfo.needsEagerInit()) {
|
||||
mModule = create();
|
||||
}
|
||||
}
|
||||
|
||||
public ModuleHolder(NativeModule nativeModule) {
|
||||
mName = nativeModule.getName();
|
||||
mReactModuleInfo =
|
||||
new ReactModuleInfo(
|
||||
nativeModule.getName(),
|
||||
nativeModule.getClass().getSimpleName(),
|
||||
nativeModule.canOverrideExistingModule(),
|
||||
true,
|
||||
CxxModuleWrapper.class.isAssignableFrom(nativeModule.getClass()),
|
||||
ReactModuleInfo.classIsTurboModule(nativeModule.getClass()));
|
||||
|
||||
mModule = nativeModule;
|
||||
PrinterHolder.getPrinter()
|
||||
.logMessage(ReactDebugOverlayTags.NATIVE_MODULE, "NativeModule init: %s", mName);
|
||||
}
|
||||
|
||||
/*
|
||||
* Checks if mModule has been created, and if so tries to initialize the module unless another
|
||||
* thread is already doing the initialization.
|
||||
* If mModule has not been created, records that initialization is needed
|
||||
*/
|
||||
/* package */ void markInitializable() {
|
||||
boolean shouldInitializeNow = false;
|
||||
NativeModule module = null;
|
||||
synchronized (this) {
|
||||
mInitializable = true;
|
||||
if (mModule != null) {
|
||||
Assertions.assertCondition(!mIsInitializing);
|
||||
shouldInitializeNow = true;
|
||||
module = mModule;
|
||||
}
|
||||
}
|
||||
if (shouldInitializeNow) {
|
||||
Assertions.assertNotNull(module);
|
||||
doInitialize(module);
|
||||
}
|
||||
}
|
||||
|
||||
/* package */ synchronized boolean hasInstance() {
|
||||
return mModule != null;
|
||||
}
|
||||
|
||||
public synchronized void destroy() {
|
||||
if (mModule != null) {
|
||||
mModule.invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
@DoNotStrip
|
||||
public String getName() {
|
||||
return mName;
|
||||
}
|
||||
|
||||
public boolean getCanOverrideExistingModule() {
|
||||
return mReactModuleInfo.canOverrideExistingModule();
|
||||
}
|
||||
|
||||
public boolean isTurboModule() {
|
||||
return mReactModuleInfo.isTurboModule();
|
||||
}
|
||||
|
||||
public boolean isCxxModule() {
|
||||
return mReactModuleInfo.isCxxModule();
|
||||
}
|
||||
|
||||
public String getClassName() {
|
||||
return mReactModuleInfo.className();
|
||||
}
|
||||
|
||||
@DoNotStrip
|
||||
public NativeModule getModule() {
|
||||
NativeModule module;
|
||||
boolean shouldCreate = false;
|
||||
synchronized (this) {
|
||||
if (mModule != null) {
|
||||
return mModule;
|
||||
// if mModule has not been set, and no one is creating it. Then this thread should call
|
||||
// create
|
||||
} else if (!mIsCreating) {
|
||||
shouldCreate = true;
|
||||
mIsCreating = true;
|
||||
} else {
|
||||
// Wait for mModule to be created by another thread
|
||||
}
|
||||
}
|
||||
if (shouldCreate) {
|
||||
module = create();
|
||||
// Once module is built (and initialized if markInitializable has been called), modify mModule
|
||||
// And signal any waiting threads that it is acceptable to read the field now
|
||||
synchronized (this) {
|
||||
mIsCreating = false;
|
||||
this.notifyAll();
|
||||
}
|
||||
return module;
|
||||
} else {
|
||||
synchronized (this) {
|
||||
// Block waiting for another thread to build mModule instance
|
||||
// Since mIsCreating is true until after creation and instantiation (if needed), we wait
|
||||
// until the module is ready to use.
|
||||
while (mModule == null && mIsCreating) {
|
||||
try {
|
||||
this.wait();
|
||||
} catch (InterruptedException e) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
return Assertions.assertNotNull(mModule);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private NativeModule create() {
|
||||
SoftAssertions.assertCondition(mModule == null, "Creating an already created module.");
|
||||
ReactMarker.logMarker(CREATE_MODULE_START, mName, mInstanceKey);
|
||||
SystraceMessage.beginSection(TRACE_TAG_REACT, "ModuleHolder.createModule")
|
||||
.arg("name", mName)
|
||||
.flush();
|
||||
PrinterHolder.getPrinter()
|
||||
.logMessage(ReactDebugOverlayTags.NATIVE_MODULE, "NativeModule init: %s", mName);
|
||||
NativeModule module;
|
||||
try {
|
||||
module = assertNotNull(mProvider).get();
|
||||
mProvider = null;
|
||||
boolean shouldInitializeNow = false;
|
||||
synchronized (this) {
|
||||
mModule = module;
|
||||
if (mInitializable && !mIsInitializing) {
|
||||
shouldInitializeNow = true;
|
||||
}
|
||||
}
|
||||
if (shouldInitializeNow) {
|
||||
doInitialize(module);
|
||||
}
|
||||
} catch (Throwable ex) {
|
||||
/**
|
||||
* When NativeModules are created from JavaScript, any exception that occurs in the creation
|
||||
* process will have its stack trace swallowed before we display a RedBox to the user. Really,
|
||||
* we should have our HostObjects on Android understand JniExceptions and log the stack trace
|
||||
* to logcat. For now, logging to Logcat directly when creation fails is sufficient.
|
||||
*
|
||||
* @todo(T53311351)
|
||||
*/
|
||||
FLog.e(ReactConstants.TAG, ex, "Failed to create NativeModule '%s'", mName);
|
||||
throw ex;
|
||||
} finally {
|
||||
ReactMarker.logMarker(CREATE_MODULE_END, mName, mInstanceKey);
|
||||
SystraceMessage.endSection(TRACE_TAG_REACT).flush();
|
||||
}
|
||||
return module;
|
||||
}
|
||||
|
||||
private void doInitialize(NativeModule module) {
|
||||
SystraceMessage.beginSection(TRACE_TAG_REACT, "ModuleHolder.initialize")
|
||||
.arg("name", mName)
|
||||
.flush();
|
||||
ReactMarker.logMarker(ReactMarkerConstants.INITIALIZE_MODULE_START, mName, mInstanceKey);
|
||||
try {
|
||||
boolean shouldInitialize = false;
|
||||
// Check to see if another thread is initializing the object, if not claim the responsibility
|
||||
synchronized (this) {
|
||||
if (mInitializable && !mIsInitializing) {
|
||||
shouldInitialize = true;
|
||||
mIsInitializing = true;
|
||||
}
|
||||
}
|
||||
if (shouldInitialize) {
|
||||
module.initialize();
|
||||
// Once finished, set flags accordingly, but we don't expect anyone to wait for this to
|
||||
// finish
|
||||
// So no need to notify other threads
|
||||
synchronized (this) {
|
||||
mIsInitializing = false;
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
ReactMarker.logMarker(ReactMarkerConstants.INITIALIZE_MODULE_END, mName, mInstanceKey);
|
||||
SystraceMessage.endSection(TRACE_TAG_REACT).flush();
|
||||
}
|
||||
}
|
||||
}
|
||||
-226
@@ -1,226 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package com.facebook.react.bridge
|
||||
|
||||
import androidx.annotation.GuardedBy
|
||||
import com.facebook.common.logging.FLog
|
||||
import com.facebook.debug.holder.PrinterHolder
|
||||
import com.facebook.debug.tags.ReactDebugOverlayTags
|
||||
import com.facebook.proguard.annotations.DoNotStrip
|
||||
import com.facebook.react.common.ReactConstants
|
||||
import com.facebook.react.module.model.ReactModuleInfo
|
||||
import com.facebook.systrace.Systrace.TRACE_TAG_REACT
|
||||
import com.facebook.systrace.SystraceMessage
|
||||
import java.util.concurrent.atomic.AtomicInteger
|
||||
import javax.inject.Provider
|
||||
|
||||
/**
|
||||
* Holder to enable us to lazy create native modules.
|
||||
*
|
||||
* This works by taking a provider instead of an instance, when it is first required we'll create
|
||||
* and initialize it. Initialization currently always happens on the UI thread but this is due to
|
||||
* change for performance reasons.
|
||||
*
|
||||
* Lifecycle events via a [LifecycleEventListener] will still always happen on the UI thread.
|
||||
*/
|
||||
@DoNotStrip
|
||||
public class ModuleHolder {
|
||||
private val instanceKey = instanceKeyCounter.getAndIncrement()
|
||||
@get:DoNotStrip public val name: String
|
||||
private val reactModuleInfo: ReactModuleInfo
|
||||
|
||||
private var provider: Provider<out NativeModule>? = null
|
||||
// Outside of the constructor, this should only be checked or set when synchronized on this
|
||||
@GuardedBy("this") private var internalModule: NativeModule? = null
|
||||
// This is used to communicate phases of creation and initialization across threads
|
||||
@GuardedBy("this") private var initializable = false
|
||||
@GuardedBy("this") private var isCreating = false
|
||||
@GuardedBy("this") private var isInitializing = false
|
||||
|
||||
public constructor(moduleInfo: ReactModuleInfo, provider: Provider<out NativeModule?>) {
|
||||
name = moduleInfo.name
|
||||
this.provider = provider
|
||||
reactModuleInfo = moduleInfo
|
||||
if (moduleInfo.needsEagerInit) {
|
||||
internalModule = create()
|
||||
}
|
||||
}
|
||||
|
||||
public constructor(nativeModule: NativeModule) {
|
||||
name = nativeModule.name
|
||||
reactModuleInfo =
|
||||
ReactModuleInfo(
|
||||
nativeModule.name,
|
||||
nativeModule.javaClass.simpleName,
|
||||
nativeModule.canOverrideExistingModule(),
|
||||
true,
|
||||
CxxModuleWrapper::class.java.isAssignableFrom(nativeModule.javaClass),
|
||||
ReactModuleInfo.classIsTurboModule(nativeModule.javaClass))
|
||||
|
||||
internalModule = nativeModule
|
||||
PrinterHolder.printer.logMessage(
|
||||
ReactDebugOverlayTags.NATIVE_MODULE, "NativeModule init: %s", name)
|
||||
}
|
||||
|
||||
/*
|
||||
* Checks if [internalModule] has been created, and if so tries to initialize the module unless another
|
||||
* thread is already doing the initialization.
|
||||
* If [internalModule] has not been created, records that initialization is needed.
|
||||
*/
|
||||
internal fun markInitializable() {
|
||||
var shouldInitializeNow = false
|
||||
var module: NativeModule? = null
|
||||
synchronized(this) {
|
||||
initializable = true
|
||||
if (internalModule != null) {
|
||||
check(!isInitializing)
|
||||
shouldInitializeNow = true
|
||||
module = internalModule
|
||||
}
|
||||
}
|
||||
if (shouldInitializeNow) {
|
||||
checkNotNull(module)
|
||||
doInitialize(module)
|
||||
}
|
||||
}
|
||||
|
||||
@Synchronized internal fun hasInstance(): Boolean = internalModule != null
|
||||
|
||||
@Synchronized
|
||||
public fun destroy() {
|
||||
internalModule?.invalidate()
|
||||
}
|
||||
|
||||
public val canOverrideExistingModule: Boolean
|
||||
get() = reactModuleInfo.canOverrideExistingModule
|
||||
|
||||
public val isTurboModule: Boolean
|
||||
get() = reactModuleInfo.isTurboModule
|
||||
|
||||
public val isCxxModule: Boolean
|
||||
get() = reactModuleInfo.isCxxModule
|
||||
|
||||
public val className: String
|
||||
get() = reactModuleInfo.className
|
||||
|
||||
@get:DoNotStrip
|
||||
public val module: NativeModule
|
||||
get() {
|
||||
val module: NativeModule
|
||||
var shouldCreate = false
|
||||
synchronized(this) {
|
||||
val safeModule = internalModule
|
||||
if (safeModule != null) {
|
||||
return safeModule
|
||||
// if `internalModule` has not been set, and no one is creating it. Then this thread
|
||||
// should call
|
||||
// create
|
||||
} else if (!isCreating) {
|
||||
shouldCreate = true
|
||||
isCreating = true
|
||||
} else {
|
||||
// Wait for `internalModule` to be created by another thread
|
||||
}
|
||||
}
|
||||
if (shouldCreate) {
|
||||
module = create()
|
||||
// Once module is built (and initialized if markInitializable has been called), modify
|
||||
// `internalModule`
|
||||
// And signal any waiting threads that it is acceptable to read the field now
|
||||
synchronized(this) {
|
||||
isCreating = false
|
||||
@Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN") (this as Object).notifyAll()
|
||||
}
|
||||
return module
|
||||
} else {
|
||||
synchronized(this) {
|
||||
// Block waiting for another thread to build `internalModule` instance
|
||||
// Since isCreating is true until after creation and instantiation (if needed), we wait
|
||||
// until the module is ready to use.
|
||||
while (internalModule == null && isCreating) {
|
||||
try {
|
||||
@Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN") (this as Object).wait()
|
||||
} catch (e: InterruptedException) {
|
||||
continue
|
||||
}
|
||||
}
|
||||
return checkNotNull(internalModule)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun create(): NativeModule {
|
||||
SoftAssertions.assertCondition(internalModule == null, "Creating an already created module.")
|
||||
ReactMarker.logMarker(ReactMarkerConstants.CREATE_MODULE_START, name, instanceKey)
|
||||
SystraceMessage.beginSection(TRACE_TAG_REACT, "ModuleHolder.createModule")
|
||||
.arg("name", name)
|
||||
.flush()
|
||||
PrinterHolder.printer.logMessage(
|
||||
ReactDebugOverlayTags.NATIVE_MODULE, "NativeModule init: %s", name)
|
||||
val module: NativeModule
|
||||
try {
|
||||
module = checkNotNull(provider).get()
|
||||
provider = null
|
||||
var shouldInitializeNow = false
|
||||
synchronized(this) {
|
||||
internalModule = module
|
||||
if (initializable && !isInitializing) {
|
||||
shouldInitializeNow = true
|
||||
}
|
||||
}
|
||||
if (shouldInitializeNow) {
|
||||
doInitialize(module)
|
||||
}
|
||||
} catch (e: Throwable) {
|
||||
/**
|
||||
* When NativeModules are created from JavaScript, any exception that occurs in the creation
|
||||
* process will have its stack trace swallowed before we display a RedBox to the user. Really,
|
||||
* we should have our HostObjects on Android understand JniExceptions and log the stack trace
|
||||
* to logcat. For now, logging to Logcat directly when creation fails is sufficient.
|
||||
*
|
||||
* @todo(T53311351)
|
||||
*/
|
||||
FLog.e(ReactConstants.TAG, e, "Failed to create NativeModule '%s'", name)
|
||||
throw e
|
||||
} finally {
|
||||
ReactMarker.logMarker(ReactMarkerConstants.CREATE_MODULE_END, name, instanceKey)
|
||||
SystraceMessage.endSection(TRACE_TAG_REACT).flush()
|
||||
}
|
||||
return module
|
||||
}
|
||||
|
||||
private fun doInitialize(module: NativeModule?) {
|
||||
SystraceMessage.beginSection(TRACE_TAG_REACT, "ModuleHolder.initialize")
|
||||
.arg("name", name)
|
||||
.flush()
|
||||
ReactMarker.logMarker(ReactMarkerConstants.INITIALIZE_MODULE_START, name, instanceKey)
|
||||
try {
|
||||
var shouldInitialize = false
|
||||
// Check to see if another thread is initializing the object, if not claim the responsibility
|
||||
synchronized(this) {
|
||||
if (initializable && !isInitializing) {
|
||||
shouldInitialize = true
|
||||
isInitializing = true
|
||||
}
|
||||
}
|
||||
if (shouldInitialize) {
|
||||
module?.initialize()
|
||||
// Once finished, set flags accordingly, but we don't expect anyone to wait for this to
|
||||
// finish, so no need to notify other threads.
|
||||
synchronized(this) { isInitializing = false }
|
||||
}
|
||||
} finally {
|
||||
ReactMarker.logMarker(ReactMarkerConstants.INITIALIZE_MODULE_END, name, instanceKey)
|
||||
SystraceMessage.endSection(TRACE_TAG_REACT).flush()
|
||||
}
|
||||
}
|
||||
|
||||
private companion object {
|
||||
private val instanceKeyCounter = AtomicInteger(1)
|
||||
}
|
||||
}
|
||||
+7
-16
@@ -33,7 +33,7 @@ internal class FpsView(reactContext: ReactContext?) : FrameLayout(reactContext!!
|
||||
textView = findViewById<View>(R.id.fps_text) as TextView
|
||||
frameCallback = FpsDebugFrameCallback(reactContext!!)
|
||||
fpsMonitorRunnable = FPSMonitorRunnable()
|
||||
setCurrentFPS(0.0, 0.0, 0, 0, frameCallback.isRunningOnFabric)
|
||||
setCurrentFPS(0.0, 0.0, 0, 0)
|
||||
}
|
||||
|
||||
override fun onAttachedToWindow() {
|
||||
@@ -53,21 +53,16 @@ internal class FpsView(reactContext: ReactContext?) : FrameLayout(reactContext!!
|
||||
currentFPS: Double,
|
||||
currentJSFPS: Double,
|
||||
droppedUIFrames: Int,
|
||||
total4PlusFrameStutters: Int,
|
||||
runningOnFabric: Boolean
|
||||
total4PlusFrameStutters: Int
|
||||
) {
|
||||
var fpsString =
|
||||
val fpsString =
|
||||
String.format(
|
||||
Locale.US,
|
||||
"UI: %.1f fps\n%d dropped so far\n%d stutters (4+) so far",
|
||||
"UI: %.1f fps\n%d dropped so far\n%d stutters (4+) so far\nJS: %.1f fps",
|
||||
currentFPS,
|
||||
droppedUIFrames,
|
||||
total4PlusFrameStutters)
|
||||
if (!runningOnFabric) {
|
||||
// The JS FPS is only relevant for the legacy architecture, as Fabric we don't use
|
||||
// BridgeIdleDebugListener to track JS frame drops.
|
||||
fpsString += String.format(Locale.US, "\nJS: %.1f fps", currentJSFPS)
|
||||
}
|
||||
total4PlusFrameStutters,
|
||||
currentJSFPS)
|
||||
textView.text = fpsString
|
||||
FLog.d(ReactConstants.TAG, fpsString)
|
||||
}
|
||||
@@ -85,11 +80,7 @@ internal class FpsView(reactContext: ReactContext?) : FrameLayout(reactContext!!
|
||||
totalFramesDropped += frameCallback.expectedNumFrames - frameCallback.numFrames
|
||||
total4PlusFrameStutters += frameCallback.get4PlusFrameStutters()
|
||||
setCurrentFPS(
|
||||
frameCallback.fps,
|
||||
frameCallback.jsFPS,
|
||||
totalFramesDropped,
|
||||
total4PlusFrameStutters,
|
||||
frameCallback.isRunningOnFabric)
|
||||
frameCallback.fps, frameCallback.jsFPS, totalFramesDropped, total4PlusFrameStutters)
|
||||
frameCallback.reset()
|
||||
postDelayed(this, UPDATE_INTERVAL_MS.toLong())
|
||||
}
|
||||
|
||||
+2
-2
@@ -40,7 +40,7 @@ internal class DevMenuModule(
|
||||
devSupportManager.setHotModuleReplacementEnabled(enabled)
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val NAME: String = NativeDevMenuSpec.NAME
|
||||
public companion object {
|
||||
public const val NAME: String = NativeDevMenuSpec.NAME
|
||||
}
|
||||
}
|
||||
|
||||
+55
-23
@@ -8,10 +8,12 @@
|
||||
package com.facebook.react.modules.debug
|
||||
|
||||
import android.view.Choreographer
|
||||
import com.facebook.infer.annotation.Assertions
|
||||
import com.facebook.react.bridge.ReactContext
|
||||
import com.facebook.react.bridge.UiThreadUtil
|
||||
import com.facebook.react.common.build.ReactBuildConfig
|
||||
import com.facebook.react.uimanager.UIManagerModule
|
||||
import java.util.TreeMap
|
||||
|
||||
/**
|
||||
* Each time a frame is drawn, records whether it should have expected any more callbacks since the
|
||||
@@ -23,8 +25,17 @@ import com.facebook.react.uimanager.UIManagerModule
|
||||
* idle and not trying to update the UI. This is different from the FPS above since JS rendering is
|
||||
* async.
|
||||
*/
|
||||
internal class FpsDebugFrameCallback(private val reactContext: ReactContext) :
|
||||
public class FpsDebugFrameCallback(private val reactContext: ReactContext) :
|
||||
Choreographer.FrameCallback {
|
||||
public class FpsInfo(
|
||||
public val totalFrames: Int,
|
||||
public val totalJsFrames: Int,
|
||||
public val totalExpectedFrames: Int,
|
||||
public val total4PlusFrameStutters: Int,
|
||||
public val fps: Double,
|
||||
public val jsFps: Double,
|
||||
public val totalTimeMs: Int
|
||||
)
|
||||
|
||||
private var choreographer: Choreographer? = null
|
||||
private val didJSUpdateUiDuringFrameDetector: DidJSUpdateUiDuringFrameDetector =
|
||||
@@ -35,7 +46,9 @@ internal class FpsDebugFrameCallback(private val reactContext: ReactContext) :
|
||||
private var expectedNumFramesPrev = 0
|
||||
private var fourPlusFrameStutters = 0
|
||||
private var numFrameCallbacksWithBatchDispatches = 0
|
||||
private var isRecordingFpsInfoAtEachFrame = false
|
||||
private var targetFps = DEFAULT_FPS
|
||||
private var timeToFps: TreeMap<Long, FpsInfo>? = null
|
||||
|
||||
override fun doFrame(l: Long) {
|
||||
if (firstFrameTime == -1L) {
|
||||
@@ -52,12 +65,25 @@ internal class FpsDebugFrameCallback(private val reactContext: ReactContext) :
|
||||
if (framesDropped >= 4) {
|
||||
fourPlusFrameStutters++
|
||||
}
|
||||
if (isRecordingFpsInfoAtEachFrame) {
|
||||
Assertions.assertNotNull(timeToFps)
|
||||
val info =
|
||||
FpsInfo(
|
||||
numFrames,
|
||||
numJSFrames,
|
||||
expectedNumFrames,
|
||||
fourPlusFrameStutters,
|
||||
fps,
|
||||
jsFPS,
|
||||
totalTimeMS)
|
||||
timeToFps?.put(System.currentTimeMillis(), info)
|
||||
}
|
||||
expectedNumFramesPrev = expectedNumFrames
|
||||
choreographer?.postFrameCallback(this)
|
||||
}
|
||||
|
||||
@JvmOverloads
|
||||
fun start(targetFps: Double = this.targetFps) {
|
||||
public fun start(targetFps: Double = this.targetFps) {
|
||||
// T172641976: re-think if we need to implement addBridgeIdleDebugListener and
|
||||
// removeBridgeIdleDebugListener for Bridgeless
|
||||
@Suppress("DEPRECATION")
|
||||
@@ -65,11 +91,6 @@ internal class FpsDebugFrameCallback(private val reactContext: ReactContext) :
|
||||
val uiManagerModule = reactContext.getNativeModule(UIManagerModule::class.java)
|
||||
if (!reactContext.isBridgeless) {
|
||||
reactContext.catalystInstance.addBridgeIdleDebugListener(didJSUpdateUiDuringFrameDetector)
|
||||
isRunningOnFabric = false
|
||||
} else {
|
||||
// T172641976 Consider either implementing a mechanism similar to addBridgeIdleDebugListener
|
||||
// for Fabric or point users to use RNDT.
|
||||
isRunningOnFabric = true
|
||||
}
|
||||
uiManagerModule?.setViewHierarchyUpdateDebugListener(didJSUpdateUiDuringFrameDetector)
|
||||
}
|
||||
@@ -80,7 +101,13 @@ internal class FpsDebugFrameCallback(private val reactContext: ReactContext) :
|
||||
}
|
||||
}
|
||||
|
||||
fun stop() {
|
||||
public fun startAndRecordFpsAtEachFrame() {
|
||||
timeToFps = TreeMap()
|
||||
isRecordingFpsInfoAtEachFrame = true
|
||||
start()
|
||||
}
|
||||
|
||||
public fun stop() {
|
||||
@Suppress("DEPRECATION")
|
||||
if (!ReactBuildConfig.UNSTABLE_ENABLE_MINIFY_LEGACY_ARCHITECTURE) {
|
||||
val uiManagerModule = reactContext.getNativeModule(UIManagerModule::class.java)
|
||||
@@ -96,48 +123,53 @@ internal class FpsDebugFrameCallback(private val reactContext: ReactContext) :
|
||||
}
|
||||
}
|
||||
|
||||
val fps: Double
|
||||
public val fps: Double
|
||||
get() =
|
||||
if (lastFrameTime == firstFrameTime) {
|
||||
0.0
|
||||
} else numFrames.toDouble() * 1e9 / (lastFrameTime - firstFrameTime)
|
||||
|
||||
/**
|
||||
* Please note that this value is not relevant if running on Fabric. That's because we don't
|
||||
* implement addBridgeIdleDebugListener on Fabric.
|
||||
*/
|
||||
val jsFPS: Double
|
||||
public val jsFPS: Double
|
||||
get() =
|
||||
if (lastFrameTime == firstFrameTime) {
|
||||
0.0
|
||||
} else numJSFrames.toDouble() * 1e9 / (lastFrameTime - firstFrameTime)
|
||||
|
||||
val numFrames: Int
|
||||
public val numFrames: Int
|
||||
get() = numFrameCallbacks - 1
|
||||
|
||||
private val numJSFrames: Int
|
||||
public val numJSFrames: Int
|
||||
get() = numFrameCallbacksWithBatchDispatches - 1
|
||||
|
||||
val expectedNumFrames: Int
|
||||
public val expectedNumFrames: Int
|
||||
get() {
|
||||
val totalTimeMS = totalTimeMS.toDouble()
|
||||
return (targetFps * totalTimeMS / 1000 + 1).toInt()
|
||||
}
|
||||
|
||||
var isRunningOnFabric = true
|
||||
private set
|
||||
public fun get4PlusFrameStutters(): Int = fourPlusFrameStutters
|
||||
|
||||
fun get4PlusFrameStutters(): Int = fourPlusFrameStutters
|
||||
|
||||
private val totalTimeMS: Int
|
||||
public val totalTimeMS: Int
|
||||
get() = ((lastFrameTime.toDouble() - firstFrameTime) / 1000000.0).toInt()
|
||||
|
||||
fun reset() {
|
||||
/**
|
||||
* Returns the FpsInfo as if stop had been called at the given upToTimeMs. Only valid if
|
||||
* monitoring was started with [startAndRecordFpsAtEachFrame].
|
||||
*/
|
||||
public fun getFpsInfo(upToTimeMs: Long): FpsInfo? {
|
||||
Assertions.assertNotNull(timeToFps, "FPS was not recorded at each frame!")
|
||||
val (_, value) = timeToFps?.floorEntry(upToTimeMs) ?: return null
|
||||
return value
|
||||
}
|
||||
|
||||
public fun reset() {
|
||||
firstFrameTime = -1
|
||||
lastFrameTime = -1
|
||||
numFrameCallbacks = 0
|
||||
fourPlusFrameStutters = 0
|
||||
numFrameCallbacksWithBatchDispatches = 0
|
||||
isRecordingFpsInfoAtEachFrame = false
|
||||
timeToFps = null
|
||||
}
|
||||
|
||||
private companion object {
|
||||
|
||||
+2
-2
@@ -74,7 +74,7 @@ internal class DeviceInfoModule(reactContext: ReactApplicationContext) :
|
||||
reactApplicationContext.removeLifecycleEventListener(this)
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val NAME: String = NativeDeviceInfoSpec.NAME
|
||||
public companion object {
|
||||
public const val NAME: String = NativeDeviceInfoSpec.NAME
|
||||
}
|
||||
}
|
||||
|
||||
+10
-10
@@ -84,7 +84,7 @@ internal class BridgelessCatalystInstance(private val reactHost: ReactHostImpl)
|
||||
throw UnsupportedOperationException("Unimplemented method 'destroy'")
|
||||
}
|
||||
|
||||
override val isDestroyed: Boolean
|
||||
public override val isDestroyed: Boolean
|
||||
get() = throw UnsupportedOperationException("Unimplemented method 'isDestroyed'")
|
||||
|
||||
@VisibleForTesting
|
||||
@@ -96,16 +96,16 @@ internal class BridgelessCatalystInstance(private val reactHost: ReactHostImpl)
|
||||
reactHost.currentReactContext?.getJSModule(jsInterface)
|
||||
|
||||
@get:Deprecated("Deprecated in Java")
|
||||
override val javaScriptContextHolder: JavaScriptContextHolder
|
||||
public override val javaScriptContextHolder: JavaScriptContextHolder
|
||||
get() = reactHost.javaScriptContextHolder!!
|
||||
|
||||
@Suppress("INAPPLICABLE_JVM_NAME")
|
||||
@get:Deprecated("Deprecated in Java")
|
||||
@get:JvmName("getJSCallInvokerHolder") // This is needed to keep backward compatibility
|
||||
override val jsCallInvokerHolder: CallInvokerHolder
|
||||
public override val jsCallInvokerHolder: CallInvokerHolder
|
||||
get() = reactHost.jsCallInvokerHolder!!
|
||||
|
||||
override val nativeMethodCallInvokerHolder: NativeMethodCallInvokerHolder
|
||||
public override val nativeMethodCallInvokerHolder: NativeMethodCallInvokerHolder
|
||||
get() =
|
||||
throw UnsupportedOperationException(
|
||||
"Unimplemented method 'getNativeMethodCallInvokerHolder'")
|
||||
@@ -119,23 +119,23 @@ internal class BridgelessCatalystInstance(private val reactHost: ReactHostImpl)
|
||||
override fun getNativeModule(moduleName: String): NativeModule? =
|
||||
reactHost.getNativeModule(moduleName)
|
||||
|
||||
override val nativeModules: Collection<NativeModule>
|
||||
public override val nativeModules: Collection<NativeModule>
|
||||
get() = reactHost.nativeModules
|
||||
|
||||
override val reactQueueConfiguration: ReactQueueConfiguration
|
||||
public override val reactQueueConfiguration: ReactQueueConfiguration
|
||||
get() = reactHost.reactQueueConfiguration!!
|
||||
|
||||
override val runtimeExecutor: RuntimeExecutor?
|
||||
public override val runtimeExecutor: RuntimeExecutor?
|
||||
get() = reactHost.runtimeExecutor
|
||||
|
||||
override val runtimeScheduler: RuntimeScheduler
|
||||
public override val runtimeScheduler: RuntimeScheduler
|
||||
get() = throw UnsupportedOperationException("Unimplemented method 'getRuntimeScheduler'")
|
||||
|
||||
override fun extendNativeModules(modules: NativeModuleRegistry) {
|
||||
public override fun extendNativeModules(modules: NativeModuleRegistry) {
|
||||
throw UnsupportedOperationException("Unimplemented method 'extendNativeModules'")
|
||||
}
|
||||
|
||||
override val sourceURL: String
|
||||
public override val sourceURL: String
|
||||
get() = throw UnsupportedOperationException("Unimplemented method 'getSourceURL'")
|
||||
|
||||
override fun addBridgeIdleDebugListener(listener: NotThreadSafeBridgeIdleDebugListener) {
|
||||
|
||||
+1
-1
@@ -57,7 +57,7 @@ internal class BridgelessReactContext(context: Context, private val reactHost: R
|
||||
|
||||
override fun getSourceURL(): String? = sourceURLRef.get()
|
||||
|
||||
fun setSourceURL(sourceURL: String?) {
|
||||
public fun setSourceURL(sourceURL: String?) {
|
||||
sourceURLRef.set(sourceURL)
|
||||
}
|
||||
|
||||
|
||||
+11
-11
@@ -59,7 +59,7 @@ internal class FabricEventDispatcher(
|
||||
eventEmitter.registerFabricEventEmitter(fabricEventEmitter)
|
||||
}
|
||||
|
||||
override fun dispatchEvent(event: Event<*>) {
|
||||
public override fun dispatchEvent(event: Event<*>) {
|
||||
for (listener in listeners) {
|
||||
listener.onEventDispatch(event)
|
||||
}
|
||||
@@ -100,7 +100,7 @@ internal class FabricEventDispatcher(
|
||||
}
|
||||
}
|
||||
|
||||
override fun dispatchAllEvents() {
|
||||
public override fun dispatchAllEvents() {
|
||||
scheduleDispatchOfBatchedEvents()
|
||||
}
|
||||
|
||||
@@ -116,46 +116,46 @@ internal class FabricEventDispatcher(
|
||||
}
|
||||
|
||||
/** Add a listener to this EventDispatcher. */
|
||||
override fun addListener(listener: EventDispatcherListener) {
|
||||
public override fun addListener(listener: EventDispatcherListener) {
|
||||
listeners.add(listener)
|
||||
}
|
||||
|
||||
/** Remove a listener from this EventDispatcher. */
|
||||
override fun removeListener(listener: EventDispatcherListener) {
|
||||
public override fun removeListener(listener: EventDispatcherListener) {
|
||||
listeners.remove(listener)
|
||||
}
|
||||
|
||||
override fun addBatchEventDispatchedListener(listener: BatchEventDispatchedListener) {
|
||||
public override fun addBatchEventDispatchedListener(listener: BatchEventDispatchedListener) {
|
||||
postEventDispatchListeners.add(listener)
|
||||
}
|
||||
|
||||
override fun removeBatchEventDispatchedListener(listener: BatchEventDispatchedListener) {
|
||||
public override fun removeBatchEventDispatchedListener(listener: BatchEventDispatchedListener) {
|
||||
postEventDispatchListeners.remove(listener)
|
||||
}
|
||||
|
||||
override fun onHostResume() {
|
||||
public override fun onHostResume() {
|
||||
scheduleDispatchOfBatchedEvents()
|
||||
if (!ReactNativeFeatureFlags.useOptimizedEventBatchingOnAndroid()) {
|
||||
currentFrameCallback.resume()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onHostPause() {
|
||||
public override fun onHostPause() {
|
||||
cancelDispatchOfBatchedEvents()
|
||||
}
|
||||
|
||||
override fun onHostDestroy() {
|
||||
public override fun onHostDestroy() {
|
||||
cancelDispatchOfBatchedEvents()
|
||||
}
|
||||
|
||||
fun invalidate() {
|
||||
public fun invalidate() {
|
||||
eventEmitter.registerFabricEventEmitter(null)
|
||||
|
||||
UiThreadUtil.runOnUiThread { cancelDispatchOfBatchedEvents() }
|
||||
}
|
||||
|
||||
@Deprecated("Private API, should only be used when the concrete implementation is known.")
|
||||
override fun onCatalystInstanceDestroyed() {
|
||||
public override fun onCatalystInstanceDestroyed() {
|
||||
invalidate()
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -21,9 +21,9 @@ import com.facebook.react.common.annotations.internal.LegacyArchitectureLogger
|
||||
@LegacyArchitecture(logLevel = LegacyArchitectureLogLevel.ERROR)
|
||||
internal class LayoutUpdateAnimation : AbstractLayoutAnimation() {
|
||||
|
||||
override fun isValid(): Boolean = durationMs > 0
|
||||
internal override fun isValid(): Boolean = durationMs > 0
|
||||
|
||||
override fun createAnimationImpl(
|
||||
internal override fun createAnimationImpl(
|
||||
view: View,
|
||||
x: Int,
|
||||
y: Int,
|
||||
|
||||
+1
-1
@@ -26,7 +26,7 @@ internal class ColorStop(var color: Int? = null, val position: LengthPercentage?
|
||||
internal class ProcessedColorStop(var color: Int? = null, val position: Float? = null)
|
||||
|
||||
internal object ColorStopUtils {
|
||||
fun getFixedColorStops(
|
||||
public fun getFixedColorStops(
|
||||
colorStops: List<ColorStop>,
|
||||
gradientLineLength: Float
|
||||
): List<ProcessedColorStop> {
|
||||
|
||||
+1
-1
@@ -10,5 +10,5 @@ package com.facebook.react.uimanager.style
|
||||
import android.graphics.Shader
|
||||
|
||||
internal interface Gradient {
|
||||
fun getShader(width: Float, height: Float): Shader
|
||||
public fun getShader(width: Float, height: Float): Shader
|
||||
}
|
||||
|
||||
+1
-1
@@ -34,7 +34,7 @@ internal class MaintainVisibleScrollPositionHelper<ScrollViewT>(
|
||||
private val horizontal: Boolean
|
||||
) : UIManagerListener where ScrollViewT : HasSmoothScroll?, ScrollViewT : ViewGroup? {
|
||||
|
||||
var config: Config? = null
|
||||
public var config: Config? = null
|
||||
private var firstVisibleViewRef: WeakReference<View>? = null
|
||||
private var prevFirstVisibleFrame: Rect? = null
|
||||
private var isListening = false
|
||||
|
||||
+3
-3
@@ -16,7 +16,7 @@ import com.facebook.proguard.annotations.DoNotStrip
|
||||
*/
|
||||
@DoNotStrip
|
||||
internal class PreparedLayout(
|
||||
val layout: Layout,
|
||||
val maximumNumberOfLines: Int,
|
||||
val verticalOffset: Float
|
||||
public val layout: Layout,
|
||||
public val maximumNumberOfLines: Int,
|
||||
public val verticalOffset: Float
|
||||
)
|
||||
|
||||
+7
-7
@@ -41,7 +41,7 @@ internal class PreparedLayoutTextView(context: Context) : ViewGroup(context), Re
|
||||
private var clickableSpans: List<ClickableSpan> = emptyList()
|
||||
private var selection: TextSelection? = null
|
||||
|
||||
var preparedLayout: PreparedLayout? = null
|
||||
public var preparedLayout: PreparedLayout? = null
|
||||
set(value) {
|
||||
if (field != value) {
|
||||
val lastSelection = selection
|
||||
@@ -63,7 +63,7 @@ internal class PreparedLayoutTextView(context: Context) : ViewGroup(context), Re
|
||||
|
||||
// T221698007: This is closest to existing behavior, but does not align with web. We may want to
|
||||
// change in the future if not too breaking.
|
||||
var overflow: Overflow = Overflow.HIDDEN
|
||||
public var overflow: Overflow = Overflow.HIDDEN
|
||||
set(value) {
|
||||
if (field != value) {
|
||||
field = value
|
||||
@@ -71,9 +71,9 @@ internal class PreparedLayoutTextView(context: Context) : ViewGroup(context), Re
|
||||
}
|
||||
}
|
||||
|
||||
@ColorInt var selectionColor: Int? = null
|
||||
public @ColorInt var selectionColor: Int? = null
|
||||
|
||||
val text: CharSequence?
|
||||
public val text: CharSequence?
|
||||
get() = preparedLayout?.layout?.text
|
||||
|
||||
init {
|
||||
@@ -88,7 +88,7 @@ internal class PreparedLayoutTextView(context: Context) : ViewGroup(context), Re
|
||||
preparedLayout = null
|
||||
}
|
||||
|
||||
fun recycleView(): Unit {
|
||||
public fun recycleView(): Unit {
|
||||
initView()
|
||||
BackgroundStyleApplicator.reset(this)
|
||||
overflow = Overflow.HIDDEN
|
||||
@@ -122,7 +122,7 @@ internal class PreparedLayoutTextView(context: Context) : ViewGroup(context), Re
|
||||
// No-op
|
||||
}
|
||||
|
||||
fun setSelection(start: Int, end: Int) {
|
||||
public fun setSelection(start: Int, end: Int) {
|
||||
val layout = checkNotNull(preparedLayout).layout
|
||||
if (start < 0 || end > layout.text.length || start >= end) {
|
||||
throw IllegalArgumentException(
|
||||
@@ -143,7 +143,7 @@ internal class PreparedLayoutTextView(context: Context) : ViewGroup(context), Re
|
||||
invalidate()
|
||||
}
|
||||
|
||||
fun clearSelection() {
|
||||
public fun clearSelection() {
|
||||
selection = null
|
||||
invalidate()
|
||||
}
|
||||
|
||||
+11
-11
@@ -98,23 +98,23 @@ internal class PreparedLayoutTextViewManager :
|
||||
}
|
||||
|
||||
@ReactProp(name = "overflow")
|
||||
fun setOverflow(view: PreparedLayoutTextView, overflow: String?): Unit {
|
||||
public fun setOverflow(view: PreparedLayoutTextView, overflow: String?): Unit {
|
||||
view.overflow = overflow?.let { Overflow.fromString(it) } ?: Overflow.HIDDEN
|
||||
}
|
||||
|
||||
@ReactProp(name = "accessible")
|
||||
fun setAccessible(view: PreparedLayoutTextView, accessible: Boolean): Unit {
|
||||
public fun setAccessible(view: PreparedLayoutTextView, accessible: Boolean): Unit {
|
||||
view.isFocusable = accessible
|
||||
}
|
||||
|
||||
@ReactProp(name = "selectable", defaultBoolean = false)
|
||||
fun setSelectable(view: PreparedLayoutTextView, isSelectable: Boolean): Unit {
|
||||
public fun setSelectable(view: PreparedLayoutTextView, isSelectable: Boolean): Unit {
|
||||
// T222052152: Implement fine-grained text selection for PreparedLayoutTextView
|
||||
// view.setTextIsSelectable(isSelectable);
|
||||
}
|
||||
|
||||
@ReactProp(name = "selectionColor", customType = "Color")
|
||||
fun setSelectionColor(view: PreparedLayoutTextView, color: Int?): Unit {
|
||||
public fun setSelectionColor(view: PreparedLayoutTextView, color: Int?): Unit {
|
||||
if (color == null) {
|
||||
view.selectionColor = DefaultStyleValuesUtil.getDefaultTextColorHighlight(view.context)
|
||||
} else {
|
||||
@@ -131,7 +131,7 @@ internal class PreparedLayoutTextViewManager :
|
||||
ViewProps.BORDER_BOTTOM_RIGHT_RADIUS,
|
||||
ViewProps.BORDER_BOTTOM_LEFT_RADIUS],
|
||||
defaultFloat = Float.NaN)
|
||||
fun setBorderRadius(view: PreparedLayoutTextView, index: Int, borderRadius: Float): Unit {
|
||||
public fun setBorderRadius(view: PreparedLayoutTextView, index: Int, borderRadius: Float): Unit {
|
||||
val radius =
|
||||
if (borderRadius.isNaN()) null
|
||||
else LengthPercentage(borderRadius, LengthPercentageType.POINT)
|
||||
@@ -139,7 +139,7 @@ internal class PreparedLayoutTextViewManager :
|
||||
}
|
||||
|
||||
@ReactProp(name = "borderStyle")
|
||||
fun setBorderStyle(view: PreparedLayoutTextView, borderStyle: String?): Unit {
|
||||
public fun setBorderStyle(view: PreparedLayoutTextView, borderStyle: String?): Unit {
|
||||
val parsedBorderStyle = if (borderStyle == null) null else BorderStyle.fromString(borderStyle)
|
||||
BackgroundStyleApplicator.setBorderStyle(view, parsedBorderStyle)
|
||||
}
|
||||
@@ -155,7 +155,7 @@ internal class PreparedLayoutTextViewManager :
|
||||
ViewProps.BORDER_START_WIDTH,
|
||||
ViewProps.BORDER_END_WIDTH],
|
||||
defaultFloat = Float.NaN)
|
||||
fun setBorderWidth(view: PreparedLayoutTextView, index: Int, width: Float): Unit {
|
||||
public fun setBorderWidth(view: PreparedLayoutTextView, index: Int, width: Float): Unit {
|
||||
BackgroundStyleApplicator.setBorderWidth(view, LogicalEdge.values()[index], width)
|
||||
}
|
||||
|
||||
@@ -174,12 +174,12 @@ internal class PreparedLayoutTextViewManager :
|
||||
ViewProps.BORDER_BLOCK_START_COLOR,
|
||||
],
|
||||
customType = "Color")
|
||||
fun setBorderColor(view: PreparedLayoutTextView, index: Int, color: Int?): Unit {
|
||||
public fun setBorderColor(view: PreparedLayoutTextView, index: Int, color: Int?): Unit {
|
||||
BackgroundStyleApplicator.setBorderColor(view, LogicalEdge.values()[index], color)
|
||||
}
|
||||
|
||||
@ReactProp(name = "disabled", defaultBoolean = false)
|
||||
fun setDisabled(view: PreparedLayoutTextView, disabled: Boolean): Unit {
|
||||
public fun setDisabled(view: PreparedLayoutTextView, disabled: Boolean): Unit {
|
||||
view.setEnabled(!disabled)
|
||||
}
|
||||
|
||||
@@ -214,7 +214,7 @@ internal class PreparedLayoutTextViewManager :
|
||||
reactTextViewManagerCallback?.onPostProcessSpannable(text)
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val REACT_CLASS: String = "RCTText"
|
||||
public companion object {
|
||||
public const val REACT_CLASS: String = "RCTText"
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -110,7 +110,7 @@ public abstract class ReactBaseTextShadowNode extends LayoutShadowNode {
|
||||
if (child instanceof ReactRawTextShadowNode) {
|
||||
String childText = ((ReactRawTextShadowNode) child).getText();
|
||||
if (childText != null) {
|
||||
sb.append(TextTransform.apply(childText, textAttributes.textTransform));
|
||||
sb.append(TextTransform.applyNonNull(childText, textAttributes.textTransform));
|
||||
}
|
||||
} else if (child instanceof ReactBaseTextShadowNode) {
|
||||
buildSpannedFromShadowNode(
|
||||
@@ -265,7 +265,7 @@ public abstract class ReactBaseTextShadowNode extends LayoutShadowNode {
|
||||
if (text != null) {
|
||||
// Handle text that is provided via a prop (e.g. the `value` and `defaultValue` props on
|
||||
// TextInput).
|
||||
sb.append(TextTransform.apply(text, textShadowNode.mTextAttributes.textTransform));
|
||||
sb.append(TextTransform.applyNonNull(text, textShadowNode.mTextAttributes.textTransform));
|
||||
}
|
||||
|
||||
buildSpannedFromShadowNode(textShadowNode, sb, ops, null, supportsInlineViews, inlineViews, 0);
|
||||
|
||||
+3
-3
@@ -134,12 +134,12 @@ public constructor(
|
||||
view.setSpanned(spanned)
|
||||
|
||||
val minimumFontSize: Float =
|
||||
paragraphAttributes.getDouble(TextLayoutManager.PA_KEY_MINIMUM_FONT_SIZE).toFloat()
|
||||
paragraphAttributes.getDouble(TextLayoutManager.PA_KEY_MINIMUM_FONT_SIZE.toInt()).toFloat()
|
||||
view.setMinimumFontSize(minimumFontSize)
|
||||
|
||||
val textBreakStrategy =
|
||||
TextAttributeProps.getTextBreakStrategy(
|
||||
paragraphAttributes.getString(TextLayoutManager.PA_KEY_TEXT_BREAK_STRATEGY))
|
||||
paragraphAttributes.getString(TextLayoutManager.PA_KEY_TEXT_BREAK_STRATEGY.toInt()))
|
||||
val currentJustificationMode =
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) 0 else view.getJustificationMode()
|
||||
|
||||
@@ -147,7 +147,7 @@ public constructor(
|
||||
spanned,
|
||||
-1, // UNUSED FOR TEXT
|
||||
false, // TODO add this into local Data
|
||||
TextLayoutManager.getTextGravity(attributedString, spanned),
|
||||
TextLayoutManager.getTextGravity(attributedString, spanned, view.gravityHorizontal),
|
||||
textBreakStrategy,
|
||||
TextAttributeProps.getJustificationMode(props, currentJustificationMode))
|
||||
}
|
||||
|
||||
+1034
File diff suppressed because it is too large
Load Diff
-1041
File diff suppressed because it is too large
Load Diff
+5
-1
@@ -21,7 +21,11 @@ internal enum class TextTransform {
|
||||
|
||||
internal companion object {
|
||||
@JvmStatic
|
||||
fun apply(text: String, textTransform: TextTransform?): String =
|
||||
fun apply(text: String?, textTransform: TextTransform?): String? =
|
||||
text?.applyTextTransform(textTransform)
|
||||
|
||||
@JvmStatic
|
||||
fun applyNonNull(text: String, textTransform: TextTransform?): String =
|
||||
text.applyTextTransform(textTransform)
|
||||
}
|
||||
}
|
||||
|
||||
+9
-9
@@ -43,7 +43,7 @@ internal class FrescoBasedReactTextInlineImageShadowNode(
|
||||
private var tintColor = 0
|
||||
|
||||
@ReactProp(name = "src")
|
||||
fun setSource(sources: ReadableArray?) {
|
||||
public fun setSource(sources: ReadableArray?) {
|
||||
val source =
|
||||
if (sources == null || sources.size() == 0 || sources.getType(0) != ReadableType.Map) null
|
||||
else checkNotNull(sources.getMap(0)).getString("uri")
|
||||
@@ -69,12 +69,12 @@ internal class FrescoBasedReactTextInlineImageShadowNode(
|
||||
}
|
||||
|
||||
@ReactProp(name = "headers")
|
||||
fun setHeaders(newHeaders: ReadableMap?) {
|
||||
public fun setHeaders(newHeaders: ReadableMap?) {
|
||||
headers = newHeaders
|
||||
}
|
||||
|
||||
@ReactProp(name = "tintColor", customType = "Color")
|
||||
fun setTintColor(newTintColor: Int) {
|
||||
public fun setTintColor(newTintColor: Int) {
|
||||
tintColor = newTintColor
|
||||
}
|
||||
|
||||
@@ -98,13 +98,13 @@ internal class FrescoBasedReactTextInlineImageShadowNode(
|
||||
}
|
||||
|
||||
@ReactProp(name = ViewProps.RESIZE_MODE)
|
||||
fun setResizeMode(newResizeMode: String?) {
|
||||
public fun setResizeMode(newResizeMode: String?) {
|
||||
resizeMode = newResizeMode
|
||||
}
|
||||
|
||||
fun getUri(): Uri? = uri
|
||||
public fun getUri(): Uri? = uri
|
||||
|
||||
fun getHeaders(): ReadableMap? = headers
|
||||
public fun getHeaders(): ReadableMap? = headers
|
||||
|
||||
override fun isVirtual(): Boolean = true
|
||||
|
||||
@@ -124,13 +124,13 @@ internal class FrescoBasedReactTextInlineImageShadowNode(
|
||||
resizeMode)
|
||||
}
|
||||
|
||||
fun getDraweeControllerBuilder() = draweeControllerBuilder
|
||||
public fun getDraweeControllerBuilder() = draweeControllerBuilder
|
||||
|
||||
fun getCallerContext(): Any? = callerContext
|
||||
public fun getCallerContext(): Any? = callerContext
|
||||
|
||||
// TODO: t9053573 is tracking that this code should be shared
|
||||
companion object {
|
||||
fun getResourceDrawableUri(context: Context, name: String?): Uri? {
|
||||
public fun getResourceDrawableUri(context: Context, name: String?): Uri? {
|
||||
if (name == null || name.isEmpty()) {
|
||||
return null
|
||||
}
|
||||
|
||||
+7
-7
@@ -73,23 +73,23 @@ internal class FrescoBasedReactTextInlineImageSpan(
|
||||
* The ReactTextView that holds this ImageSpan is responsible for passing these methods on so that
|
||||
* we can do proper lifetime management for Fresco
|
||||
*/
|
||||
override fun onDetachedFromWindow() {
|
||||
public override fun onDetachedFromWindow() {
|
||||
draweeHolder.onDetach()
|
||||
}
|
||||
|
||||
override fun onStartTemporaryDetach() {
|
||||
public override fun onStartTemporaryDetach() {
|
||||
draweeHolder.onDetach()
|
||||
}
|
||||
|
||||
override fun onAttachedToWindow() {
|
||||
public override fun onAttachedToWindow() {
|
||||
draweeHolder.onAttach()
|
||||
}
|
||||
|
||||
override fun onFinishTemporaryDetach() {
|
||||
public override fun onFinishTemporaryDetach() {
|
||||
draweeHolder.onAttach()
|
||||
}
|
||||
|
||||
override fun getSize(
|
||||
public override fun getSize(
|
||||
paint: Paint,
|
||||
text: CharSequence,
|
||||
start: Int,
|
||||
@@ -110,11 +110,11 @@ internal class FrescoBasedReactTextInlineImageSpan(
|
||||
return _width
|
||||
}
|
||||
|
||||
override fun setTextView(textView: TextView?) {
|
||||
public override fun setTextView(textView: TextView?) {
|
||||
this.textView = textView
|
||||
}
|
||||
|
||||
override fun draw(
|
||||
public override fun draw(
|
||||
canvas: Canvas,
|
||||
text: CharSequence,
|
||||
start: Int,
|
||||
|
||||
+2
-1
@@ -16,7 +16,8 @@ import android.text.style.MetricAffectingSpan
|
||||
* The letter spacing is specified in pixels, which are converted to ems at paint time; this span
|
||||
* must therefore be applied after any spans affecting font size.
|
||||
*/
|
||||
internal class CustomLetterSpacingSpan(val spacing: Float) : MetricAffectingSpan(), ReactSpan {
|
||||
internal class CustomLetterSpacingSpan(public val spacing: Float) :
|
||||
MetricAffectingSpan(), ReactSpan {
|
||||
override fun updateDrawState(paint: TextPaint) {
|
||||
apply(paint)
|
||||
}
|
||||
|
||||
+3
-1
@@ -71,6 +71,8 @@ import com.facebook.react.views.text.ReactTextViewManagerCallback
|
||||
import com.facebook.react.views.text.ReactTypefaceUtils.parseFontVariant
|
||||
import com.facebook.react.views.text.TextAttributeProps
|
||||
import com.facebook.react.views.text.TextLayoutManager
|
||||
import com.facebook.react.views.text.TextTransform
|
||||
import com.facebook.react.views.text.TextTransform.Companion.apply
|
||||
import com.facebook.react.views.text.internal.span.TextInlineImageSpan.Companion.possiblyUpdateInlineImageSpans
|
||||
import java.util.LinkedList
|
||||
|
||||
@@ -180,7 +182,7 @@ public open class ReactTextInputManager public constructor() :
|
||||
|
||||
private fun getReactTextUpdate(text: String?, mostRecentEventCount: Int): ReactTextUpdate {
|
||||
val sb = SpannableStringBuilder()
|
||||
sb.append(text)
|
||||
sb.append(apply(text, TextTransform.UNSET))
|
||||
return ReactTextUpdate(
|
||||
sb, mostRecentEventCount, false, 0f, 0f, 0f, 0f, Gravity.NO_GRAVITY, 0, 0)
|
||||
}
|
||||
|
||||
+2
-2
@@ -50,9 +50,9 @@ import org.mockito.stubbing.Answer
|
||||
import org.robolectric.RobolectricTestRunner
|
||||
import org.robolectric.Shadows.shadowOf
|
||||
|
||||
object MockCompat {
|
||||
public object MockCompat {
|
||||
// Same as Mockito's 'eq()', but works for non-nullable types
|
||||
fun <T : Any> eq(value: T): T = ArgumentMatchers.eq(value) ?: value
|
||||
public fun <T : Any> eq(value: T): T = ArgumentMatchers.eq(value) ?: value
|
||||
|
||||
// Same as Mockito's 'any()', but works for non-nullable types
|
||||
fun <T> any(): T {
|
||||
|
||||
@@ -16,6 +16,8 @@ else
|
||||
source[:tag] = "v#{version}"
|
||||
end
|
||||
|
||||
using_hermes = ENV['USE_HERMES'] == nil || ENV['USE_HERMES'] == "1"
|
||||
|
||||
Pod::Spec.new do |s|
|
||||
s.name = "ReactCommon"
|
||||
s.module_name = "ReactCommon"
|
||||
@@ -46,7 +48,7 @@ Pod::Spec.new do |s|
|
||||
ss.dependency "React-cxxreact", version
|
||||
ss.dependency "React-jsi", version
|
||||
ss.dependency "React-logger", version
|
||||
if use_hermes()
|
||||
if using_hermes
|
||||
ss.dependency "hermes-engine"
|
||||
end
|
||||
|
||||
@@ -56,7 +58,7 @@ Pod::Spec.new do |s|
|
||||
sss.exclude_files = "react/bridging/tests"
|
||||
sss.header_dir = "react/bridging"
|
||||
sss.pod_target_xcconfig = { "HEADER_SEARCH_PATHS" => "\"$(PODS_TARGET_SRCROOT)/ReactCommon\"" }
|
||||
if use_hermes()
|
||||
if using_hermes
|
||||
sss.dependency "hermes-engine"
|
||||
end
|
||||
end
|
||||
|
||||
@@ -48,7 +48,7 @@ Pod::Spec.new do |s|
|
||||
|
||||
s.resource_bundles = {'React-cxxreact_privacy' => 'PrivacyInfo.xcprivacy'}
|
||||
|
||||
if use_hermes()
|
||||
if ENV['USE_HERMES'] == nil || ENV['USE_HERMES'] == "1"
|
||||
s.dependency 'hermes-engine'
|
||||
end
|
||||
|
||||
|
||||
@@ -44,7 +44,7 @@ Pod::Spec.new do |s|
|
||||
add_dependency(s, "React-featureflags")
|
||||
add_dependency(s, "React-debug")
|
||||
|
||||
if use_hermes()
|
||||
if ENV['USE_HERMES'] == nil || ENV['USE_HERMES'] == "1"
|
||||
s.dependency 'hermes-engine'
|
||||
end
|
||||
|
||||
|
||||
@@ -5,6 +5,10 @@
|
||||
|
||||
require "json"
|
||||
|
||||
js_engine = ENV['USE_HERMES'] == "0" ?
|
||||
:jsc :
|
||||
:hermes
|
||||
|
||||
package = JSON.parse(File.read(File.join(__dir__, "..", "..", "package.json")))
|
||||
version = package['version']
|
||||
|
||||
@@ -38,7 +42,7 @@ Pod::Spec.new do |s|
|
||||
"jsi/jsilib-windows.cpp",
|
||||
"**/test/*"
|
||||
]
|
||||
if use_hermes()
|
||||
if js_engine == :hermes
|
||||
# JSI is a part of hermes-engine. Including them also in react-native will violate the One Definition Rulle.
|
||||
files_to_exclude += [ "jsi/jsi.cpp" ]
|
||||
s.dependency "hermes-engine"
|
||||
|
||||
@@ -36,7 +36,7 @@ Pod::Spec.new do |s|
|
||||
add_dependency(s, "React-jsinspector", :framework_name => 'jsinspector_modern')
|
||||
add_dependency(s, "React-jsinspectorcdp", :framework_name => 'jsinspector_moderncdp')
|
||||
add_dependency(s, "React-jsinspectortracing", :framework_name => 'jsinspector_moderntracing')
|
||||
if use_hermes()
|
||||
if ENV['USE_HERMES'] == nil || ENV['USE_HERMES'] == "1"
|
||||
s.dependency 'hermes-engine'
|
||||
end
|
||||
|
||||
|
||||
@@ -55,7 +55,7 @@ Pod::Spec.new do |s|
|
||||
add_dependency(s, "React-jsinspectornetwork", :framework_name => 'jsinspector_modernnetwork')
|
||||
add_dependency(s, "React-jsinspectortracing", :framework_name => 'jsinspector_moderntracing')
|
||||
s.dependency "React-perflogger", version
|
||||
if use_hermes()
|
||||
if ENV["USE_HERMES"] == nil || ENV["USE_HERMES"] == "1"
|
||||
s.dependency "hermes-engine"
|
||||
end
|
||||
|
||||
|
||||
+36
-37
@@ -16,7 +16,6 @@
|
||||
#include <jsinspector-modern/InspectorInterfaces.h>
|
||||
#include <jsinspector-modern/InspectorPackagerConnection.h>
|
||||
|
||||
#include <format>
|
||||
#include <memory>
|
||||
|
||||
#include "FollyDynamicMatchers.h"
|
||||
@@ -26,7 +25,7 @@
|
||||
using namespace ::testing;
|
||||
using namespace std::literals::chrono_literals;
|
||||
using namespace std::literals::string_literals;
|
||||
using folly::dynamic, folly::toJson;
|
||||
using folly::dynamic, folly::toJson, folly::sformat;
|
||||
|
||||
namespace facebook::react::jsinspector_modern {
|
||||
|
||||
@@ -282,7 +281,7 @@ TEST_F(InspectorPackagerConnectionTest, TestSendReceiveEvents) {
|
||||
.lazily_make_unique<std::unique_ptr<IRemoteConnection>>());
|
||||
|
||||
// Connect to the page.
|
||||
webSockets_[0]->getDelegate().didReceiveMessage(std::format(
|
||||
webSockets_[0]->getDelegate().didReceiveMessage(sformat(
|
||||
R"({{
|
||||
"event": "connect",
|
||||
"payload": {{
|
||||
@@ -322,7 +321,7 @@ TEST_F(InspectorPackagerConnectionTest, TestSendReceiveEvents) {
|
||||
AtJsonPtr("/params", ElementsAre("arg1", "arg2"))))))
|
||||
.RetiresOnSaturation();
|
||||
|
||||
webSockets_[0]->getDelegate().didReceiveMessage(std::format(
|
||||
webSockets_[0]->getDelegate().didReceiveMessage(sformat(
|
||||
R"({{
|
||||
"event": "wrappedEvent",
|
||||
"payload": {{
|
||||
@@ -374,7 +373,7 @@ TEST_F(InspectorPackagerConnectionTest, TestSendReceiveEventsToMultiplePages) {
|
||||
|
||||
for (int i = 0; i < kNumPages; ++i) {
|
||||
// Connect to the i-th page.
|
||||
webSockets_[0]->getDelegate().didReceiveMessage(std::format(
|
||||
webSockets_[0]->getDelegate().didReceiveMessage(sformat(
|
||||
R"({{
|
||||
"event": "connect",
|
||||
"payload": {{
|
||||
@@ -416,7 +415,7 @@ TEST_F(InspectorPackagerConnectionTest, TestSendReceiveEventsToMultiplePages) {
|
||||
*localConnections_[i],
|
||||
sendMessage(JsonParsed(AtJsonPtr("/method", Eq(method)))))
|
||||
.RetiresOnSaturation();
|
||||
webSockets_[0]->getDelegate().didReceiveMessage(std::format(
|
||||
webSockets_[0]->getDelegate().didReceiveMessage(sformat(
|
||||
R"({{
|
||||
"event": "wrappedEvent",
|
||||
"payload": {{
|
||||
@@ -446,7 +445,7 @@ TEST_F(InspectorPackagerConnectionTest, TestSendEventToAllConnections) {
|
||||
.lazily_make_unique<std::unique_ptr<IRemoteConnection>>());
|
||||
|
||||
// Connect to the page.
|
||||
webSockets_[0]->getDelegate().didReceiveMessage(std::format(
|
||||
webSockets_[0]->getDelegate().didReceiveMessage(sformat(
|
||||
R"({{
|
||||
"event": "connect",
|
||||
"payload": {{
|
||||
@@ -487,7 +486,7 @@ TEST_F(InspectorPackagerConnectionTest, TestConnectThenDisconnect) {
|
||||
.lazily_make_unique<std::unique_ptr<IRemoteConnection>>());
|
||||
|
||||
// Connect to the page.
|
||||
webSockets_[0]->getDelegate().didReceiveMessage(std::format(
|
||||
webSockets_[0]->getDelegate().didReceiveMessage(sformat(
|
||||
R"({{
|
||||
"event": "connect",
|
||||
"payload": {{
|
||||
@@ -499,7 +498,7 @@ TEST_F(InspectorPackagerConnectionTest, TestConnectThenDisconnect) {
|
||||
|
||||
// Disconnect from the page.
|
||||
EXPECT_CALL(*localConnections_[0], disconnect()).RetiresOnSaturation();
|
||||
webSockets_[0]->getDelegate().didReceiveMessage(std::format(
|
||||
webSockets_[0]->getDelegate().didReceiveMessage(sformat(
|
||||
R"({{
|
||||
"event": "disconnect",
|
||||
"payload": {{
|
||||
@@ -522,7 +521,7 @@ TEST_F(InspectorPackagerConnectionTest, TestConnectThenCloseSocket) {
|
||||
.lazily_make_unique<std::unique_ptr<IRemoteConnection>>());
|
||||
|
||||
// Connect to the page.
|
||||
webSockets_[0]->getDelegate().didReceiveMessage(std::format(
|
||||
webSockets_[0]->getDelegate().didReceiveMessage(sformat(
|
||||
R"({{
|
||||
"event": "connect",
|
||||
"payload": {{
|
||||
@@ -550,7 +549,7 @@ TEST_F(InspectorPackagerConnectionTest, TestConnectThenSocketFailure) {
|
||||
.lazily_make_unique<std::unique_ptr<IRemoteConnection>>());
|
||||
|
||||
// Connect to the page.
|
||||
webSockets_[0]->getDelegate().didReceiveMessage(std::format(
|
||||
webSockets_[0]->getDelegate().didReceiveMessage(sformat(
|
||||
R"({{
|
||||
"event": "connect",
|
||||
"payload": {{
|
||||
@@ -580,7 +579,7 @@ TEST_F(
|
||||
.lazily_make_unique<std::unique_ptr<IRemoteConnection>>());
|
||||
|
||||
// Connect to the page.
|
||||
webSockets_[0]->getDelegate().didReceiveMessage(std::format(
|
||||
webSockets_[0]->getDelegate().didReceiveMessage(sformat(
|
||||
R"({{
|
||||
"event": "connect",
|
||||
"payload": {{
|
||||
@@ -626,7 +625,7 @@ TEST_F(
|
||||
.lazily_make_unique<std::unique_ptr<IRemoteConnection>>());
|
||||
|
||||
// Connect to the page.
|
||||
webSockets_[0]->getDelegate().didReceiveMessage(std::format(
|
||||
webSockets_[0]->getDelegate().didReceiveMessage(sformat(
|
||||
R"({{
|
||||
"event": "connect",
|
||||
"payload": {{
|
||||
@@ -638,7 +637,7 @@ TEST_F(
|
||||
|
||||
// Try connecting to the same page again. This results in a disconnection.
|
||||
EXPECT_CALL(*localConnections_[0], disconnect()).RetiresOnSaturation();
|
||||
webSockets_[0]->getDelegate().didReceiveMessage(std::format(
|
||||
webSockets_[0]->getDelegate().didReceiveMessage(sformat(
|
||||
R"({{
|
||||
"event": "connect",
|
||||
"payload": {{
|
||||
@@ -661,7 +660,7 @@ TEST_F(InspectorPackagerConnectionTest, TestMultipleDisconnect) {
|
||||
.lazily_make_unique<std::unique_ptr<IRemoteConnection>>());
|
||||
|
||||
// Connect to the page.
|
||||
webSockets_[0]->getDelegate().didReceiveMessage(std::format(
|
||||
webSockets_[0]->getDelegate().didReceiveMessage(sformat(
|
||||
R"({{
|
||||
"event": "connect",
|
||||
"payload": {{
|
||||
@@ -673,7 +672,7 @@ TEST_F(InspectorPackagerConnectionTest, TestMultipleDisconnect) {
|
||||
|
||||
// Disconnect from the page.
|
||||
EXPECT_CALL(*localConnections_[0], disconnect()).RetiresOnSaturation();
|
||||
webSockets_[0]->getDelegate().didReceiveMessage(std::format(
|
||||
webSockets_[0]->getDelegate().didReceiveMessage(sformat(
|
||||
R"({{
|
||||
"event": "disconnect",
|
||||
"payload": {{
|
||||
@@ -684,7 +683,7 @@ TEST_F(InspectorPackagerConnectionTest, TestMultipleDisconnect) {
|
||||
EXPECT_FALSE(localConnections_[0]);
|
||||
|
||||
// Disconnect again. This is a noop.
|
||||
webSockets_[0]->getDelegate().didReceiveMessage(std::format(
|
||||
webSockets_[0]->getDelegate().didReceiveMessage(sformat(
|
||||
R"({{
|
||||
"event": "disconnect",
|
||||
"payload": {{
|
||||
@@ -707,7 +706,7 @@ TEST_F(InspectorPackagerConnectionTest, TestDisconnectThenSendEvent) {
|
||||
.lazily_make_unique<std::unique_ptr<IRemoteConnection>>());
|
||||
|
||||
// Connect to the page.
|
||||
webSockets_[0]->getDelegate().didReceiveMessage(std::format(
|
||||
webSockets_[0]->getDelegate().didReceiveMessage(sformat(
|
||||
R"({{
|
||||
"event": "connect",
|
||||
"payload": {{
|
||||
@@ -719,7 +718,7 @@ TEST_F(InspectorPackagerConnectionTest, TestDisconnectThenSendEvent) {
|
||||
|
||||
// Disconnect from the page.
|
||||
EXPECT_CALL(*localConnections_[0], disconnect()).RetiresOnSaturation();
|
||||
webSockets_[0]->getDelegate().didReceiveMessage(std::format(
|
||||
webSockets_[0]->getDelegate().didReceiveMessage(sformat(
|
||||
R"({{
|
||||
"event": "disconnect",
|
||||
"payload": {{
|
||||
@@ -731,7 +730,7 @@ TEST_F(InspectorPackagerConnectionTest, TestDisconnectThenSendEvent) {
|
||||
|
||||
// Send an event from the frontend (remote) to the backend (local). This
|
||||
// is a noop.
|
||||
webSockets_[0]->getDelegate().didReceiveMessage(std::format(
|
||||
webSockets_[0]->getDelegate().didReceiveMessage(sformat(
|
||||
R"({{
|
||||
"event": "wrappedEvent",
|
||||
"payload": {{
|
||||
@@ -755,7 +754,7 @@ TEST_F(InspectorPackagerConnectionTest, TestSendEventToUnknownPage) {
|
||||
|
||||
// Send an event from the frontend (remote) to the backend (local). This
|
||||
// is a noop (except for logging).
|
||||
webSockets_[0]->getDelegate().didReceiveMessage(std::format(
|
||||
webSockets_[0]->getDelegate().didReceiveMessage(sformat(
|
||||
R"({{
|
||||
"event": "wrappedEvent",
|
||||
"payload": {{
|
||||
@@ -922,7 +921,7 @@ TEST_F(
|
||||
.lazily_make_unique<std::unique_ptr<IRemoteConnection>>());
|
||||
|
||||
// Connect to the page.
|
||||
retainedWebSocketDelegate->didReceiveMessage(std::format(
|
||||
retainedWebSocketDelegate->didReceiveMessage(sformat(
|
||||
R"({{
|
||||
"event": "connect",
|
||||
"payload": {{
|
||||
@@ -942,7 +941,7 @@ TEST_F(
|
||||
AtJsonPtr("/params", ElementsAre("arg1", "arg2"))))))
|
||||
.RetiresOnSaturation();
|
||||
|
||||
retainedWebSocketDelegate->didReceiveMessage(std::format(
|
||||
retainedWebSocketDelegate->didReceiveMessage(sformat(
|
||||
R"({{
|
||||
"event": "wrappedEvent",
|
||||
"payload": {{
|
||||
@@ -976,7 +975,7 @@ TEST_F(InspectorPackagerConnectionTest, TestDestroyConnectionOnPageRemoved) {
|
||||
.lazily_make_unique<std::unique_ptr<IRemoteConnection>>());
|
||||
|
||||
// Connect to the page.
|
||||
webSockets_[0]->getDelegate().didReceiveMessage(std::format(
|
||||
webSockets_[0]->getDelegate().didReceiveMessage(sformat(
|
||||
R"({{
|
||||
"event": "connect",
|
||||
"payload": {{
|
||||
@@ -1006,7 +1005,7 @@ TEST_F(
|
||||
.lazily_make_unique<std::unique_ptr<IRemoteConnection>>());
|
||||
|
||||
// Connect to the page.
|
||||
webSockets_[0]->getDelegate().didReceiveMessage(std::format(
|
||||
webSockets_[0]->getDelegate().didReceiveMessage(sformat(
|
||||
R"({{
|
||||
"event": "connect",
|
||||
"payload": {{
|
||||
@@ -1046,7 +1045,7 @@ TEST_F(
|
||||
.lazily_make_unique<std::unique_ptr<IRemoteConnection>>());
|
||||
|
||||
// Connect to the page.
|
||||
webSockets_[0]->getDelegate().didReceiveMessage(std::format(
|
||||
webSockets_[0]->getDelegate().didReceiveMessage(sformat(
|
||||
R"({{
|
||||
"event": "connect",
|
||||
"payload": {{
|
||||
@@ -1065,7 +1064,7 @@ TEST_F(
|
||||
|
||||
// Disconnect from the page.
|
||||
EXPECT_CALL(*localConnections_[0], disconnect()).RetiresOnSaturation();
|
||||
webSockets_[0]->getDelegate().didReceiveMessage(std::format(
|
||||
webSockets_[0]->getDelegate().didReceiveMessage(sformat(
|
||||
R"({{
|
||||
"event": "disconnect",
|
||||
"payload": {{
|
||||
@@ -1076,7 +1075,7 @@ TEST_F(
|
||||
EXPECT_FALSE(localConnections_[0]);
|
||||
|
||||
// Connect to the same page again.
|
||||
webSockets_[0]->getDelegate().didReceiveMessage(std::format(
|
||||
webSockets_[0]->getDelegate().didReceiveMessage(sformat(
|
||||
R"({{
|
||||
"event": "connect",
|
||||
"payload": {{
|
||||
@@ -1128,7 +1127,7 @@ TEST_F(
|
||||
.lazily_make_unique<std::unique_ptr<IRemoteConnection>>());
|
||||
|
||||
// Connect to the page.
|
||||
webSockets_[0]->getDelegate().didReceiveMessage(std::format(
|
||||
webSockets_[0]->getDelegate().didReceiveMessage(sformat(
|
||||
R"({{
|
||||
"event": "connect",
|
||||
"payload": {{
|
||||
@@ -1152,7 +1151,7 @@ TEST_F(
|
||||
|
||||
// Disconnect from the page.
|
||||
EXPECT_CALL(*localConnections_[0], disconnect()).RetiresOnSaturation();
|
||||
webSockets_[0]->getDelegate().didReceiveMessage(std::format(
|
||||
webSockets_[0]->getDelegate().didReceiveMessage(sformat(
|
||||
R"({{
|
||||
"event": "disconnect",
|
||||
"payload": {{
|
||||
@@ -1163,7 +1162,7 @@ TEST_F(
|
||||
EXPECT_FALSE(localConnections_[0]);
|
||||
|
||||
// Connect to the same page again.
|
||||
webSockets_[0]->getDelegate().didReceiveMessage(std::format(
|
||||
webSockets_[0]->getDelegate().didReceiveMessage(sformat(
|
||||
R"({{
|
||||
"event": "connect",
|
||||
"payload": {{
|
||||
@@ -1257,7 +1256,7 @@ TEST_F(InspectorPackagerConnectionTest, TestRejectedPageConnection) {
|
||||
AtJsonPtr("/payload/pageId", Eq(std::to_string(pageId)))))))
|
||||
.RetiresOnSaturation();
|
||||
|
||||
webSockets_[0]->getDelegate().didReceiveMessage(std::format(
|
||||
webSockets_[0]->getDelegate().didReceiveMessage(sformat(
|
||||
R"({{
|
||||
"event": "connect",
|
||||
"payload": {{
|
||||
@@ -1266,7 +1265,7 @@ TEST_F(InspectorPackagerConnectionTest, TestRejectedPageConnection) {
|
||||
}})",
|
||||
toJson(std::to_string(pageId))));
|
||||
|
||||
webSockets_[0]->getDelegate().didReceiveMessage(std::format(
|
||||
webSockets_[0]->getDelegate().didReceiveMessage(sformat(
|
||||
R"({{
|
||||
"event": "wrappedEvent",
|
||||
"payload": {{
|
||||
@@ -1292,7 +1291,7 @@ TEST_F(InspectorPackagerConnectionTest, TestRejectedPageConnection) {
|
||||
AtJsonPtr("/payload/pageId", Eq(std::to_string(pageId)))))))
|
||||
.RetiresOnSaturation();
|
||||
|
||||
webSockets_[0]->getDelegate().didReceiveMessage(std::format(
|
||||
webSockets_[0]->getDelegate().didReceiveMessage(sformat(
|
||||
R"({{
|
||||
"event": "connect",
|
||||
"payload": {{
|
||||
@@ -1301,7 +1300,7 @@ TEST_F(InspectorPackagerConnectionTest, TestRejectedPageConnection) {
|
||||
}})",
|
||||
toJson(std::to_string(pageId))));
|
||||
|
||||
webSockets_[0]->getDelegate().didReceiveMessage(std::format(
|
||||
webSockets_[0]->getDelegate().didReceiveMessage(sformat(
|
||||
R"({{
|
||||
"event": "wrappedEvent",
|
||||
"payload": {{
|
||||
@@ -1320,7 +1319,7 @@ TEST_F(InspectorPackagerConnectionTest, TestRejectedPageConnection) {
|
||||
// page.
|
||||
mockNextConnectionBehavior = Accept;
|
||||
|
||||
webSockets_[0]->getDelegate().didReceiveMessage(std::format(
|
||||
webSockets_[0]->getDelegate().didReceiveMessage(sformat(
|
||||
R"({{
|
||||
"event": "connect",
|
||||
"payload": {{
|
||||
@@ -1337,7 +1336,7 @@ TEST_F(InspectorPackagerConnectionTest, TestRejectedPageConnection) {
|
||||
AtJsonPtr("/params", ElementsAre("arg1", "arg2"))))))
|
||||
.RetiresOnSaturation();
|
||||
|
||||
webSockets_[0]->getDelegate().didReceiveMessage(std::format(
|
||||
webSockets_[0]->getDelegate().didReceiveMessage(sformat(
|
||||
R"({{
|
||||
"event": "wrappedEvent",
|
||||
"payload": {{
|
||||
|
||||
@@ -8,13 +8,13 @@
|
||||
#include <folly/Format.h>
|
||||
#include <folly/executors/ManualExecutor.h>
|
||||
#include <folly/executors/QueuedImmediateExecutor.h>
|
||||
#include <format>
|
||||
|
||||
#include "JsiIntegrationTest.h"
|
||||
#include "engines/JsiIntegrationTestGenericEngineAdapter.h"
|
||||
#include "engines/JsiIntegrationTestHermesEngineAdapter.h"
|
||||
|
||||
using namespace ::testing;
|
||||
using folly::sformat;
|
||||
|
||||
namespace facebook::react::jsinspector_modern {
|
||||
|
||||
@@ -486,7 +486,7 @@ TYPED_TEST(JsiIntegrationHermesTest, EvaluateExpressionInExecutionContext) {
|
||||
}
|
||||
}
|
||||
})"));
|
||||
this->toPage_->sendMessage(std::format(
|
||||
this->toPage_->sendMessage(sformat(
|
||||
R"({{
|
||||
"id": 1,
|
||||
"method": "Runtime.evaluate",
|
||||
@@ -508,7 +508,7 @@ TYPED_TEST(JsiIntegrationHermesTest, EvaluateExpressionInExecutionContext) {
|
||||
// Now the old execution context is stale.
|
||||
this->expectMessageFromPage(
|
||||
JsonParsed(AllOf(AtJsonPtr("/id", 3), AtJsonPtr("/error/code", -32600))));
|
||||
this->toPage_->sendMessage(std::format(
|
||||
this->toPage_->sendMessage(sformat(
|
||||
R"({{
|
||||
"id": 3,
|
||||
"method": "Runtime.evaluate",
|
||||
@@ -731,7 +731,7 @@ TYPED_TEST(JsiIntegrationHermesTest, ReleaseRemoteObject) {
|
||||
// Ensure we can get the properties of the object.
|
||||
this->expectMessageFromPage(JsonParsed(
|
||||
AllOf(AtJsonPtr("/id", 2), AtJsonPtr("/result/result", SizeIs(Gt(0))))));
|
||||
this->toPage_->sendMessage(std::format(
|
||||
this->toPage_->sendMessage(sformat(
|
||||
R"({{
|
||||
"id": 2,
|
||||
"method": "Runtime.getProperties",
|
||||
@@ -744,7 +744,7 @@ TYPED_TEST(JsiIntegrationHermesTest, ReleaseRemoteObject) {
|
||||
"id": 3,
|
||||
"result": {}
|
||||
})"));
|
||||
this->toPage_->sendMessage(std::format(
|
||||
this->toPage_->sendMessage(sformat(
|
||||
R"({{
|
||||
"id": 3,
|
||||
"method": "Runtime.releaseObject",
|
||||
@@ -755,7 +755,7 @@ TYPED_TEST(JsiIntegrationHermesTest, ReleaseRemoteObject) {
|
||||
// Getting properties for a released object results in an error.
|
||||
this->expectMessageFromPage(
|
||||
JsonParsed(AllOf(AtJsonPtr("/id", 4), AtJsonPtr("/error/code", -32000))));
|
||||
this->toPage_->sendMessage(std::format(
|
||||
this->toPage_->sendMessage(sformat(
|
||||
R"({{
|
||||
"id": 4,
|
||||
"method": "Runtime.getProperties",
|
||||
@@ -766,7 +766,7 @@ TYPED_TEST(JsiIntegrationHermesTest, ReleaseRemoteObject) {
|
||||
// Releasing an already released object is an error.
|
||||
this->expectMessageFromPage(
|
||||
JsonParsed(AllOf(AtJsonPtr("/id", 5), AtJsonPtr("/error/code", -32000))));
|
||||
this->toPage_->sendMessage(std::format(
|
||||
this->toPage_->sendMessage(sformat(
|
||||
R"({{
|
||||
"id": 5,
|
||||
"method": "Runtime.releaseObject",
|
||||
@@ -797,7 +797,7 @@ TYPED_TEST(JsiIntegrationHermesTest, ReleaseRemoteObjectGroup) {
|
||||
// Ensure we can get the properties of the object.
|
||||
this->expectMessageFromPage(JsonParsed(
|
||||
AllOf(AtJsonPtr("/id", 2), AtJsonPtr("/result/result", SizeIs(Gt(0))))));
|
||||
this->toPage_->sendMessage(std::format(
|
||||
this->toPage_->sendMessage(sformat(
|
||||
R"({{
|
||||
"id": 2,
|
||||
"method": "Runtime.getProperties",
|
||||
@@ -819,7 +819,7 @@ TYPED_TEST(JsiIntegrationHermesTest, ReleaseRemoteObjectGroup) {
|
||||
// Getting properties for a released object results in an error.
|
||||
this->expectMessageFromPage(
|
||||
JsonParsed(AllOf(AtJsonPtr("/id", 4), AtJsonPtr("/error/code", -32000))));
|
||||
this->toPage_->sendMessage(std::format(
|
||||
this->toPage_->sendMessage(sformat(
|
||||
R"({{
|
||||
"id": 4,
|
||||
"method": "Runtime.getProperties",
|
||||
|
||||
+6
-3
@@ -62,12 +62,15 @@ Pod::Spec.new do |s|
|
||||
add_dependency(s, "React-RCTFBReactNativeSpec")
|
||||
add_dependency(s, "React-utils", :additional_framework_paths => ["react/utils/platform/ios"])
|
||||
|
||||
if use_third_party_jsc()
|
||||
s.exclude_files = ["ReactCommon/RCTHermesInstance.{mm,h}", "ReactCommon/RCTJscInstance.{mm,h}"]
|
||||
else
|
||||
if ENV["USE_HERMES"] == nil || ENV["USE_HERMES"] == "1"
|
||||
s.dependency "hermes-engine"
|
||||
add_dependency(s, "React-RuntimeHermes")
|
||||
s.exclude_files = "ReactCommon/RCTJscInstance.{mm,h}"
|
||||
elsif ENV['USE_THIRD_PARTY_JSC'] == '1'
|
||||
s.exclude_files = ["ReactCommon/RCTHermesInstance.{mm,h}", "ReactCommon/RCTJscInstance.{mm,h}"]
|
||||
else
|
||||
s.dependency "React-jsc"
|
||||
s.exclude_files = "ReactCommon/RCTHermesInstance.{mm,h}"
|
||||
end
|
||||
|
||||
add_rn_third_party_dependencies(s)
|
||||
|
||||
@@ -44,7 +44,4 @@ Pod::Spec.new do |s|
|
||||
"DEFINES_MODULE" => "YES" }
|
||||
|
||||
s.dependency "React-jsi", version
|
||||
s.dependency "React-featureflags", version
|
||||
add_dependency(s, "React-debug")
|
||||
add_dependency(s, "React-utils", :additional_framework_paths => ["react/utils/platform/ios"])
|
||||
end
|
||||
|
||||
+1
-1
@@ -24,7 +24,7 @@ void executeSynchronouslyOnSameThread_CAN_DEADLOCK(
|
||||
template <typename DataT>
|
||||
inline static DataT executeSynchronouslyOnSameThread_CAN_DEADLOCK(
|
||||
const RuntimeExecutor& runtimeExecutor,
|
||||
std::function<DataT(jsi::Runtime&)>&& runtimeWork) {
|
||||
std::function<DataT(jsi::Runtime& runtime)>&& runtimeWork) {
|
||||
DataT data;
|
||||
|
||||
executeSynchronouslyOnSameThread_CAN_DEADLOCK(
|
||||
|
||||
+1
-4
@@ -24,7 +24,7 @@ void executeSynchronouslyOnSameThread_CAN_DEADLOCK(
|
||||
template <typename DataT>
|
||||
inline static DataT executeSynchronouslyOnSameThread_CAN_DEADLOCK(
|
||||
const RuntimeExecutor& runtimeExecutor,
|
||||
std::function<DataT(jsi::Runtime&)>&& runtimeWork) {
|
||||
std::function<DataT(jsi::Runtime& runtime)>&& runtimeWork) {
|
||||
DataT data;
|
||||
|
||||
executeSynchronouslyOnSameThread_CAN_DEADLOCK(
|
||||
@@ -33,7 +33,4 @@ inline static DataT executeSynchronouslyOnSameThread_CAN_DEADLOCK(
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
void unsafeExecuteOnMainThreadSync(std::function<void()> work);
|
||||
|
||||
} // namespace facebook::react
|
||||
|
||||
+3
-202
@@ -5,160 +5,11 @@
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#import <ReactCommon/RuntimeExecutorSyncUIThreadUtils.h>
|
||||
#import <react/debug/react_native_assert.h>
|
||||
#import <react/featureflags/ReactNativeFeatureFlags.h>
|
||||
#import <react/utils/OnScopeExit.h>
|
||||
#import <algorithm>
|
||||
#import <functional>
|
||||
#import <future>
|
||||
#import <mutex>
|
||||
#import <optional>
|
||||
#import <thread>
|
||||
#include <future>
|
||||
#include <thread>
|
||||
|
||||
namespace facebook::react {
|
||||
|
||||
namespace {
|
||||
class UITask {
|
||||
std::promise<void> _isDone;
|
||||
std::function<void()> _uiWork;
|
||||
|
||||
public:
|
||||
UITask(UITask &&other) = default;
|
||||
UITask &operator=(UITask &&other) = default;
|
||||
UITask(const UITask &) = delete;
|
||||
UITask &operator=(const UITask &) = delete;
|
||||
~UITask() = default;
|
||||
|
||||
UITask(std::function<void()> &&uiWork) : _uiWork(std::move(uiWork)) {}
|
||||
|
||||
void operator()()
|
||||
{
|
||||
if (!_uiWork) {
|
||||
return;
|
||||
}
|
||||
OnScopeExit onScopeExit(^{
|
||||
_uiWork = nullptr;
|
||||
_isDone.set_value();
|
||||
});
|
||||
_uiWork();
|
||||
}
|
||||
|
||||
std::future<void> future()
|
||||
{
|
||||
return _isDone.get_future();
|
||||
}
|
||||
};
|
||||
|
||||
// Protects access to g_uiTask
|
||||
std::mutex &g_mutex()
|
||||
{
|
||||
static std::mutex mutex;
|
||||
return mutex;
|
||||
}
|
||||
|
||||
std::condition_variable &g_cv()
|
||||
{
|
||||
static std::condition_variable cv;
|
||||
return cv;
|
||||
}
|
||||
|
||||
std::mutex &g_ticket()
|
||||
{
|
||||
static std::mutex ticket;
|
||||
return ticket;
|
||||
}
|
||||
|
||||
std::optional<UITask> &g_uiTask()
|
||||
{
|
||||
static std::optional<UITask> uiTaskQueue;
|
||||
return uiTaskQueue;
|
||||
}
|
||||
|
||||
// Must be called holding g_mutex();
|
||||
bool hasUITask()
|
||||
{
|
||||
return g_uiTask().has_value();
|
||||
}
|
||||
|
||||
// Must be called holding g_mutex();
|
||||
UITask takeUITask()
|
||||
{
|
||||
react_native_assert(hasUITask());
|
||||
auto uiTask = std::move(*g_uiTask());
|
||||
g_uiTask() = std::nullopt;
|
||||
return uiTask;
|
||||
}
|
||||
|
||||
// Must be called holding g_mutex();
|
||||
UITask &postUITask(std::function<void()> &&uiWork)
|
||||
{
|
||||
react_native_assert(!hasUITask());
|
||||
g_uiTask() = UITask(std::move(uiWork));
|
||||
g_cv().notify_one();
|
||||
return *g_uiTask();
|
||||
}
|
||||
|
||||
bool g_isRunningUITask = false;
|
||||
void runUITask(UITask &uiTask)
|
||||
{
|
||||
react_native_assert([[NSThread currentThread] isMainThread]);
|
||||
g_isRunningUITask = true;
|
||||
OnScopeExit onScopeExit([]() { g_isRunningUITask = false; });
|
||||
uiTask();
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is resilient to multiple javascript threads.
|
||||
* This can happen when multiple react instances interleave.
|
||||
*
|
||||
* The extension from 1 js thread to n: All js threads race to
|
||||
* get a ticket to post a ui task. The first one to get the ticket
|
||||
* will post the ui task, and go to sleep. The cooridnator or
|
||||
* main queue will execute that ui task, waking up the js thread
|
||||
* and releasing that ticket. Another js thread will get the ticket.
|
||||
*
|
||||
* For simplicity, we will just use this algorithm for all bg threads.
|
||||
* Not just the js thread.
|
||||
*/
|
||||
void saferExecuteSynchronouslyOnSameThread_CAN_DEADLOCK(
|
||||
const RuntimeExecutor &runtimeExecutor,
|
||||
std::function<void(jsi::Runtime &runtime)> &&runtimeWork)
|
||||
{
|
||||
react_native_assert([[NSThread currentThread] isMainThread] && !g_isRunningUITask);
|
||||
|
||||
jsi::Runtime *runtime = nullptr;
|
||||
std::promise<void> runtimeWorkDone;
|
||||
|
||||
runtimeExecutor([&runtime, runtimeWorkDoneFuture = runtimeWorkDone.get_future().share()](jsi::Runtime &rt) {
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(g_mutex());
|
||||
runtime = &rt;
|
||||
g_cv().notify_one();
|
||||
}
|
||||
|
||||
runtimeWorkDoneFuture.wait();
|
||||
});
|
||||
|
||||
while (true) {
|
||||
std::unique_lock<std::mutex> lock(g_mutex());
|
||||
g_cv().wait(lock, [&] { return runtime != nullptr || hasUITask(); });
|
||||
if (runtime != nullptr) {
|
||||
break;
|
||||
}
|
||||
|
||||
auto uiTask = takeUITask();
|
||||
lock.unlock();
|
||||
runUITask(uiTask);
|
||||
}
|
||||
|
||||
OnScopeExit onScopeExit([&]() { runtimeWorkDone.set_value(); });
|
||||
// Calls into runtime scheduler, which takes care of error handling
|
||||
runtimeWork(*runtime);
|
||||
}
|
||||
|
||||
/*
|
||||
* Schedules `runtimeWork` to be executed on the same thread using the
|
||||
* `RuntimeExecutor`, and blocks on its completion.
|
||||
@@ -175,7 +26,7 @@ void saferExecuteSynchronouslyOnSameThread_CAN_DEADLOCK(
|
||||
* - [JS thread] Signal runtime capture block is finished:
|
||||
* resolve(runtimeCaptureBlockDone);
|
||||
*/
|
||||
void legacyExecuteSynchronouslyOnSameThread_CAN_DEADLOCK(
|
||||
void executeSynchronouslyOnSameThread_CAN_DEADLOCK(
|
||||
const RuntimeExecutor &runtimeExecutor,
|
||||
std::function<void(jsi::Runtime &)> &&runtimeWork)
|
||||
{
|
||||
@@ -207,54 +58,4 @@ void legacyExecuteSynchronouslyOnSameThread_CAN_DEADLOCK(
|
||||
runtimeCaptureBlockDone.get_future().wait();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void executeSynchronouslyOnSameThread_CAN_DEADLOCK(
|
||||
const RuntimeExecutor &runtimeExecutor,
|
||||
std::function<void(jsi::Runtime &)> &&runtimeWork)
|
||||
{
|
||||
if (ReactNativeFeatureFlags::enableMainQueueCoordinatorOnIOS()) {
|
||||
saferExecuteSynchronouslyOnSameThread_CAN_DEADLOCK(runtimeExecutor, std::move(runtimeWork));
|
||||
} else {
|
||||
legacyExecuteSynchronouslyOnSameThread_CAN_DEADLOCK(runtimeExecutor, std::move(runtimeWork));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is resilient to multiple javascript threads.
|
||||
* This can happen when multiple react instances interleave.
|
||||
*
|
||||
* The extension from 1 js thread to n: All js threads race to
|
||||
* get a ticket to post a ui task. The first one to get the ticket
|
||||
* will post the ui task, and go to sleep. The cooridnator or
|
||||
* main queue will execute that ui task, waking up the js thread
|
||||
* and releasing that ticket. Another js thread will get the ticket.
|
||||
*
|
||||
* For simplicity, we will just use this method for all bg threads.
|
||||
* Not just the js thread.
|
||||
*/
|
||||
void unsafeExecuteOnMainThreadSync(std::function<void()> work)
|
||||
{
|
||||
std::lock_guard<std::mutex> ticket(g_ticket());
|
||||
|
||||
std::future<void> isDone;
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(g_mutex());
|
||||
isDone = postUITask(std::move(work)).future();
|
||||
}
|
||||
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
std::unique_lock<std::mutex> lock(g_mutex());
|
||||
if (!hasUITask()) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto uiTask = takeUITask();
|
||||
lock.unlock();
|
||||
runUITask(uiTask);
|
||||
});
|
||||
|
||||
isDone.wait();
|
||||
}
|
||||
|
||||
} // namespace facebook::react
|
||||
|
||||
@@ -81,7 +81,6 @@
|
||||
"gradle.properties",
|
||||
"gradle/libs.versions.toml",
|
||||
"index.js",
|
||||
"index.flow.js",
|
||||
"interface.js",
|
||||
"jest-preset.js",
|
||||
"jest",
|
||||
|
||||
@@ -26,9 +26,53 @@ class JSEngineTests < Test::Unit::TestCase
|
||||
Pod::Config.reset()
|
||||
Pod::UI.reset()
|
||||
podSpy_cleanUp()
|
||||
ENV['USE_HERMES'] = '1'
|
||||
ENV['CI'] = nil
|
||||
end
|
||||
|
||||
# =============== #
|
||||
# TEST - setupJsc #
|
||||
# =============== #
|
||||
def test_setupJsc_installsPods
|
||||
# Arrange
|
||||
fabric_enabled = false
|
||||
|
||||
# Act
|
||||
setup_jsc!(:react_native_path => @react_native_path, :fabric_enabled => fabric_enabled)
|
||||
|
||||
# Assert
|
||||
assert_equal($podInvocationCount, 2)
|
||||
assert_equal($podInvocation["React-jsi"][:path], "../../ReactCommon/jsi")
|
||||
assert_equal($podInvocation["React-jsc"][:path], "../../ReactCommon/jsc")
|
||||
end
|
||||
|
||||
def test_setupJsc_installsPods_installsFabricSubspecWhenFabricEnabled
|
||||
# Arrange
|
||||
fabric_enabled = true
|
||||
|
||||
# Act
|
||||
setup_jsc!(:react_native_path => @react_native_path, :fabric_enabled => fabric_enabled)
|
||||
|
||||
# Assert
|
||||
assert_equal($podInvocationCount, 3)
|
||||
assert_equal($podInvocation["React-jsi"][:path], "../../ReactCommon/jsi")
|
||||
assert_equal($podInvocation["React-jsc"][:path], "../../ReactCommon/jsc")
|
||||
assert_equal($podInvocation["React-jsc/Fabric"][:path], "../../ReactCommon/jsc")
|
||||
end
|
||||
|
||||
def test_setupJsc_installsPodsWithThirdPartyJSC
|
||||
# Arrange
|
||||
ENV['USE_THIRD_PARTY_JSC'] = '1'
|
||||
fabric_enabled = false
|
||||
|
||||
# Act
|
||||
setup_jsc!(:react_native_path => @react_native_path, :fabric_enabled => fabric_enabled)
|
||||
|
||||
# Assert
|
||||
assert_equal($podInvocationCount, 1)
|
||||
assert_equal($podInvocation["React-jsi"][:path], "../../ReactCommon/jsi")
|
||||
end
|
||||
|
||||
# ================== #
|
||||
# TEST - setupHermes #
|
||||
# ================== #
|
||||
|
||||
@@ -34,6 +34,7 @@ class UtilsTests < Test::Unit::TestCase
|
||||
Xcodeproj::Plist.reset()
|
||||
XcodebuildMock.reset()
|
||||
ENV['RCT_NEW_ARCH_ENABLED'] = '0'
|
||||
ENV['USE_HERMES'] = '1'
|
||||
ENV['USE_FRAMEWORKS'] = nil
|
||||
system_reset_commands
|
||||
$RN_PLATFORMS = nil
|
||||
@@ -105,6 +106,21 @@ class UtilsTests < Test::Unit::TestCase
|
||||
})
|
||||
end
|
||||
|
||||
def test_getDefaultFlag_whenOldArchitectureButHermesDisabled()
|
||||
# Arrange
|
||||
ENV['RCT_NEW_ARCH_ENABLED'] = '0'
|
||||
ENV['USE_HERMES'] = '0'
|
||||
|
||||
# Act
|
||||
flags = ReactNativePodsUtils.get_default_flags()
|
||||
|
||||
# Assert
|
||||
assert_equal(flags, {
|
||||
:fabric_enabled => false,
|
||||
:hermes_enabled => false,
|
||||
})
|
||||
end
|
||||
|
||||
def test_getDefaultFlag_whenNewArchitecture()
|
||||
# Arrange
|
||||
ENV['RCT_NEW_ARCH_ENABLED'] = '1'
|
||||
@@ -119,6 +135,21 @@ class UtilsTests < Test::Unit::TestCase
|
||||
})
|
||||
end
|
||||
|
||||
def test_getDefaultFlag_whenNewArchitectureButHermesDisabled()
|
||||
# Arrange
|
||||
ENV['RCT_NEW_ARCH_ENABLED'] = '1'
|
||||
ENV['USE_HERMES'] = '0'
|
||||
|
||||
# Act
|
||||
flags = ReactNativePodsUtils.get_default_flags()
|
||||
|
||||
# Assert
|
||||
assert_equal(flags, {
|
||||
:fabric_enabled => true,
|
||||
:hermes_enabled => false,
|
||||
})
|
||||
end
|
||||
|
||||
# ============== #
|
||||
# TEST - has_pod #
|
||||
# ============== #
|
||||
|
||||
@@ -5,6 +5,19 @@
|
||||
|
||||
require_relative './utils.rb'
|
||||
|
||||
# It sets up the JavaScriptCore.
|
||||
#
|
||||
# @parameter react_native_path: relative path to react-native
|
||||
# @parameter fabric_enabled: whether Fabirc is enabled
|
||||
def setup_jsc!(react_native_path: "../node_modules/react-native", fabric_enabled: false)
|
||||
if ENV['USE_THIRD_PARTY_JSC'] != '1'
|
||||
pod 'React-jsc', :path => "#{react_native_path}/ReactCommon/jsc"
|
||||
if fabric_enabled
|
||||
pod 'React-jsc/Fabric', :path => "#{react_native_path}/ReactCommon/jsc"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# It sets up the Hermes.
|
||||
#
|
||||
# @parameter react_native_path: relative path to react-native
|
||||
@@ -19,37 +32,11 @@ def setup_hermes!(react_native_path: "../node_modules/react-native")
|
||||
pod 'React-hermes', :path => "#{react_native_path}/ReactCommon/hermes"
|
||||
end
|
||||
|
||||
def use_third_party_jsc
|
||||
return ENV['USE_THIRD_PARTY_JSC'] == '1'
|
||||
end
|
||||
|
||||
# use Hermes is the default. The only other option is the third-party JSC
|
||||
# if the 3rd party JSC is not true, we always want to use Hermes.
|
||||
def use_hermes
|
||||
return !use_third_party_jsc()
|
||||
end
|
||||
|
||||
def use_hermes_flags
|
||||
return "-DUSE_HERMES=1"
|
||||
end
|
||||
|
||||
def use_third_party_jsc_flags
|
||||
return "-DUSE_THIRD_PARTY_JSC=1"
|
||||
end
|
||||
|
||||
def js_engine_flags()
|
||||
if use_hermes()
|
||||
return use_hermes_flags()
|
||||
else
|
||||
return use_third_party_jsc_flags()
|
||||
end
|
||||
end
|
||||
|
||||
# Utility function to depend on JS engine based on the environment variable.
|
||||
def depend_on_js_engine(s)
|
||||
if use_hermes()
|
||||
if ENV["USE_HERMES"] == nil || ENV["USE_HERMES"] == "1"
|
||||
s.dependency 'hermes-engine'
|
||||
elsif use_third_party_jsc()
|
||||
elsif ENV['USE_THIRD_PARTY_JSC'] != '1'
|
||||
s.dependency 'React-jsc'
|
||||
end
|
||||
end
|
||||
|
||||
@@ -142,17 +142,8 @@ class ReactNativeDependenciesUtils
|
||||
end
|
||||
|
||||
def self.nightly_tarball_url(version)
|
||||
artefact_coordinate = "react-native-artifacts"
|
||||
artefact_name = "reactnative-dependencies-debug.tar.gz"
|
||||
xml_url = "https://central.sonatype.com/repository/maven-snapshots/com/facebook/react/#{artefact_coordinate}/#{version}-SNAPSHOT/maven-metadata.xml"
|
||||
|
||||
xml = REXML::Document.new(Net::HTTP.get(URI(xml_url)))
|
||||
timestamp = xml.elements['metadata/versioning/snapshot/timestamp'].text
|
||||
build_number = xml.elements['metadata/versioning/snapshot/buildNumber'].text
|
||||
full_version = "#{version}-#{timestamp}-#{build_number}"
|
||||
|
||||
final_url = "https://central.sonatype.com/repository/maven-snapshots/com/facebook/react/#{artefact_coordinate}/#{version}-SNAPSHOT/#{artefact_coordinate}-#{full_version}-#{artefact_name}"
|
||||
return final_url
|
||||
params = "r=snapshots\&g=com.facebook.react\&a=react-native-artifacts\&c=reactnative-dependencies-debug\&e=tar.gz\&v=#{version}-SNAPSHOT"
|
||||
return resolve_url_redirects("http://oss.sonatype.org/service/local/artifact/maven/redirect\?#{params}")
|
||||
end
|
||||
|
||||
def self.download_stable_rndeps(react_native_path, version, configuration)
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
require 'shellwords'
|
||||
|
||||
require_relative "./helpers.rb"
|
||||
require_relative "./jsengine.rb"
|
||||
|
||||
# Utilities class for React Native Cocoapods
|
||||
class ReactNativePodsUtils
|
||||
@@ -33,7 +32,7 @@ class ReactNativePodsUtils
|
||||
flags[:hermes_enabled] = true
|
||||
end
|
||||
|
||||
if !use_hermes()
|
||||
if ENV['USE_HERMES'] == '0'
|
||||
flags[:hermes_enabled] = false
|
||||
end
|
||||
|
||||
|
||||
@@ -64,14 +64,12 @@ def use_react_native! (
|
||||
fabric_enabled: false,
|
||||
new_arch_enabled: NewArchitectureHelper.new_arch_enabled,
|
||||
production: false, # deprecated
|
||||
hermes_enabled: true, # deprecated. Hermes is the default engine and JSC has been moved to community support
|
||||
hermes_enabled: ENV['USE_HERMES'] && ENV['USE_HERMES'] == '0' ? false : true,
|
||||
app_path: '..',
|
||||
config_file_dir: '',
|
||||
privacy_file_aggregation_enabled: true
|
||||
)
|
||||
error_if_try_to_use_jsc_from_core()
|
||||
|
||||
hermes_enabled= true
|
||||
# Set the app_path as env variable so the podspecs can access it.
|
||||
ENV['APP_PATH'] = app_path
|
||||
ENV['REACT_NATIVE_PATH'] = path
|
||||
@@ -95,6 +93,7 @@ def use_react_native! (
|
||||
fabric_enabled = fabric_enabled || NewArchitectureHelper.new_arch_enabled
|
||||
|
||||
ENV['RCT_FABRIC_ENABLED'] = fabric_enabled ? "1" : "0"
|
||||
ENV['USE_HERMES'] = hermes_enabled ? "1" : "0"
|
||||
ENV['RCT_AGGREGATE_PRIVACY_FILES'] = privacy_file_aggregation_enabled ? "1" : "0"
|
||||
ENV["RCT_NEW_ARCH_ENABLED"] = new_arch_enabled ? "1" : "0"
|
||||
|
||||
@@ -143,6 +142,8 @@ def use_react_native! (
|
||||
|
||||
if hermes_enabled
|
||||
setup_hermes!(:react_native_path => prefix)
|
||||
else
|
||||
setup_jsc!(:react_native_path => prefix, :fabric_enabled => fabric_enabled)
|
||||
end
|
||||
|
||||
pod 'React-jsiexecutor', :path => "#{prefix}/ReactCommon/jsiexecutor"
|
||||
@@ -384,7 +385,8 @@ end
|
||||
def print_jsc_removal_message()
|
||||
puts ''
|
||||
puts '=============== JavaScriptCore is being moved ==============='.yellow
|
||||
puts 'JavaScriptCore has been removed from React Native. It can now be'.yellow
|
||||
puts 'JavaScriptCore has been extracted from react-native core'.yellow
|
||||
puts 'and will be removed in a future release. It can now be'.yellow
|
||||
puts 'installed from `@react-native-community/javascriptcore`'.yellow
|
||||
puts 'See: https://github.com/react-native-community/javascriptcore'.yellow
|
||||
puts '============================================================='.yellow
|
||||
@@ -410,19 +412,6 @@ def print_cocoapods_deprecation_message()
|
||||
|
||||
end
|
||||
|
||||
def error_if_try_to_use_jsc_from_core()
|
||||
explicitly_not_use_hermes = ENV['USE_HERMES'] != nil && ENV['USE_HERMES'] == '0'
|
||||
not_use_3rd_party_jsc = ENV['USE_THIRD_PARTY_JSC'] == nil || ENV['USE_THIRD_PARTY_JSC'] == '0'
|
||||
if (explicitly_not_use_hermes && not_use_3rd_party_jsc)
|
||||
message = "Hermes is the default engine and JSC has been moved to community support.\n" +
|
||||
"Please remove the USE_HERMES=0, as it is not supported anymore.\n" +
|
||||
"If you want to use JSC, you can install it from `@react-native-community/javascriptcore`.\n" +
|
||||
"See: https://github.com/react-native-community/javascriptcore"
|
||||
puts message.red
|
||||
exit()
|
||||
end
|
||||
end
|
||||
|
||||
# Function that executes after React Native has been installed to configure some flags and build settings.
|
||||
#
|
||||
# Parameters
|
||||
@@ -440,16 +429,17 @@ def react_native_post_install(
|
||||
|
||||
ReactNativePodsUtils.apply_mac_catalyst_patches(installer) if mac_catalyst_enabled
|
||||
|
||||
hermes_enabled = ENV['USE_HERMES'] == '1'
|
||||
privacy_file_aggregation_enabled = ENV['RCT_AGGREGATE_PRIVACY_FILES'] == '1'
|
||||
|
||||
if use_hermes()
|
||||
if hermes_enabled
|
||||
ReactNativePodsUtils.set_gcc_preprocessor_definition_for_React_hermes(installer)
|
||||
end
|
||||
ReactNativePodsUtils.set_gcc_preprocessor_definition_for_debugger(installer)
|
||||
|
||||
ReactNativePodsUtils.fix_library_search_paths(installer)
|
||||
ReactNativePodsUtils.update_search_paths(installer)
|
||||
ReactNativePodsUtils.set_build_setting(installer, build_setting: "USE_HERMES", value: use_hermes())
|
||||
ReactNativePodsUtils.set_build_setting(installer, build_setting: "USE_HERMES", value: hermes_enabled)
|
||||
ReactNativePodsUtils.set_build_setting(installer, build_setting: "REACT_NATIVE_PATH", value: File.join("${PODS_ROOT}", "..", react_native_path))
|
||||
ReactNativePodsUtils.set_build_setting(installer, build_setting: "SWIFT_ACTIVE_COMPILATION_CONDITIONS", value: ['$(inherited)', 'DEBUG'], config_name: "Debug")
|
||||
|
||||
@@ -469,7 +459,7 @@ def react_native_post_install(
|
||||
NewArchitectureHelper.modify_flags_for_new_architecture(installer, NewArchitectureHelper.new_arch_enabled)
|
||||
NewArchitectureHelper.set_RCTNewArchEnabled_in_info_plist(installer, NewArchitectureHelper.new_arch_enabled)
|
||||
|
||||
if !use_hermes() && !use_third_party_jsc()
|
||||
if ENV['USE_HERMES'] == '0' && ENV['USE_THIRD_PARTY_JSC'] != '1'
|
||||
print_jsc_removal_message()
|
||||
end
|
||||
|
||||
|
||||
@@ -230,17 +230,8 @@ def download_hermes_tarball(react_native_path, tarball_url, version, configurati
|
||||
end
|
||||
|
||||
def nightly_tarball_url(version)
|
||||
artefact_coordinate = "react-native-artifacts"
|
||||
artefact_name = "hermes-ios-debug.tar.gz"
|
||||
xml_url = "https://central.sonatype.com/repository/maven-snapshots/com/facebook/react/#{artefact_coordinate}/#{version}-SNAPSHOT/maven-metadata.xml"
|
||||
|
||||
xml = REXML::Document.new(Net::HTTP.get(URI(xml_url)))
|
||||
timestamp = xml.elements['metadata/versioning/snapshot/timestamp'].text
|
||||
build_number = xml.elements['metadata/versioning/snapshot/buildNumber'].text
|
||||
full_version = "#{version}-#{timestamp}-#{build_number}"
|
||||
|
||||
final_url = "https://central.sonatype.com/repository/maven-snapshots/com/facebook/react/#{artefact_coordinate}/#{version}-SNAPSHOT/#{artefact_coordinate}-#{full_version}-#{artefact_name}"
|
||||
return final_url
|
||||
params = "r=snapshots\&g=com.facebook.react\&a=react-native-artifacts\&c=hermes-ios-debug\&e=tar.gz\&v=#{version}-SNAPSHOT"
|
||||
return resolve_url_redirects("http://oss.sonatype.org/service/local/artifact/maven/redirect\?#{params}")
|
||||
end
|
||||
|
||||
def resolve_url_redirects(url)
|
||||
|
||||
@@ -10,17 +10,9 @@ hermesc_dir_path="$1"; shift
|
||||
jsi_path="$1"
|
||||
|
||||
# This script is supposed to be executed from Xcode "run script" phase.
|
||||
# Xcode sets up its build environment based on the build target (iphone, iphonesimulator, macosx).
|
||||
# Xcode sets up its build environment based on the build target (iphone, iphonesimulator, macodsx).
|
||||
# We want to make sure that hermesc is built for mac.
|
||||
# So we clean the environment with env -i, and explicitly set SDKROOT to macosx
|
||||
SDKROOT=$(xcode-select -p)/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk
|
||||
|
||||
env -i \
|
||||
PATH="$PATH" \
|
||||
SDKROOT="$SDKROOT" \
|
||||
"$CMAKE_BINARY" -S "${PODS_ROOT}/hermes-engine" -B "$hermesc_dir_path" -DJSI_DIR="$jsi_path"
|
||||
|
||||
env -i \
|
||||
PATH="$PATH" \
|
||||
SDKROOT="$SDKROOT" \
|
||||
"$CMAKE_BINARY" --build "$hermesc_dir_path" --target hermesc -j "$(sysctl -n hw.ncpu)"
|
||||
env -i SDKROOT="$SDKROOT" "$CMAKE_BINARY" -S "${PODS_ROOT}/hermes-engine" -B "$hermesc_dir_path" -DJSI_DIR="$jsi_path"
|
||||
env -i SDKROOT="$SDKROOT" "$CMAKE_BINARY" --build "$hermesc_dir_path" --target hermesc -j "$(sysctl -n hw.ncpu)"
|
||||
|
||||
@@ -37,9 +37,15 @@ def pods(target_name, options = {})
|
||||
|
||||
fabric_enabled = true
|
||||
|
||||
# Hermes is now enabled by default.
|
||||
# The following line will only disable Hermes if the USE_HERMES envvar is SET to a value other than 1 (e.g. USE_HERMES=0).
|
||||
hermes_enabled = !ENV.has_key?('USE_HERMES') || ENV['USE_HERMES'] == '1'
|
||||
puts "Configuring #{target_name} with Fabric #{fabric_enabled ? "enabled" : "disabled"}.#{hermes_enabled ? " Using Hermes engine." : ""}"
|
||||
|
||||
use_react_native!(
|
||||
path: @prefix_path,
|
||||
fabric_enabled: fabric_enabled,
|
||||
hermes_enabled: hermes_enabled,
|
||||
app_path: "#{Dir.pwd}",
|
||||
config_file_dir: "#{Dir.pwd}/node_modules",
|
||||
production: false, #deprecated
|
||||
|
||||
@@ -31,7 +31,7 @@ If you are still having a problem after doing the clean up (which can happen if
|
||||
Both macOS and Xcode are required.
|
||||
1. `cd packages/rn-tester`
|
||||
2. Install [Bundler](https://bundler.io/): `gem install bundler`. We use bundler to install the right version of [CocoaPods](https://cocoapods.org/) locally.
|
||||
3. Install Bundler and CocoaPods dependencies: `bundle install && bundle exec pod install` or `yarn prepare-ios`.
|
||||
3. Install Bundler and CocoaPods dependencies: `bundle install && bundle exec pod install` or `yarn prepare-ios`. In order to use JSC instead of Hermes engine, run: `USE_HERMES=0 bundle exec pod install` or `yarn prepare-ios --arch old --jsvm jsc` instead.
|
||||
4. Open the generated `RNTesterPods.xcworkspace`. This is not checked in, as it is generated by CocoaPods. Do not open `RNTesterPods.xcodeproj` directly.
|
||||
|
||||
#### Note for Apple Silicon users
|
||||
|
||||
@@ -8,8 +8,6 @@
|
||||
* @format
|
||||
*/
|
||||
|
||||
import type {ReportFullyDrawnViewType} from './ReportFullyDrawnViewNativeComponent';
|
||||
|
||||
import {View} from 'react-native';
|
||||
|
||||
export default View as ReportFullyDrawnViewType;
|
||||
export default View;
|
||||
|
||||
+3
-26
@@ -7,12 +7,11 @@
|
||||
|
||||
package com.facebook.react.uiapp
|
||||
|
||||
import android.content.res.Configuration
|
||||
import android.graphics.Color
|
||||
import android.graphics.drawable.ColorDrawable
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import android.widget.FrameLayout
|
||||
import androidx.core.graphics.drawable.toDrawable
|
||||
import androidx.core.view.ViewCompat
|
||||
import androidx.core.view.WindowInsetsCompat
|
||||
import com.facebook.react.FBRNTesterEndToEndHelper
|
||||
@@ -44,28 +43,13 @@ internal class RNTesterActivity : ReactActivity() {
|
||||
if (this::initialProps.isInitialized) initialProps else Bundle()
|
||||
}
|
||||
|
||||
// set background color so it will show below transparent system bars on forced edge-to-edge
|
||||
private fun maybeUpdateBackgroundColor() {
|
||||
val isDarkMode =
|
||||
resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK ==
|
||||
Configuration.UI_MODE_NIGHT_YES
|
||||
|
||||
val color =
|
||||
if (isDarkMode) {
|
||||
Color.rgb(11, 6, 0)
|
||||
} else {
|
||||
Color.rgb(243, 248, 255)
|
||||
}
|
||||
|
||||
window?.setBackgroundDrawable(color.toDrawable())
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
fullyDrawnReporter.addReporter()
|
||||
maybeUpdateBackgroundColor()
|
||||
|
||||
// set background color so it will show below transparent system bars on forced edge-to-edge
|
||||
this.window?.setBackgroundDrawable(ColorDrawable(Color.BLACK))
|
||||
// register insets listener to update margins on the ReactRootView to avoid overlap w/ system
|
||||
// bars
|
||||
getReactDelegate()?.getReactRootView()?.let { rootView ->
|
||||
@@ -85,13 +69,6 @@ internal class RNTesterActivity : ReactActivity() {
|
||||
}
|
||||
}
|
||||
|
||||
override fun onConfigurationChanged(newConfig: Configuration) {
|
||||
super.onConfigurationChanged(newConfig)
|
||||
|
||||
// update background color on UI mode change
|
||||
maybeUpdateBackgroundColor()
|
||||
}
|
||||
|
||||
override fun createReactActivityDelegate() = RNTesterActivityDelegate(this, mainComponentName)
|
||||
|
||||
override fun getMainComponentName() = "RNTesterApp"
|
||||
|
||||
@@ -55,7 +55,6 @@ const config /*: InputConfigT */ = {
|
||||
// We need to wrap the default transformer so we can run it from source
|
||||
// using babel-register.
|
||||
babelTransformerPath: path.resolve(__dirname, 'metro-babel-transformer.js'),
|
||||
hermesParser: true,
|
||||
},
|
||||
serializer: {
|
||||
// Force an empty list so Metro doesn't inject InitializeCore in tests.
|
||||
|
||||
@@ -37,7 +37,6 @@ add_react_third_party_ndk_subdir(folly)
|
||||
|
||||
# Common targets
|
||||
add_react_common_subdir(yoga)
|
||||
add_react_common_subdir(react/featureflags)
|
||||
|
||||
file(GLOB SOURCES "src/*.cpp" "src/*.h")
|
||||
add_executable(fantom_tester ${SOURCES})
|
||||
@@ -49,7 +48,6 @@ target_link_libraries(fantom_tester
|
||||
double-conversion
|
||||
fast_float
|
||||
folly_runtime
|
||||
react_featureflags
|
||||
yogacore)
|
||||
|
||||
target_compile_options(fantom_tester
|
||||
|
||||
@@ -15,10 +15,3 @@ cmake -S "$SCRIPT_DIR" -B "$BUILD_DIR" \
|
||||
-DREACT_COMMON_DIR="${REACT_NATIVE_ROOT_DIR}/ReactCommon"
|
||||
|
||||
cmake --build "$BUILD_DIR" --target fantom_tester
|
||||
|
||||
while getopts ":r" opt; do
|
||||
case $opt in
|
||||
r) "$BUILD_DIR/fantom_tester" ;;
|
||||
\?) echo "Invalid option: -$OPTARG"; exit 1;;
|
||||
esac
|
||||
done
|
||||
|
||||
@@ -5,40 +5,19 @@
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#include <fmt/format.h>
|
||||
#include <glog/logging.h>
|
||||
#include <react/featureflags/ReactNativeFeatureFlags.h>
|
||||
#include <react/featureflags/ReactNativeFeatureFlagsDynamicProvider.h>
|
||||
#include <yoga/YGEnums.h>
|
||||
#include <yoga/YGValue.h>
|
||||
#include <format>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
|
||||
using namespace facebook::react;
|
||||
|
||||
static void setUpLogging() {
|
||||
google::InitGoogleLogging("react-native-fantom");
|
||||
FLAGS_logtostderr = true;
|
||||
}
|
||||
|
||||
static void setUpFeatureFlags() {
|
||||
folly::dynamic dynamicFeatureFlags = folly::dynamic::object();
|
||||
|
||||
dynamicFeatureFlags["enableBridgelessArchitecture"] = true;
|
||||
dynamicFeatureFlags["cxxNativeAnimatedEnabled"] = true;
|
||||
|
||||
ReactNativeFeatureFlags::override(
|
||||
std::make_unique<ReactNativeFeatureFlagsDynamicProvider>(
|
||||
dynamicFeatureFlags));
|
||||
}
|
||||
|
||||
int main() {
|
||||
setUpLogging();
|
||||
|
||||
setUpFeatureFlags();
|
||||
google::InitGoogleLogging("fantom_tester");
|
||||
FLAGS_logtostderr = true;
|
||||
|
||||
LOG(INFO) << "Hello, I am fantom_tester using glog!";
|
||||
LOG(INFO) << std::format(
|
||||
|
||||
LOG(INFO) << fmt::format(
|
||||
"[Yoga] undefined == zero: {}", YGValueZero == YGValueUndefined);
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -14,6 +14,7 @@ def use_react_native! (
|
||||
fabric_enabled: false,
|
||||
new_arch_enabled: NewArchitectureHelper.new_arch_enabled,
|
||||
production: false, # deprecated
|
||||
hermes_enabled: ENV['USE_HERMES'] && ENV['USE_HERMES'] == '0' ? false : true,
|
||||
flipper_configuration: FlipperConfiguration.disabled,
|
||||
app_path: '..',
|
||||
config_file_dir: '',
|
||||
@@ -26,6 +27,7 @@ def use_react_native! (
|
||||
path: "../node_modules/react-native",
|
||||
fabric_enabled: false,
|
||||
production: false, # deprecated
|
||||
hermes_enabled: ENV['USE_HERMES'] && ENV['USE_HERMES'] == '0' ? false : true,
|
||||
flipper_configuration: FlipperConfiguration.disabled,
|
||||
app_path: '..',
|
||||
config_file_dir: '',
|
||||
@@ -37,6 +39,7 @@ const expectedReactNativePodsFile = `
|
||||
def use_react_native! (
|
||||
path: "../node_modules/react-native",
|
||||
production: false, # deprecated
|
||||
hermes_enabled: ENV['USE_HERMES'] && ENV['USE_HERMES'] == '0' ? false : true,
|
||||
flipper_configuration: FlipperConfiguration.disabled,
|
||||
app_path: '..',
|
||||
config_file_dir: '',
|
||||
|
||||
@@ -19,25 +19,11 @@
|
||||
js-tokens "^4.0.0"
|
||||
picocolors "^1.0.0"
|
||||
|
||||
"@babel/code-frame@^7.27.1":
|
||||
version "7.27.1"
|
||||
resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.27.1.tgz#200f715e66d52a23b221a9435534a91cc13ad5be"
|
||||
integrity sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==
|
||||
dependencies:
|
||||
"@babel/helper-validator-identifier" "^7.27.1"
|
||||
js-tokens "^4.0.0"
|
||||
picocolors "^1.1.1"
|
||||
|
||||
"@babel/compat-data@^7.22.6", "@babel/compat-data@^7.26.5", "@babel/compat-data@^7.26.8":
|
||||
version "7.26.8"
|
||||
resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.26.8.tgz#821c1d35641c355284d4a870b8a4a7b0c141e367"
|
||||
integrity sha512-oH5UPLMWR3L2wEFLnFJ1TZXqHufiTKAiLfqw5zkhS4dKXLJ10yVztfil/twG8EDTA4F/tvVNw9nOl4ZMslB8rQ==
|
||||
|
||||
"@babel/compat-data@^7.27.2":
|
||||
version "7.27.5"
|
||||
resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.27.5.tgz#7d0658ec1a8420fc866d1df1b03bea0e79934c82"
|
||||
integrity sha512-KiRAp/VoJaWkkte84TvUd9qjdbZAdiqyvMxrGl1N6vzFogKmaLgoM3L1kgtLicp2HP5fBJS8JrZKLVIZGVJAVg==
|
||||
|
||||
"@babel/core@^7.11.6", "@babel/core@^7.12.3", "@babel/core@^7.23.9", "@babel/core@^7.25.2":
|
||||
version "7.26.9"
|
||||
resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.26.9.tgz#71838542a4b1e49dfed353d7acbc6eb89f4a76f2"
|
||||
@@ -59,27 +45,6 @@
|
||||
json5 "^2.2.3"
|
||||
semver "^6.3.1"
|
||||
|
||||
"@babel/core@^7.24.4":
|
||||
version "7.27.4"
|
||||
resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.27.4.tgz#cc1fc55d0ce140a1828d1dd2a2eba285adbfb3ce"
|
||||
integrity sha512-bXYxrXFubeYdvB0NhD/NBB3Qi6aZeV20GOWVI47t2dkecCEoneR4NPVcb7abpXDEvejgrUfFtG6vG/zxAKmg+g==
|
||||
dependencies:
|
||||
"@ampproject/remapping" "^2.2.0"
|
||||
"@babel/code-frame" "^7.27.1"
|
||||
"@babel/generator" "^7.27.3"
|
||||
"@babel/helper-compilation-targets" "^7.27.2"
|
||||
"@babel/helper-module-transforms" "^7.27.3"
|
||||
"@babel/helpers" "^7.27.4"
|
||||
"@babel/parser" "^7.27.4"
|
||||
"@babel/template" "^7.27.2"
|
||||
"@babel/traverse" "^7.27.4"
|
||||
"@babel/types" "^7.27.3"
|
||||
convert-source-map "^2.0.0"
|
||||
debug "^4.1.0"
|
||||
gensync "^1.0.0-beta.2"
|
||||
json5 "^2.2.3"
|
||||
semver "^6.3.1"
|
||||
|
||||
"@babel/eslint-parser@^7.25.1":
|
||||
version "7.26.8"
|
||||
resolved "https://registry.yarnpkg.com/@babel/eslint-parser/-/eslint-parser-7.26.8.tgz#55c4f4aae4970ae127f7a12369182ed6250e6f09"
|
||||
@@ -100,17 +65,6 @@
|
||||
"@jridgewell/trace-mapping" "^0.3.25"
|
||||
jsesc "^3.0.2"
|
||||
|
||||
"@babel/generator@^7.27.3":
|
||||
version "7.27.5"
|
||||
resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.27.5.tgz#3eb01866b345ba261b04911020cbe22dd4be8c8c"
|
||||
integrity sha512-ZGhA37l0e/g2s1Cnzdix0O3aLYm66eF8aufiVteOgnwxgnRP8GoyMj7VWsgWnQbVKXyge7hqrFh2K2TQM6t1Hw==
|
||||
dependencies:
|
||||
"@babel/parser" "^7.27.5"
|
||||
"@babel/types" "^7.27.3"
|
||||
"@jridgewell/gen-mapping" "^0.3.5"
|
||||
"@jridgewell/trace-mapping" "^0.3.25"
|
||||
jsesc "^3.0.2"
|
||||
|
||||
"@babel/helper-annotate-as-pure@^7.25.9":
|
||||
version "7.25.9"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.25.9.tgz#d8eac4d2dc0d7b6e11fa6e535332e0d3184f06b4"
|
||||
@@ -118,13 +72,6 @@
|
||||
dependencies:
|
||||
"@babel/types" "^7.25.9"
|
||||
|
||||
"@babel/helper-annotate-as-pure@^7.27.1":
|
||||
version "7.27.3"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.27.3.tgz#f31fd86b915fc4daf1f3ac6976c59be7084ed9c5"
|
||||
integrity sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg==
|
||||
dependencies:
|
||||
"@babel/types" "^7.27.3"
|
||||
|
||||
"@babel/helper-compilation-targets@^7.22.6", "@babel/helper-compilation-targets@^7.25.9", "@babel/helper-compilation-targets@^7.26.5":
|
||||
version "7.26.5"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.26.5.tgz#75d92bb8d8d51301c0d49e52a65c9a7fe94514d8"
|
||||
@@ -136,17 +83,6 @@
|
||||
lru-cache "^5.1.1"
|
||||
semver "^6.3.1"
|
||||
|
||||
"@babel/helper-compilation-targets@^7.27.2":
|
||||
version "7.27.2"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz#46a0f6efab808d51d29ce96858dd10ce8732733d"
|
||||
integrity sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==
|
||||
dependencies:
|
||||
"@babel/compat-data" "^7.27.2"
|
||||
"@babel/helper-validator-option" "^7.27.1"
|
||||
browserslist "^4.24.0"
|
||||
lru-cache "^5.1.1"
|
||||
semver "^6.3.1"
|
||||
|
||||
"@babel/helper-create-class-features-plugin@^7.25.9":
|
||||
version "7.26.9"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.26.9.tgz#d6f83e3039547fbb39967e78043cd3c8b7820c71"
|
||||
@@ -160,19 +96,6 @@
|
||||
"@babel/traverse" "^7.26.9"
|
||||
semver "^6.3.1"
|
||||
|
||||
"@babel/helper-create-class-features-plugin@^7.27.1":
|
||||
version "7.27.1"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.27.1.tgz#5bee4262a6ea5ddc852d0806199eb17ca3de9281"
|
||||
integrity sha512-QwGAmuvM17btKU5VqXfb+Giw4JcN0hjuufz3DYnpeVDvZLAObloM77bhMXiqry3Iio+Ai4phVRDwl6WU10+r5A==
|
||||
dependencies:
|
||||
"@babel/helper-annotate-as-pure" "^7.27.1"
|
||||
"@babel/helper-member-expression-to-functions" "^7.27.1"
|
||||
"@babel/helper-optimise-call-expression" "^7.27.1"
|
||||
"@babel/helper-replace-supers" "^7.27.1"
|
||||
"@babel/helper-skip-transparent-expression-wrappers" "^7.27.1"
|
||||
"@babel/traverse" "^7.27.1"
|
||||
semver "^6.3.1"
|
||||
|
||||
"@babel/helper-create-regexp-features-plugin@^7.18.6", "@babel/helper-create-regexp-features-plugin@^7.25.9":
|
||||
version "7.26.3"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.26.3.tgz#5169756ecbe1d95f7866b90bb555b022595302a0"
|
||||
@@ -201,14 +124,6 @@
|
||||
"@babel/traverse" "^7.25.9"
|
||||
"@babel/types" "^7.25.9"
|
||||
|
||||
"@babel/helper-member-expression-to-functions@^7.27.1":
|
||||
version "7.27.1"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.27.1.tgz#ea1211276be93e798ce19037da6f06fbb994fa44"
|
||||
integrity sha512-E5chM8eWjTp/aNoVpcbfM7mLxu9XGLWYise2eBKGQomAk/Mb4XoxyqXTZbuTohbsl8EKqdlMhnDI2CCLfcs9wA==
|
||||
dependencies:
|
||||
"@babel/traverse" "^7.27.1"
|
||||
"@babel/types" "^7.27.1"
|
||||
|
||||
"@babel/helper-module-imports@^7.25.9":
|
||||
version "7.25.9"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.25.9.tgz#e7f8d20602ebdbf9ebbea0a0751fb0f2a4141715"
|
||||
@@ -217,14 +132,6 @@
|
||||
"@babel/traverse" "^7.25.9"
|
||||
"@babel/types" "^7.25.9"
|
||||
|
||||
"@babel/helper-module-imports@^7.27.1":
|
||||
version "7.27.1"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz#7ef769a323e2655e126673bb6d2d6913bbead204"
|
||||
integrity sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==
|
||||
dependencies:
|
||||
"@babel/traverse" "^7.27.1"
|
||||
"@babel/types" "^7.27.1"
|
||||
|
||||
"@babel/helper-module-transforms@^7.25.9", "@babel/helper-module-transforms@^7.26.0":
|
||||
version "7.26.0"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.26.0.tgz#8ce54ec9d592695e58d84cd884b7b5c6a2fdeeae"
|
||||
@@ -234,15 +141,6 @@
|
||||
"@babel/helper-validator-identifier" "^7.25.9"
|
||||
"@babel/traverse" "^7.25.9"
|
||||
|
||||
"@babel/helper-module-transforms@^7.27.3":
|
||||
version "7.27.3"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.27.3.tgz#db0bbcfba5802f9ef7870705a7ef8788508ede02"
|
||||
integrity sha512-dSOvYwvyLsWBeIRyOeHXp5vPj5l1I011r52FM1+r1jCERv+aFXYk4whgQccYEGYxK2H3ZAIA8nuPkQ0HaUo3qg==
|
||||
dependencies:
|
||||
"@babel/helper-module-imports" "^7.27.1"
|
||||
"@babel/helper-validator-identifier" "^7.27.1"
|
||||
"@babel/traverse" "^7.27.3"
|
||||
|
||||
"@babel/helper-optimise-call-expression@^7.25.9":
|
||||
version "7.25.9"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.25.9.tgz#3324ae50bae7e2ab3c33f60c9a877b6a0146b54e"
|
||||
@@ -250,23 +148,11 @@
|
||||
dependencies:
|
||||
"@babel/types" "^7.25.9"
|
||||
|
||||
"@babel/helper-optimise-call-expression@^7.27.1":
|
||||
version "7.27.1"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.27.1.tgz#c65221b61a643f3e62705e5dd2b5f115e35f9200"
|
||||
integrity sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw==
|
||||
dependencies:
|
||||
"@babel/types" "^7.27.1"
|
||||
|
||||
"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.18.6", "@babel/helper-plugin-utils@^7.18.9", "@babel/helper-plugin-utils@^7.22.5", "@babel/helper-plugin-utils@^7.25.9", "@babel/helper-plugin-utils@^7.26.5", "@babel/helper-plugin-utils@^7.8.0", "@babel/helper-plugin-utils@^7.8.3":
|
||||
version "7.26.5"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.26.5.tgz#18580d00c9934117ad719392c4f6585c9333cc35"
|
||||
integrity sha512-RS+jZcRdZdRFzMyr+wcsaqOmld1/EqTghfaBGQQd/WnRdzdlvSZ//kF7U8VQTxf1ynZ4cjUcYgjVGx13ewNPMg==
|
||||
|
||||
"@babel/helper-plugin-utils@^7.27.1":
|
||||
version "7.27.1"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.27.1.tgz#ddb2f876534ff8013e6c2b299bf4d39b3c51d44c"
|
||||
integrity sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==
|
||||
|
||||
"@babel/helper-remap-async-to-generator@^7.25.9":
|
||||
version "7.25.9"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.25.9.tgz#e53956ab3d5b9fb88be04b3e2f31b523afd34b92"
|
||||
@@ -285,15 +171,6 @@
|
||||
"@babel/helper-optimise-call-expression" "^7.25.9"
|
||||
"@babel/traverse" "^7.26.5"
|
||||
|
||||
"@babel/helper-replace-supers@^7.27.1":
|
||||
version "7.27.1"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.27.1.tgz#b1ed2d634ce3bdb730e4b52de30f8cccfd692bc0"
|
||||
integrity sha512-7EHz6qDZc8RYS5ElPoShMheWvEgERonFCs7IAonWLLUTXW59DP14bCZt89/GKyreYn8g3S83m21FelHKbeDCKA==
|
||||
dependencies:
|
||||
"@babel/helper-member-expression-to-functions" "^7.27.1"
|
||||
"@babel/helper-optimise-call-expression" "^7.27.1"
|
||||
"@babel/traverse" "^7.27.1"
|
||||
|
||||
"@babel/helper-skip-transparent-expression-wrappers@^7.25.9":
|
||||
version "7.25.9"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.25.9.tgz#0b2e1b62d560d6b1954893fd2b705dc17c91f0c9"
|
||||
@@ -302,44 +179,21 @@
|
||||
"@babel/traverse" "^7.25.9"
|
||||
"@babel/types" "^7.25.9"
|
||||
|
||||
"@babel/helper-skip-transparent-expression-wrappers@^7.27.1":
|
||||
version "7.27.1"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.27.1.tgz#62bb91b3abba8c7f1fec0252d9dbea11b3ee7a56"
|
||||
integrity sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg==
|
||||
dependencies:
|
||||
"@babel/traverse" "^7.27.1"
|
||||
"@babel/types" "^7.27.1"
|
||||
|
||||
"@babel/helper-string-parser@^7.25.9":
|
||||
version "7.25.9"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz#1aabb72ee72ed35789b4bbcad3ca2862ce614e8c"
|
||||
integrity sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==
|
||||
|
||||
"@babel/helper-string-parser@^7.27.1":
|
||||
version "7.27.1"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz#54da796097ab19ce67ed9f88b47bb2ec49367687"
|
||||
integrity sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==
|
||||
|
||||
"@babel/helper-validator-identifier@^7.25.9":
|
||||
version "7.25.9"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz#24b64e2c3ec7cd3b3c547729b8d16871f22cbdc7"
|
||||
integrity sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==
|
||||
|
||||
"@babel/helper-validator-identifier@^7.27.1":
|
||||
version "7.27.1"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz#a7054dcc145a967dd4dc8fee845a57c1316c9df8"
|
||||
integrity sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==
|
||||
|
||||
"@babel/helper-validator-option@^7.25.9":
|
||||
version "7.25.9"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.25.9.tgz#86e45bd8a49ab7e03f276577f96179653d41da72"
|
||||
integrity sha512-e/zv1co8pp55dNdEcCynfj9X7nyUKUXoUEwfXqaZt0omVOmDe9oOTdKStH4GmAw6zxMFs50ZayuMfHDKlO7Tfw==
|
||||
|
||||
"@babel/helper-validator-option@^7.27.1":
|
||||
version "7.27.1"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz#fa52f5b1e7db1ab049445b421c4471303897702f"
|
||||
integrity sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==
|
||||
|
||||
"@babel/helper-wrap-function@^7.25.9":
|
||||
version "7.25.9"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.25.9.tgz#d99dfd595312e6c894bd7d237470025c85eea9d0"
|
||||
@@ -357,14 +211,6 @@
|
||||
"@babel/template" "^7.26.9"
|
||||
"@babel/types" "^7.26.9"
|
||||
|
||||
"@babel/helpers@^7.27.4":
|
||||
version "7.27.6"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.27.6.tgz#6456fed15b2cb669d2d1fabe84b66b34991d812c"
|
||||
integrity sha512-muE8Tt8M22638HU31A3CgfSUciwz1fhATfoVai05aPXGor//CdWDCbnlY1yvBPo07njuVOCNGCSp/GTt12lIug==
|
||||
dependencies:
|
||||
"@babel/template" "^7.27.2"
|
||||
"@babel/types" "^7.27.6"
|
||||
|
||||
"@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.20.7", "@babel/parser@^7.23.9", "@babel/parser@^7.25.3", "@babel/parser@^7.26.9":
|
||||
version "7.26.9"
|
||||
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.26.9.tgz#d9e78bee6dc80f9efd8f2349dcfbbcdace280fd5"
|
||||
@@ -372,13 +218,6 @@
|
||||
dependencies:
|
||||
"@babel/types" "^7.26.9"
|
||||
|
||||
"@babel/parser@^7.24.4", "@babel/parser@^7.27.2", "@babel/parser@^7.27.4", "@babel/parser@^7.27.5":
|
||||
version "7.27.5"
|
||||
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.27.5.tgz#ed22f871f110aa285a6fd934a0efed621d118826"
|
||||
integrity sha512-OsQd175SxWkGlzbny8J3K8TnnDD0N3lrIUtB92xwyRpzaenGZhxDvxN/JgU00U3CDZNj9tPuDJ5H0WS4Nt3vKg==
|
||||
dependencies:
|
||||
"@babel/types" "^7.27.3"
|
||||
|
||||
"@babel/plugin-bugfix-firefox-class-in-computed-class-key@^7.25.9":
|
||||
version "7.25.9"
|
||||
resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.25.9.tgz#cc2e53ebf0a0340777fff5ed521943e253b4d8fe"
|
||||
@@ -881,14 +720,6 @@
|
||||
dependencies:
|
||||
"@babel/helper-plugin-utils" "^7.25.9"
|
||||
|
||||
"@babel/plugin-transform-private-methods@^7.24.4":
|
||||
version "7.27.1"
|
||||
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.27.1.tgz#fdacbab1c5ed81ec70dfdbb8b213d65da148b6af"
|
||||
integrity sha512-10FVt+X55AjRAYI9BrdISN9/AQWHqldOeZDUoLyif1Kn05a56xVBXb8ZouL8pZ9jem8QpXaOt8TS7RHUIS+GPA==
|
||||
dependencies:
|
||||
"@babel/helper-create-class-features-plugin" "^7.27.1"
|
||||
"@babel/helper-plugin-utils" "^7.27.1"
|
||||
|
||||
"@babel/plugin-transform-private-methods@^7.24.7", "@babel/plugin-transform-private-methods@^7.25.9":
|
||||
version "7.25.9"
|
||||
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.25.9.tgz#847f4139263577526455d7d3223cd8bda51e3b57"
|
||||
@@ -1189,15 +1020,6 @@
|
||||
"@babel/parser" "^7.26.9"
|
||||
"@babel/types" "^7.26.9"
|
||||
|
||||
"@babel/template@^7.27.2":
|
||||
version "7.27.2"
|
||||
resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.27.2.tgz#fa78ceed3c4e7b63ebf6cb39e5852fca45f6809d"
|
||||
integrity sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==
|
||||
dependencies:
|
||||
"@babel/code-frame" "^7.27.1"
|
||||
"@babel/parser" "^7.27.2"
|
||||
"@babel/types" "^7.27.1"
|
||||
|
||||
"@babel/traverse--for-generate-function-map@npm:@babel/traverse@^7.25.3", "@babel/traverse@^7.25.3", "@babel/traverse@^7.25.9", "@babel/traverse@^7.26.5", "@babel/traverse@^7.26.8", "@babel/traverse@^7.26.9":
|
||||
version "7.26.9"
|
||||
resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.26.9.tgz#4398f2394ba66d05d988b2ad13c219a2c857461a"
|
||||
@@ -1211,19 +1033,6 @@
|
||||
debug "^4.3.1"
|
||||
globals "^11.1.0"
|
||||
|
||||
"@babel/traverse@^7.27.1", "@babel/traverse@^7.27.3", "@babel/traverse@^7.27.4":
|
||||
version "7.27.4"
|
||||
resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.27.4.tgz#b0045ac7023c8472c3d35effd7cc9ebd638da6ea"
|
||||
integrity sha512-oNcu2QbHqts9BtOWJosOVJapWjBDSxGCpFvikNR5TGDYDQf3JwpIoMzIKrvfoti93cLfPJEG4tH9SPVeyCGgdA==
|
||||
dependencies:
|
||||
"@babel/code-frame" "^7.27.1"
|
||||
"@babel/generator" "^7.27.3"
|
||||
"@babel/parser" "^7.27.4"
|
||||
"@babel/template" "^7.27.2"
|
||||
"@babel/types" "^7.27.3"
|
||||
debug "^4.3.1"
|
||||
globals "^11.1.0"
|
||||
|
||||
"@babel/types@^7.0.0", "@babel/types@^7.20.7", "@babel/types@^7.25.2", "@babel/types@^7.25.9", "@babel/types@^7.26.9", "@babel/types@^7.3.3", "@babel/types@^7.4.4":
|
||||
version "7.26.9"
|
||||
resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.26.9.tgz#08b43dec79ee8e682c2ac631c010bdcac54a21ce"
|
||||
@@ -1232,14 +1041,6 @@
|
||||
"@babel/helper-string-parser" "^7.25.9"
|
||||
"@babel/helper-validator-identifier" "^7.25.9"
|
||||
|
||||
"@babel/types@^7.27.1", "@babel/types@^7.27.3", "@babel/types@^7.27.6":
|
||||
version "7.27.6"
|
||||
resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.27.6.tgz#a434ca7add514d4e646c80f7375c0aa2befc5535"
|
||||
integrity sha512-ETyHEk2VHHvl9b9jZP5IHPavHYk57EhanlRRuae9XCpb/j5bDCbPPMOBfCWhnl/7EDJz0jEMCi/RhccCE8r1+Q==
|
||||
dependencies:
|
||||
"@babel/helper-string-parser" "^7.27.1"
|
||||
"@babel/helper-validator-identifier" "^7.27.1"
|
||||
|
||||
"@bcoe/v8-coverage@^0.2.3":
|
||||
version "0.2.3"
|
||||
resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39"
|
||||
@@ -4226,17 +4027,10 @@ eslint-plugin-jsx-a11y@^6.6.0:
|
||||
safe-regex-test "^1.0.3"
|
||||
string.prototype.includes "^2.0.0"
|
||||
|
||||
eslint-plugin-react-hooks@6.1.0-canary-12bc60f5-20250613, eslint-plugin-react-hooks@^5.2.0:
|
||||
version "6.1.0-canary-12bc60f5-20250613"
|
||||
resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-6.1.0-canary-12bc60f5-20250613.tgz#fac24a3cf8c2b7397b06cc39e016b6b4acad1078"
|
||||
integrity sha512-K+594rswc9TF1sxVO/Mp5QxxgD6tDsFT/FiwJ+O0/z9+Id6IKUyLn5S7TP24sIij6caUE6aRSEaOqkeIqmzK9A==
|
||||
dependencies:
|
||||
"@babel/core" "^7.24.4"
|
||||
"@babel/parser" "^7.24.4"
|
||||
"@babel/plugin-transform-private-methods" "^7.24.4"
|
||||
hermes-parser "^0.25.1"
|
||||
zod "^3.22.4"
|
||||
zod-validation-error "^3.0.3"
|
||||
eslint-plugin-react-hooks@^5.2.0:
|
||||
version "5.2.0"
|
||||
resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-5.2.0.tgz#1be0080901e6ac31ce7971beed3d3ec0a423d9e3"
|
||||
integrity sha512-+f15FfK64YQwZdJNELETdn5ibXEUQmW1DZL6KXhNnc2heoy/sg9VJJeT7n8TlMWouzWqSWavFkIhHyIbIAEapg==
|
||||
|
||||
eslint-plugin-react-native-globals@^0.1.1:
|
||||
version "0.1.2"
|
||||
@@ -5002,7 +4796,7 @@ hermes-estree@0.28.1:
|
||||
resolved "https://registry.yarnpkg.com/hermes-estree/-/hermes-estree-0.28.1.tgz#631e6db146b06e62fc1c630939acf4a3c77d1b24"
|
||||
integrity sha512-w3nxl/RGM7LBae0v8LH2o36+8VqwOZGv9rX1wyoWT6YaKZLqpJZ0YQ5P0LVr3tuRpf7vCx0iIG4i/VmBJejxTQ==
|
||||
|
||||
hermes-parser@0.25.1, hermes-parser@^0.25.1:
|
||||
hermes-parser@0.25.1:
|
||||
version "0.25.1"
|
||||
resolved "https://registry.yarnpkg.com/hermes-parser/-/hermes-parser-0.25.1.tgz#5be0e487b2090886c62bd8a11724cd766d5f54d1"
|
||||
integrity sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA==
|
||||
@@ -9236,13 +9030,3 @@ yocto-queue@^0.1.0:
|
||||
version "0.1.0"
|
||||
resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b"
|
||||
integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==
|
||||
|
||||
zod-validation-error@^3.0.3:
|
||||
version "3.5.0"
|
||||
resolved "https://registry.yarnpkg.com/zod-validation-error/-/zod-validation-error-3.5.0.tgz#13d31d04abbc72f3cc33c5466985f861f54ff96c"
|
||||
integrity sha512-IWK6O51sRkq0YsnYD2oLDuK2BNsIjYUlR0+1YSd4JyBzm6/892IWroUnLc7oW4FU+b0f6948BHi6H8MDcqpOGw==
|
||||
|
||||
zod@^3.22.4:
|
||||
version "3.25.64"
|
||||
resolved "https://registry.yarnpkg.com/zod/-/zod-3.25.64.tgz#57b5c7e76dd64e447f7e710285fcdb396b32f803"
|
||||
integrity sha512-hbP9FpSZf7pkS7hRVUrOjhwKJNyampPgtXKc3AN6DsWtoHsg2Sb4SQaS4Tcay380zSwd2VPo9G9180emBACp5g==
|
||||
|
||||
Reference in New Issue
Block a user