Skip to content

Commit c884d19

Browse files
blakeffacebook-github-bot
authored andcommitted
Moved @react-native-community script internally into react-native/scripts
Summary: This decouples the listing of modules from the linking of those modules into Cocoapods. I've made this backwards compatible, but our internal template wont lean on the community config. The user can now override how they capture a list of React Native modules, providing an escape hatch for Framework authors to build on. Changelog: [General][iOS] Use our fork of the react-native-communti/cli-platform-ios use_native_modues.rb script Reviewed By: cipolleschi Differential Revision: D56242486 fbshipit-source-id: 78505669ab6abd6718348388c3bfba3290f7071b
1 parent ff094d8 commit c884d19

File tree

4 files changed

+231
-18
lines changed

4 files changed

+231
-18
lines changed
Lines changed: 204 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,204 @@
1+
# Copyright (c) Meta Platforms, Inc. and affiliates.
2+
#
3+
# This source code is licensed under the MIT license found in the
4+
# LICENSE file in the root directory of this source tree.
5+
6+
require 'json'
7+
require 'pathname'
8+
require 'cocoapods'
9+
require_relative './autolinking_utils.rb'
10+
11+
# Your project will have to depend on the @react-native-community/cli if you use this method
12+
# for listing React native modules.
13+
#
14+
# Parameters:
15+
# - config_command: the command to run to get the application's current config, e.g. ['npx', '@react-native-community/cli', 'config']
16+
def list_native_modules!(config_command)
17+
18+
if !(config_command.is_a? Array and config_command.size > 0)
19+
Pod::UI.warn "Expected a list_native_modules! to be called with a config command", [
20+
"Unable to autolink if no config is provided for the current project."
21+
]
22+
exit(1)
23+
end
24+
25+
# Ignore stderr output, we're only interested in stdout and the return code. Libraries can output warnings to
26+
# stderr which create problems for JSON deserializing.
27+
json, _, status = Pod::Executable.capture_command(config_command[0], config_command[1..], capture: :both)
28+
29+
if not status.success?
30+
Pod::UI.warn "The command: '#{config_command.join(" ").bold.yellow}' returned a status code of #{status.exitstatus.to_s.bold.red}", [
31+
"In order to autolink using Cocoapods, this framework uses @react-native-community/cli to discover React Native native modules",
32+
"Please either add it: yarn add -D @react-native-community/cli or consult your framework's documentation."
33+
]
34+
exit(status.exitstatus)
35+
end
36+
37+
config = JSON.parse(json)
38+
39+
packages = config["dependencies"]
40+
ios_project_root = Pathname.new(config["project"]["ios"]["sourceDir"])
41+
react_native_path = Pathname.new(config["reactNativePath"])
42+
found_pods = []
43+
44+
packages.each do |package_name, package|
45+
next unless package_config = package["platforms"]["ios"]
46+
47+
name = package["name"]
48+
podspec_path = package_config["podspecPath"]
49+
script_phases = package_config["scriptPhases"]
50+
configurations = package_config["configurations"]
51+
52+
# Add a warning to the queue and continue to the next dependency if the podspec_path is nil/empty
53+
if podspec_path.nil? || podspec_path.empty?
54+
Pod::UI.warn("list_native_modules! skipped the react-native dependency '#{name}'. No podspec file was found.",
55+
[
56+
"Check to see if there is an updated version that contains the necessary podspec file",
57+
"Contact the library maintainers or send them a PR to add a podspec. The react-native-webview podspec is a good example of a package.json driven podspec. See https://github.com/react-native-community/react-native-webview/blob/master/react-native-webview.podspec",
58+
"If necessary, you can disable autolinking for the dependency and link it manually. See https://github.com/react-native-community/cli/blob/main/docs/autolinking.md#how-can-i-disable-autolinking-for-unsupported-library"
59+
])
60+
next
61+
end
62+
63+
spec = Pod::Specification.from_file(podspec_path)
64+
65+
# Skip pods that do not support the platform of the current target.
66+
next unless AutolinkingUtils.is_platform_supported?(current_target_definition, spec)
67+
68+
podspec_dir_path = Pathname.new(File.dirname(podspec_path))
69+
70+
relative_path = podspec_dir_path.relative_path_from ios_project_root
71+
72+
found_pods.push({
73+
"configurations": configurations,
74+
"name": name,
75+
"path": relative_path.to_path,
76+
"podspec_path": podspec_path,
77+
"script_phases": script_phases
78+
})
79+
end
80+
81+
if found_pods.size > 0
82+
pods = found_pods.map { |p| p[:name] }.sort.to_sentence
83+
Pod::UI.puts "Found #{found_pods.size} #{"module".pluralize(found_pods.size)} for target `#{current_target_definition.name}`"
84+
end
85+
86+
return {
87+
"ios_packages": found_pods,
88+
"ios_project_root_path": ios_project_root.to_s,
89+
"react_native_path": react_native_path.relative_path_from(ios_project_root).to_s
90+
}
91+
end
92+
93+
# Your project will have to depend on the @react-native-community/cli if you use this method
94+
# for listing React native modules.
95+
#
96+
# Parameters:
97+
# - config:
98+
# - :ios_packages - Array of React Native iOS packages, e.g. [{ package_name: "Foo", package: { .. }}, ...]
99+
# - :ios_project_root_path - Absolute path to the react_native project's ios folder, e.g. /Users/foobar/project/rn_project/ios
100+
# - :react_native_path - Relative path to the react_native from the project, e.g. ./node_modules/react-native
101+
def link_native_modules!(config)
102+
Pod::UI.puts "link_native_modules! #{config}"
103+
104+
if !(
105+
config[:ios_packages].is_a? Array and
106+
config[:ios_project_root_path].is_a? String and
107+
config[:react_native_path].is_a? String
108+
)
109+
Pod::UI.warn("link_native_modules! has been called with a malformed 'config' parameter",
110+
[
111+
"This is the config argument passed: #{config.inspect}",
112+
]);
113+
exit(1)
114+
end
115+
116+
ios_project_root = config[:ios_project_root_path]
117+
118+
packages = config[:ios_packages]
119+
found_pods = []
120+
121+
packages.each do |package|
122+
podspec_path = package[:podspec_path]
123+
configurations = package[:configurations]
124+
125+
# Add a warning to the queue and continue to the next dependency if the podspec_path is nil/empty
126+
if podspec_path.nil? || podspec_path.empty?
127+
Pod::UI.warn("use_native_modules! skipped the react-native dependency '#{package[:name]}'. No podspec file was found.",
128+
[
129+
"Check to see if there is an updated version that contains the necessary podspec file",
130+
"Contact the library maintainers or send them a PR to add a podspec. The react-native-webview podspec is a good example of a package.json driven podspec. See https://github.com/react-native-community/react-native-webview/blob/master/react-native-webview.podspec",
131+
"If necessary, you can disable autolinking for the dependency and link it manually. See https://github.com/react-native-community/cli/blob/main/docs/autolinking.md#how-can-i-disable-autolinking-for-unsupported-library"
132+
])
133+
next
134+
end
135+
136+
spec = Pod::Specification.from_file(podspec_path)
137+
138+
# Don't try track packages that exclude our platforms
139+
next unless AutolinkingUtils.is_platform_supported?(current_target_definition, spec)
140+
141+
# We want to do a look up inside the current CocoaPods target
142+
# to see if it's already included, this:
143+
# 1. Gives you the chance to define it beforehand
144+
# 2. Ensures CocoaPods won't explode if it's included twice
145+
#
146+
this_target = current_target_definition
147+
existing_deps = current_target_definition.dependencies
148+
149+
# Skip dependencies that the user already activated themselves.
150+
next if existing_deps.find do |existing_dep|
151+
existing_dep.name.split('/').first == spec.name
152+
end
153+
154+
podspec_dir_path = Pathname.new(File.dirname(podspec_path))
155+
156+
relative_path = podspec_dir_path.relative_path_from ios_project_root
157+
158+
# Register the found React Native module into our collection of Pods.
159+
pod spec.name, :path => relative_path.to_path, :configurations => configurations
160+
161+
if package[:script_phases] && !this_target.abstract?
162+
# Can be either an object, or an array of objects
163+
Array(package[:script_phases]).each do |phase|
164+
# see https://www.rubydoc.info/gems/cocoapods-core/Pod/Podfile/DSL#script_phase-instance_method
165+
# for the full object keys
166+
Pod::UI.puts "Adding a custom script phase for Pod #{spec.name}: #{phase["name"] || 'No name specified.'}"
167+
168+
# Support passing in a path relative to the root of the package
169+
if phase["path"]
170+
phase["script"] = File.read(File.expand_path(phase["path"], package["root"]))
171+
phase.delete("path")
172+
end
173+
174+
# Support converting the execution position into a symbol
175+
phase["execution_position"] = phase["execution_position"]&.to_sym
176+
177+
phase = Hash[phase.map { |k, v| [k.to_sym, v] }]
178+
script_phase phase
179+
end
180+
end
181+
182+
found_pods.push spec
183+
end
184+
185+
if found_pods.size > 0
186+
pods = found_pods.map { |p| p.name }.sort.to_sentence
187+
Pod::UI.puts "Auto-linking React Native #{"module".pluralize(found_pods.size)} for target `#{current_target_definition.name}`: #{pods}"
188+
end
189+
190+
return {
191+
:reactNativePath => config[:react_native_path]
192+
}
193+
end
194+
195+
$default_command = ['node', '-e', "process.argv=['', '', 'config'];require('@react-native-community/cli').run()"];
196+
197+
# Autolink your native modules
198+
#
199+
# Parameters:
200+
# - config_command: the command to run to get the application's current config, e.g. ['npx', '@react-native-community/cli', 'config'],
201+
# you can override this if you'd like to avoid the dependency. e.g. ['cat', 'your_config.json']
202+
def use_native_modules!(config_command = $default_command)
203+
return link_native_modules!(list_native_modules!(config_command))
204+
end
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# Copyright (c) Meta Platforms, Inc. and affiliates.
2+
#
3+
# This source code is licensed under the MIT license found in the
4+
# LICENSE file in the root directory of this source tree.
5+
6+
class AutolinkingUtils
7+
8+
def self.nested_path_exists?(object, *path)
9+
path.reduce(object) do |obj, method|
10+
return false unless obj.respond_to?(method)
11+
obj.public_send(method)
12+
end
13+
return true
14+
end
15+
16+
def self.is_platform_supported?(current_target_definition, spec)
17+
platform = current_target_definition.platform
18+
if !platform
19+
# Historically we've supported platforms that aren't specifically excluded.
20+
return true
21+
end
22+
return spec.supported_on_platform?(platform.name)
23+
end
24+
25+
end

packages/react-native/scripts/native_modules.rb

Lines changed: 0 additions & 6 deletions
This file was deleted.

packages/react-native/scripts/react_native_pods.rb

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -16,25 +16,15 @@
1616
require_relative './cocoapods/local_podspec_patch.rb'
1717
require_relative './cocoapods/runtime.rb'
1818
require_relative './cocoapods/helpers.rb'
19+
# Importing to expose use_native_modules!
20+
require_relative './cocoapods/autolinking.rb'
1921

2022
$CODEGEN_OUTPUT_DIR = 'build/generated/ios'
2123
$CODEGEN_COMPONENT_DIR = 'react/renderer/components'
2224
$CODEGEN_MODULE_DIR = '.'
2325

2426
$START_TIME = Time.now.to_i
2527

26-
# `@react-native-community/cli-platform-ios/native_modules` defines
27-
# use_native_modules. We use node to resolve its path to allow for
28-
# different packager and workspace setups. This is reliant on
29-
# `@react-native-community/cli-platform-ios` being a direct dependency
30-
# of `react-native`.
31-
require Pod::Executable.execute_command('node', ['-p',
32-
'require.resolve(
33-
"@react-native-community/cli-platform-ios/native_modules.rb",
34-
{paths: [process.argv[1]]},
35-
)', __dir__]).strip
36-
37-
3828
def min_ios_version_supported
3929
return Helpers::Constants.min_ios_version_supported
4030
end

0 commit comments

Comments
 (0)