Skip to content

Commit 80b4479

Browse files
cipolleschifacebook-github-bot
authored andcommitted
Add support for distributed registration of Fabric Components with Dynamic Libraries
Summary: With dynamic frameworks, we can't use floating C functions. The way in which dynamic frameworks work is that they need to be self contained. They are built in isolation so that other frameworks can be linked against them to solve their dependencies. Currently, when working with 3rd party libraries, we are Codegenerating a RCTThirdPartyComponentProvider which tries to invoke floating C functions that are defined in other modules. React-RCTFabric has no visibility on those modules, therefore it fails building. The implemented solution exclude the generation of those symbols and leverage a the Objective-C runtime to automatically register libraries when they are loaded. **This mechanism is applied ONLY when the flag RCT_DYNAMIC_FRAMEWORKS is turned on.** There will be no impact on internal meta apps, nor on any apps that are not using Dynamic Frameworks. This change requires a small migration in all the Fabric components libraries that wants to support dynamic frameworks. They have to implement a ``` + (void)load { [super load]; } ``` method in their ComponentView. Not to slow down the adoption of the new architecture, waiting for a migration in the ecosystem, the next diff introduce a secondary, declarative loading mechanism for Fabric Components, which follows the same approach used by TurboModules. ## Changelog: [iOS][Changed] - Add support for distributed registration of Fabric Components with Dynamic Libraries. Notes that this change is NOT breaking as dynamic frameworks were not working before in the New Architecture. Static Libraries and Static Frameworks continue working as usual. Differential Revision: D45605441 fbshipit-source-id: 6ff81fe5af8763c19b86d7b04761c556fac51e79
1 parent 39b74af commit 80b4479

File tree

7 files changed

+40
-0
lines changed

7 files changed

+40
-0
lines changed

packages/react-native-codegen/src/generators/components/GenerateThirdPartyFabricComponentsProviderH.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,12 @@ extern "C" {
3636
3737
Class<RCTComponentViewProtocol> RCTThirdPartyFabricComponentsProvider(const char *name);
3838
39+
#ifndef RCT_DYNAMIC_FRAMEWORKS
40+
3941
${lookupFuncs}
4042
43+
#endif
44+
4145
#ifdef __cplusplus
4246
}
4347
#endif

packages/react-native-codegen/src/generators/components/GenerateThirdPartyFabricComponentsProviderObjCpp.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,9 @@ const FileTemplate = ({lookupMap}: {lookupMap: string}) => `
3434
3535
Class<RCTComponentViewProtocol> RCTThirdPartyFabricComponentsProvider(const char *name) {
3636
static std::unordered_map<std::string, Class (*)(void)> sFabricComponentsClassMap = {
37+
#ifndef RCT_DYNAMIC_FRAMEWORKS
3738
${lookupMap}
39+
#endif
3840
};
3941
4042
auto p = sFabricComponentsClassMap.find(name);

packages/react-native-codegen/src/generators/components/__tests__/__snapshots__/GenerateThirdPartyFabricComponentsProviderH-test.js.snap

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ extern \\"C\\" {
2323
2424
Class<RCTComponentViewProtocol> RCTThirdPartyFabricComponentsProvider(const char *name);
2525
26+
#ifndef RCT_DYNAMIC_FRAMEWORKS
27+
2628
Class<RCTComponentViewProtocol> NoPropsNoEventsComponentCls(void) __attribute__((used)); // NO_PROPS_NO_EVENTS
2729
Class<RCTComponentViewProtocol> InterfaceOnlyComponentCls(void) __attribute__((used)); // INTERFACE_ONLY
2830
Class<RCTComponentViewProtocol> BooleanPropNativeComponentCls(void) __attribute__((used)); // BOOLEAN_PROP
@@ -55,6 +57,8 @@ Class<RCTComponentViewProtocol> ExcludedAndroidComponentCls(void) __attribute__(
5557
5658
Class<RCTComponentViewProtocol> MultiFileIncludedNativeComponentCls(void) __attribute__((used)); // EXCLUDE_IOS_TWO_COMPONENTS_DIFFERENT_FILES
5759
60+
#endif
61+
5862
#ifdef __cplusplus
5963
}
6064
#endif

packages/react-native-codegen/src/generators/components/__tests__/__snapshots__/GenerateThirdPartyFabricComponentsProviderObjCpp-test.js.snap

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ Map {
2121
2222
Class<RCTComponentViewProtocol> RCTThirdPartyFabricComponentsProvider(const char *name) {
2323
static std::unordered_map<std::string, Class (*)(void)> sFabricComponentsClassMap = {
24+
#ifndef RCT_DYNAMIC_FRAMEWORKS
2425
2526
{\\"NoPropsNoEventsComponent\\", NoPropsNoEventsComponentCls}, // NO_PROPS_NO_EVENTS
2627
@@ -80,6 +81,7 @@ Class<RCTComponentViewProtocol> RCTThirdPartyFabricComponentsProvider(const char
8081
8182
8283
{\\"MultiFileIncludedNativeComponent\\", MultiFileIncludedNativeComponentCls}, // EXCLUDE_IOS_TWO_COMPONENTS_DIFFERENT_FILES
84+
#endif
8385
};
8486
8587
auto p = sFabricComponentsClassMap.find(name);

packages/react-native/React/Fabric/Mounting/ComponentViews/View/RCTViewComponentView.mm

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
#import <React/RCTAssert.h>
1515
#import <React/RCTBorderDrawing.h>
16+
#import <React/RCTComponentViewFactory.h>
1617
#import <React/RCTConversions.h>
1718
#import <react/renderer/components/view/ViewComponentDescriptor.h>
1819
#import <react/renderer/components/view/ViewEventEmitter.h>
@@ -30,6 +31,13 @@ @implementation RCTViewComponentView {
3031
NSSet<NSString *> *_Nullable _propKeysManagedByAnimated_DO_NOT_USE_THIS_IS_BROKEN;
3132
}
3233

34+
#ifdef RCT_DYNAMIC_FRAMEWORKS
35+
+ (void)load
36+
{
37+
[RCTComponentViewFactory.currentComponentViewFactory registerComponentViewClass:self];
38+
}
39+
#endif
40+
3341
- (instancetype)initWithFrame:(CGRect)frame
3442
{
3543
if (self = [super initWithFrame:frame]) {

packages/react-native/scripts/cocoapods/new_architecture.rb

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,17 @@ def self.modify_flags_for_new_architecture(installer, is_new_arch_enabled)
6767
end
6868
end
6969

70+
# Set "RCT_DYNAMIC_FRAMEWORKS=1" if pod are installed with USE_FRAMEWORKS=dynamic
71+
# This helps with backward compatibility.
72+
if pod_name == 'React-RCTFabric' && ENV['USE_FRAMEWORKS'] == 'dynamic'
73+
Pod::UI.puts "Adding RCT_DYNAMIC_FRAMEWORKS=1 to React-RCTFabric".yellow
74+
rct_dynamic_framework_flag = " -DRCT_DYNAMIC_FRAMEWORKS=1"
75+
target_installation_result.native_target.build_configurations.each do |config|
76+
prev_build_settings = config.build_settings['OTHER_CPLUSPLUSFLAGS'] != nil ? config.build_settings['OTHER_CPLUSPLUSFLAGS'] : "$(inherithed)"
77+
config.build_settings['OTHER_CPLUSPLUSFLAGS'] = prev_build_settings + rct_dynamic_framework_flag
78+
end
79+
end
80+
7081
target_installation_result.native_target.build_configurations.each do |config|
7182
if config.name == "Release"
7283
current_flags = config.build_settings['OTHER_CPLUSPLUSFLAGS'] != nil ? config.build_settings['OTHER_CPLUSPLUSFLAGS'] : "$(inherited)"

packages/rn-tester/NativeComponentExample/ios/RNTMyNativeViewComponentView.mm

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
#import "RNTMyNativeViewComponentView.h"
99

10+
#import <React/RCTComponentViewFactory.h>
1011
#import <react/renderer/components/AppSpecs/ComponentDescriptors.h>
1112
#import <react/renderer/components/AppSpecs/EventEmitters.h>
1213
#import <react/renderer/components/AppSpecs/Props.h>
@@ -28,6 +29,14 @@ + (ComponentDescriptorProvider)componentDescriptorProvider
2829
return concreteComponentDescriptorProvider<RNTMyNativeViewComponentDescriptor>();
2930
}
3031

32+
// Load is not invoked if it is not defined, therefore, we must ask to update this.
33+
// See the Apple documentation: https://developer.apple.com/documentation/objectivec/nsobject/1418815-load?language=objc
34+
// "[...] but only if the newly loaded class or category implements a method that can respond."
35+
+ (void)load
36+
{
37+
[super load];
38+
}
39+
3140
- (instancetype)initWithFrame:(CGRect)frame
3241
{
3342
if (self = [super initWithFrame:frame]) {

0 commit comments

Comments
 (0)