From 332be0f0c84c48e0b0edd373636b0b5538fa3b2b Mon Sep 17 00:00:00 2001 From: Riccardo Cipolleschi Date: Wed, 14 Jun 2023 10:10:16 -0700 Subject: [PATCH] download hermes-engine when the configuration change (#37850) Summary: Currently, we ask users to reinstall the pods using the `PRODUCTION` flag when they want to either profile their app or prepare a release. This way of working with the Release mode is not standard. One of the reason why we introduced it was to provide a different binary for Hermes and reinstalling the pods was the quickest way. With this change, we are deferring the decision on when Hermes should be installed for apps to the moment where the app is actually build by the system. These changes are not applied to Nightlies, when a specific tarball is passed to the cocoapods using the `HERMES_ENGINE_TARBALL_PATH` env var, and when hermes is built from source as in these scenarios we are usually not interested in building for Release. The system is also smart enough not to redownload the tarball if the configuration does not change. It assumes that the default configuration when the pods are installed for the first time is Debug. ## Changelog: [IOS] [CHANGED] - Download the right `hermes-engine` configuration at build time. Pull Request resolved: https://github.com/facebook/react-native/pull/37850 Test Plan: - CircleCI green for the Release template jobs - Tested locally modifying the `hermes-utils` to force specific versions. - Tested locally with RNTestProject Reviewed By: dmytrorykun Differential Revision: D46687390 Pulled By: cipolleschi fbshipit-source-id: 375406e0ab351a5d1f5d5146e724f5ed0cd77949 --- .gitignore | 1 + .../scripts/cocoapods/__tests__/utils-test.rb | 23 ++-- .../react-native/scripts/cocoapods/utils.rb | 4 +- .../sdks/hermes-engine/hermes-engine.podspec | 31 ++++-- .../sdks/hermes-engine/hermes-utils.rb | 38 ++++--- .../utils/replace_hermes_version.js | 104 ++++++++++++++++++ packages/rn-tester/Podfile.lock | 82 +++++++------- 7 files changed, 212 insertions(+), 71 deletions(-) create mode 100644 packages/react-native/sdks/hermes-engine/utils/replace_hermes_version.js diff --git a/.gitignore b/.gitignore index 491d740ad1a070..5f30b988d17c85 100644 --- a/.gitignore +++ b/.gitignore @@ -21,6 +21,7 @@ DerivedData *.xcuserstate project.xcworkspace **/.xcode.env.local +/poackages/react-native/sdks/downloads/ # Gradle /build/ diff --git a/packages/react-native/scripts/cocoapods/__tests__/utils-test.rb b/packages/react-native/scripts/cocoapods/__tests__/utils-test.rb index 44fb7c6c557b38..82209f2dc1d49e 100644 --- a/packages/react-native/scripts/cocoapods/__tests__/utils-test.rb +++ b/packages/react-native/scripts/cocoapods/__tests__/utils-test.rb @@ -178,21 +178,26 @@ def test_hasPod_whenInstallerHasPod_returnTrue # Test - Set GCC Preprocessor Definition for React-hermes # # ======================================================== # - def test_SetGCCPreprocessorDefinitionForReactHermes_itSetsThePreprocessorForDebug + def test_SetGCCPreprocessorDefinitionForHermes_itSetsThePreprocessorForDebug # Arrange react_hermes_name = "React-hermes" react_core_name = "React-Core" - react_hermes_debug_config = BuildConfigurationMock.new("Debug") - react_hermes_release_config = BuildConfigurationMock.new("Release") - react_core_debug_config = BuildConfigurationMock.new("Debug") - react_core_release_config = BuildConfigurationMock.new("Release") - react_hermes_target = TargetMock.new(react_hermes_name, [react_hermes_debug_config, react_hermes_release_config]) - react_core_target = TargetMock.new(react_core_name, [react_core_debug_config, react_core_release_config]) + hermes_engine_name = "hermes-engine" + react_hermes_debug_config = BuildConfigurationMock.new("Debug") + react_hermes_release_config = BuildConfigurationMock.new("Release") + react_core_debug_config = BuildConfigurationMock.new("Debug") + react_core_release_config = BuildConfigurationMock.new("Release") + hermes_engine_debug_config = BuildConfigurationMock.new("Debug") + hermes_engine_release_config = BuildConfigurationMock.new("Release") + react_hermes_target = TargetMock.new(react_hermes_name, [react_hermes_debug_config, react_hermes_release_config]) + react_core_target = TargetMock.new(react_core_name, [react_core_debug_config, react_core_release_config]) + hermes_engine_target = TargetMock.new(hermes_engine_name, [hermes_engine_debug_config, hermes_engine_release_config]) installer = InstallerMock.new( :pod_target_installation_results => { react_hermes_name => TargetInstallationResultMock.new(react_hermes_target, react_hermes_target), react_core_name => TargetInstallationResultMock.new(react_core_target, react_core_target), + hermes_engine_name => TargetInstallationResultMock.new(hermes_engine_target, hermes_engine_target), } ) @@ -201,11 +206,13 @@ def test_SetGCCPreprocessorDefinitionForReactHermes_itSetsThePreprocessorForDebu # Assert build_setting = "GCC_PREPROCESSOR_DEFINITIONS" - expected_value = "HERMES_ENABLE_DEBUGGER=1" + expected_value = "$(inherited) HERMES_ENABLE_DEBUGGER=1" assert_equal(expected_value, react_hermes_debug_config.build_settings[build_setting]) assert_nil(react_hermes_release_config.build_settings[build_setting]) assert_nil(react_core_debug_config.build_settings[build_setting]) assert_nil(react_core_release_config.build_settings[build_setting]) + assert_equal(expected_value, hermes_engine_debug_config.build_settings[build_setting]) + assert_nil(hermes_engine_release_config.build_settings[build_setting]) end # ============================ # diff --git a/packages/react-native/scripts/cocoapods/utils.rb b/packages/react-native/scripts/cocoapods/utils.rb index 91c638f50afb4e..fc823b54e41393 100644 --- a/packages/react-native/scripts/cocoapods/utils.rb +++ b/packages/react-native/scripts/cocoapods/utils.rb @@ -41,6 +41,7 @@ def self.has_pod(installer, name) def self.set_gcc_preprocessor_definition_for_React_hermes(installer) self.add_build_settings_to_pod(installer, "GCC_PREPROCESSOR_DEFINITIONS", "HERMES_ENABLE_DEBUGGER=1", "React-hermes", "Debug") + self.add_build_settings_to_pod(installer, "GCC_PREPROCESSOR_DEFINITIONS", "HERMES_ENABLE_DEBUGGER=1", "hermes-engine", "Debug") end def self.turn_off_resource_bundle_react_core(installer) @@ -153,7 +154,8 @@ def self.add_build_settings_to_pod(installer, settings_name, settings_value, tar if pod_name.to_s == target_pod_name target_installation_result.native_target.build_configurations.each do |config| if configuration == nil || (configuration != nil && configuration == config.name) - config.build_settings[settings_name] = settings_value + config.build_settings[settings_name] ||= '$(inherited) ' + config.build_settings[settings_name] << settings_value end end end diff --git a/packages/react-native/sdks/hermes-engine/hermes-engine.podspec b/packages/react-native/sdks/hermes-engine/hermes-engine.podspec index 5be0a8d49908f8..681cb2c4d234a6 100644 --- a/packages/react-native/sdks/hermes-engine/hermes-engine.podspec +++ b/packages/react-native/sdks/hermes-engine/hermes-engine.podspec @@ -8,9 +8,6 @@ require_relative "./hermes-utils.rb" react_native_path = File.join(__dir__, "..", "..") -# Whether Hermes is built for Release or Debug is determined by the PRODUCTION envvar. -build_type = ENV['PRODUCTION'] == "1" ? :release : :debug - # package.json package = JSON.parse(File.read(File.join(react_native_path, "package.json"))) version = package['version'] @@ -23,7 +20,7 @@ git = "https://github.com/facebook/hermes.git" abort_if_invalid_tarball_provided! -source = compute_hermes_source(build_from_source, hermestag_file, git, version, build_type, react_native_path) +source = compute_hermes_source(build_from_source, hermestag_file, git, version, react_native_path) Pod::Spec.new do |spec| spec.name = "hermes-engine" @@ -42,7 +39,7 @@ Pod::Spec.new do |spec| spec.pod_target_xcconfig = { "CLANG_CXX_LANGUAGE_STANDARD" => "c++17", "CLANG_CXX_LIBRARY" => "compiler-default" - }.merge!(build_type == :debug ? { "GCC_PREPROCESSOR_DEFINITIONS" => "HERMES_ENABLE_DEBUGGER=1" } : {}) + } spec.ios.vendored_frameworks = "destroot/Library/Frameworks/ios/hermes.framework" spec.osx.vendored_frameworks = "destroot/Library/Frameworks/macosx/hermes.framework" @@ -50,7 +47,7 @@ Pod::Spec.new do |spec| if source[:http] then spec.subspec 'Pre-built' do |ss| - ss.preserve_paths = ["destroot/bin/*"].concat(build_type == :debug ? ["**/*.{h,c,cpp}"] : []) + ss.preserve_paths = ["destroot/bin/*"].concat(["**/*.{h,c,cpp}"]) ss.source_files = "destroot/include/**/*.h" ss.exclude_files = ["destroot/include/jsi/jsi/JSIDynamic.{h,cpp}", "destroot/include/jsi/jsi/jsilib-*.{h,cpp}"] ss.header_mappings_dir = "destroot/include" @@ -58,6 +55,24 @@ Pod::Spec.new do |spec| ss.osx.vendored_frameworks = "destroot/Library/Frameworks/macosx/hermes.framework" end + + # Right now, even reinstalling pods with the PRODUCTION flag turned on, does not change the version of hermes that is downloaded + # To remove the PRODUCTION flag, we want to download the right version of hermes on the flight + # we do so in a pre-build script we invoke from the Xcode build pipeline + # We use this only for Apps created using the template. RNTester and Nightlies should not be used to build for Release. + # We ignore this if we provide a specific tarball: the assumption here is that if you are providing a tarball, is because you want to + # test something specific for that tarball. + if source[:http].include?('https://repo1.maven.org/') + spec.script_phase = { + :name => "[Hermes] Replace Hermes for the right configuration, if needed", + :execution_position => :before_compile, + :script => <<-EOS + . "$REACT_NATIVE_PATH/scripts/xcode/with-environment.sh" + "$NODE_BINARY" "$REACT_NATIVE_PATH/sdks/hermes-engine/utils/replace_hermes_version.js" -c "$CONFIGURATION" -r "#{version}" -p "$REACT_NATIVE_PATH" + EOS + } + end + elsif source[:git] then spec.subspec 'Hermes' do |ss| @@ -96,7 +111,7 @@ Pod::Spec.new do |spec| { :name => '[RN] [1] Build Hermesc', :script => <<-EOS - . ${PODS_ROOT}/../.xcode.env + . "${REACT_NATIVE_PATH}/scripts/xcode/with-environment.sh" export CMAKE_BINARY=${CMAKE_BINARY:-#{CMAKE_BINARY}} . ${REACT_NATIVE_PATH}/sdks/hermes-engine/utils/build-hermesc-xcode.sh #{hermesc_path} EOS @@ -104,7 +119,7 @@ Pod::Spec.new do |spec| { :name => '[RN] [2] Build Hermes', :script => <<-EOS - . ${PODS_ROOT}/../.xcode.env + . "${REACT_NATIVE_PATH}/scripts/xcode/with-environment.sh" export CMAKE_BINARY=${CMAKE_BINARY:-#{CMAKE_BINARY}} . ${REACT_NATIVE_PATH}/sdks/hermes-engine/utils/build-hermes-xcode.sh #{version} #{hermesc_path}/ImportHermesc.cmake EOS diff --git a/packages/react-native/sdks/hermes-engine/hermes-utils.rb b/packages/react-native/sdks/hermes-engine/hermes-utils.rb index 26abc7b70761fb..1d3f501d9d3910 100644 --- a/packages/react-native/sdks/hermes-engine/hermes-utils.rb +++ b/packages/react-native/sdks/hermes-engine/hermes-utils.rb @@ -30,7 +30,7 @@ def abort_if_invalid_tarball_provided!() # - react_native_path: path to react native # # Returns: a properly configured source object -def compute_hermes_source(build_from_source, hermestag_file, git, version, build_type, react_native_path) +def compute_hermes_source(build_from_source, hermestag_file, git, version, react_native_path) source = {} if ENV.has_key?('HERMES_ENGINE_TARBALL_PATH') @@ -43,8 +43,10 @@ def compute_hermes_source(build_from_source, hermestag_file, git, version, build else build_hermes_from_source(source, git) end - elsif hermes_artifact_exists(release_tarball_url(version, build_type)) - use_release_tarball(source, version, build_type) + elsif hermes_artifact_exists(release_tarball_url(version, :debug)) + use_release_tarball(source, version, :debug) + download_stable_hermes(react_native_path, version, :debug) + download_stable_hermes(react_native_path, version, :release) elsif hermes_artifact_exists(nightly_tarball_url(version).gsub("\\", "")) use_nightly_tarball(source, react_native_path, version) else @@ -100,6 +102,25 @@ def putsIfPodPresent(message, level = 'warning') end end +def download_stable_hermes(react_native_path, version, configuration) + tarball_url = release_tarball_url(version, configuration) + download_hermes_tarball(react_native_path, tarball_url, version, configuration) +end + +def download_hermes_tarball(react_native_path, tarball_url, version, configuration) + destination_folder = "#{react_native_path}/sdks/downloads" + destination_path = configuration == nil ? + "#{destination_folder}/hermes-ios-#{version}.tar.gz" : + "#{destination_folder}/hermes-ios-#{version}-#{configuration}.tar.gz" + + unless File.exist?(destination_path) + # Download to a temporary file first so we don't cache incomplete downloads. + tmp_file = "#{destination_folder}/hermes-ios.download" + `mkdir -p "#{destination_folder}" && curl "#{tarball_url}" -Lo "#{tmp_file}" && mv "#{tmp_file}" "#{destination_path}"` + end + return destination_path +end + # This function downloads the nightly prebuilt version of Hermes based on the passed version # and save it in the node_module/react_native/sdks/downloads folder # It then returns the path to the hermes tarball @@ -110,16 +131,7 @@ def putsIfPodPresent(message, level = 'warning') # Returns: the path to the downloaded Hermes tarball def download_nightly_hermes(react_native_path, version) tarball_url = nightly_tarball_url(version) - - destination_folder = "#{react_native_path}/sdks/downloads" - destination_path = "#{destination_folder}/hermes-ios-#{version}.tar.gz" - - unless File.exist?(destination_path) - # Download to a temporary file first so we don't cache incomplete downloads. - tmp_file = "#{destination_folder}/hermes-ios.download" - `mkdir -p "#{destination_folder}" && curl "#{tarball_url}" -Lo "#{tmp_file}" && mv "#{tmp_file}" "#{destination_path}"` - end - return destination_path + return download_stable_hermes(react_native_path, tarball_url, version, nil) end def nightly_tarball_url(version) diff --git a/packages/react-native/sdks/hermes-engine/utils/replace_hermes_version.js b/packages/react-native/sdks/hermes-engine/utils/replace_hermes_version.js new file mode 100644 index 00000000000000..1ccc91b85f9e79 --- /dev/null +++ b/packages/react-native/sdks/hermes-engine/utils/replace_hermes_version.js @@ -0,0 +1,104 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @format + */ + +'use strict'; + +const yargs = require('yargs'); +const fs = require('fs'); +const {execSync} = require('child_process'); + +const LAST_BUILD_FILENAME = '.last_build_configuration'; + +function validateBuildConfiguration(configuration) { + if (!['Debug', 'Release'].includes(configuration)) { + throw new Error(`Invalid configuration ${configuration}`); + } +} + +function validateVersion(version) { + if (version == null || version === '') { + throw new Error('Version cannot be empty'); + } +} + +function shouldReplaceHermesConfiguration(configuration) { + const fileExists = fs.existsSync(LAST_BUILD_FILENAME); + + if (fileExists) { + console.log(`Found ${LAST_BUILD_FILENAME} file`); + const oldConfiguration = fs.readFileSync(LAST_BUILD_FILENAME).toString(); + if (oldConfiguration === configuration) { + console.log('No need to download a new build of Hermes!'); + return false; + } + } + + // Assumption: if there is no stored last build, we assume that it was build for debug. + if (!fs.existsSync && configuration === 'Debug') { + console.log( + 'File does not exists, but Debug configuration. No need to download a new build of Hermes!', + ); + return false; + } + + return true; +} + +function replaceHermesConfiguration(configuration, version, reactNativePath) { + const tarballURLPath = `${reactNativePath}/sdks/downloads/hermes-ios-${version}-${configuration}.tar.gz`; + + const finalLocation = 'hermes-engine'; + console.log('Preparing the final location'); + fs.rmSync(finalLocation, {force: true, recursive: true}); + fs.mkdirSync(finalLocation, {recursive: true}); + + console.log('Extracting the tarball'); + execSync(`tar -xf ${tarballURLPath} -C ${finalLocation}`); +} + +function updateLastBuildConfiguration(configuration) { + fs.writeFileSync(LAST_BUILD_FILENAME, configuration); +} + +function main(configuration, version, reactNativePath) { + validateBuildConfiguration(configuration); + validateVersion(version); + + if (!shouldReplaceHermesConfiguration(configuration)) { + return; + } + + replaceHermesConfiguration(configuration, version, reactNativePath); + updateLastBuildConfiguration(configuration); + console.log('Done replacing hermes-engine'); +} + +// This script is executed in the Pods folder, which is usually not synched to Github, so it should be ok +const argv = yargs + .option('c', { + alias: 'configuration', + description: + 'Configuration to use to download the right Hermes version. Allowed values are "Debug" and "Release".', + }) + .option('r', { + alias: 'reactNativeVersion', + description: + 'The Version of React Native associated with the Hermes tarball.', + }) + .option('p', { + alias: 'reactNativePath', + description: 'The path to the React Native root folder', + }) + .usage('Usage: $0 -c Debug -r -p ').argv; + +const configuration = argv.configuration; +const version = argv.reactNativeVersion; +const reactNativePath = argv.reactNativePath; + +main(configuration, version, reactNativePath); diff --git a/packages/rn-tester/Podfile.lock b/packages/rn-tester/Podfile.lock index a9132e6b3dd66c..75cf0dff61df6d 100644 --- a/packages/rn-tester/Podfile.lock +++ b/packages/rn-tester/Podfile.lock @@ -1242,8 +1242,8 @@ SPEC CHECKSUMS: boost: 57d2868c099736d80fcd648bf211b4431e51a558 CocoaAsyncSocket: 065fd1e645c7abab64f7a6a2007a48038fdc6a99 DoubleConversion: fea03f2699887d960129cc54bba7e52542b6f953 - FBLazyVector: 9c79ec2238e065a949c9bb7aebdf7cebd6203015 - FBReactNativeSpec: 66b1b6348a3f6c3133e6e437ad50b46f4fef812f + FBLazyVector: ca580232ba491b6601ee57bcdc874fda97a459a5 + FBReactNativeSpec: 4db5acd51db3de49e59e3740f03c94ce1282a31e Flipper: 6edb735e6c3e332975d1b17956bcc584eccf5818 Flipper-Boost-iOSX: fd1e2b8cbef7e662a122412d7ac5f5bea715403c Flipper-DoubleConversion: 2dc99b02f658daf147069aad9dbd29d8feb06d30 @@ -1254,53 +1254,53 @@ SPEC CHECKSUMS: FlipperKit: 2efad7007d6745a3f95e4034d547be637f89d3f6 fmt: ff9d55029c625d3757ed641535fd4a75fedc7ce9 glog: 99bd064df01718db56b8f75e6b5ea3051c7dad0a - hermes-engine: 6085d07261e8a8bfe708e4b0dcd0f3eae72a8e4d + hermes-engine: 4ea4b12e82d2ccfd03b29e3d9191b716b4c8f476 libevent: 4049cae6c81cdb3654a443be001fb9bdceff7913 OCMock: 9491e4bec59e0b267d52a9184ff5605995e74be8 OpenSSL-Universal: ebc357f1e6bc71fa463ccb2fe676756aff50e88c RCT-Folly: b0d1393cb3763d71efca99db314c65f0072eb0fe - RCTRequired: 40ffd795b32a630f147fcc15247920e5161b6a4e - RCTTypeSafety: fd9d941c329580ea280cad3565bb2e1656969f41 - React: 47363de0e2c161a347eef1cb57cba33f1a4b7377 - React-callinvoker: 28e99e6254975d5be67eafeedbcc3a45bb1ace94 + RCTRequired: 5394bb1f71591633e1158bdf0534206cb5ccbeb5 + RCTTypeSafety: ba46a7f654566047a9358f2e74b2eafd97ccba9b + React: 8a004085056a81c7820f65a8bc0a92e1f7ef6878 + React-callinvoker: c2b59f2cbf0d8bcdc18b33f53e097907c12a149c React-Codegen: 9ecf53f804f4d1d2a5d29bb2154e22a30c381f81 - React-Core: f2a04589df942502db2f3ef84ddc83a35a7086d3 - React-CoreModules: 4fe81e5b80d5daa3e81151dfc9e516ae1a0e575f - React-cxxreact: 1235a3b3d8ea0639f95741cc907ddbb41da4bea3 - React-debug: 9c6d0fd7867cc4a8f435d528e2c5fa8465e9c054 - React-Fabric: b429ac248d619825f97ceb607d1a2d556a49c47c - React-FabricImage: 8136841d81a7005ac3c294623f87497f6bbf8f09 - React-graphics: ed6de536e153c7bc852f9c773a3c9b21c2ee22da - React-hermes: b494c9c833faa6217b2f666d13aa52623c34c2e9 - React-ImageManager: 3e990b6ffbc7634556ddf5b90e5bb1025c397a4c - React-jsi: 00d3c30ce021ff1a074315b824b22108db01131f - React-jsiexecutor: 473c386e219c256066689a334663e8813cdc65ef - React-jsinspector: 25164fdf93d5be275ba455d916e96adb49fa407c - React-logger: a2165169d9c1897c1a139c6b158f6f79090ee174 - React-NativeModulesApple: 5ca2a6989b4549ecf557958c72d514bda071922d - React-perflogger: b5ecf879c705577c80e5299ae678b9375fe2f998 - React-RCTActionSheet: 4a241f444d11926261dd904449a31f35157d4eee - React-RCTAnimation: cf7c9f502e597ee97ce18d1bc4eb8a5836ecf21d - React-RCTAppDelegate: da46fbaa608f201a832d1310bd2e8ce4234642b1 - React-RCTBlob: 48eae02e3f75777da97e9282a5861d04471624a9 - React-RCTFabric: 4b122d0e96f6a581046b8cb950e3277036a5d45a - React-RCTImage: 3efab57255aeb986f89ddc8719fbffd4559954ad - React-RCTLinking: 708dbd9b0aa0845c735e5d6b0e9f7f268008a830 - React-RCTNetwork: d88896f8b7adf85ba366168c5bf1e03d7c235493 - React-RCTPushNotification: dbacfd181137a62deebc62fd386419e707cdcf95 - React-RCTSettings: 17cb468bba42b17b7b0e40ea971d6bd8a78baa3f - React-RCTTest: d7142acb2544c01f53deb2b0543d63df6e214ac2 - React-RCTText: 8cb3ebda2675a02de0cb363a765fafb7d6c31cc1 - React-RCTVibration: c40f0f3e0114354bbf4b418e381c2c96d1d22d48 - React-rncore: 11d8412fb1e339cd1be30aa33cb3b265b46a542b - React-runtimeexecutor: c810e5b7d7500a9ad3ed66b834503e412684936d - ReactCommon: a7972e80473d6ba9bcf3ee53bcc310ac6b944a49 - ReactCommon-Samples: 93c677b30087b6aa82bbccb4458a2028cd6ebd10 + React-Core: d730664c1ee918190a0c26bbf5c993f57e46ff5d + React-CoreModules: 390071843c203f516ec8dbc1c9ce1a815d35e908 + React-cxxreact: 39409697255baeb1ac42e436daee59913036109d + React-debug: d69fb5b4e3a47e8d5f8fdb01c1ec8983b7c1afec + React-Fabric: b19750f6cd0fae4e87173b1c2b6f9c94621b6679 + React-FabricImage: dc031099e2ae4734b70f1f66b7edf4f1cc40335a + React-graphics: e2c5d8a680cd5db24ab87756f688ecd24fd4628e + React-hermes: 4e22050b18127c27759488b703c0a9d5e6a341ba + React-ImageManager: f6792f5987f85271cbbc31e99dc16e63fd82fccb + React-jsi: 57f6f99db8d596dd599450f921b77229616e983b + React-jsiexecutor: 05d7b49ae31548ed320bb17d97bf5d648406278b + React-jsinspector: 03d477e4dd236c5411ef9a2f8c52cc2951ab6149 + React-logger: adce225eaf6d94e0e2568ba586c3f6e857fc8862 + React-NativeModulesApple: 67bb14d796e45adad89238b96a26b0f0daa5fa72 + React-perflogger: 8889aa68bda6d4cb649f890677d36c7b1eadfcd9 + React-RCTActionSheet: f5f5aa4079e8316562171fdf6346883d79fc51b1 + React-RCTAnimation: 0a3247bc23fd71f8eff8ccdb1bdeebbcb1de8af3 + React-RCTAppDelegate: 4d24c5365e3581fe22a05f0fadf5595b18d8c456 + React-RCTBlob: 484c22d88cbfc3d3441c1e54686f7793eaf30fa3 + React-RCTFabric: cd58dfa8a168d41363f84e78abe2d71d081581fb + React-RCTImage: 65ef7ecc938dea1decadd876448c47bc71e9d60b + React-RCTLinking: 100b9d0a895d95ea1e59e62375fe9b95d83fe031 + React-RCTNetwork: 710d044df7ddbe7be1ecae2608fc2ae2c5096c9a + React-RCTPushNotification: 502720de4bfd05358169c10e1ab791a794f550b0 + React-RCTSettings: f0f73ba95d32777386c294572c0e7f757bd33e08 + React-RCTTest: 6978788114214cf1f3004c04c5c2b882d9c0c0ea + React-RCTText: a64c63e34beec7c9893042a200d48accde4a406e + React-RCTVibration: e16f969546e42256468f7681d6d6ec3d2cab4524 + React-rncore: 4b86b32071e99b892eefaeee55dcec300e3e9194 + React-runtimeexecutor: 5499cb980788a75a5a474ab07b480e73f87e76b0 + ReactCommon: ed5e5ad966bbc436641a15fedb1b20dd68a2d147 + ReactCommon-Samples: cc63a8216d5e2090cc82c9427cd8d6675bef4d0f ScreenshotManager: d39b964a374e5012e2b8c143e29ead86b1da6a3c SocketRocket: fccef3f9c5cedea1353a9ef6ada904fde10d6608 - Yoga: b82f2e3cbeb3d926329278b24d54d798215d4fa3 + Yoga: 456e136b8de9c5360b609bd3238656cea243958f YogaKit: f782866e155069a2cca2517aafea43200b01fd5a PODFILE CHECKSUM: bdab6add69d555774de227d7119a8f5ae02a670e -COCOAPODS: 1.12.0 +COCOAPODS: 1.12.1