Add support for distributed registration of Fabric Components with Dynamic Libraries - #37274
Add support for distributed registration of Fabric Components with Dynamic Libraries#37274cipolleschi wants to merge 1 commit into
Conversation
|
This pull request was exported from Phabricator. Differential Revision: D45605441 |
Base commit: d8ced6f |
|
This pull request was exported from Phabricator. Differential Revision: D45605441 |
14 similar comments
|
This pull request was exported from Phabricator. Differential Revision: D45605441 |
|
This pull request was exported from Phabricator. Differential Revision: D45605441 |
|
This pull request was exported from Phabricator. Differential Revision: D45605441 |
|
This pull request was exported from Phabricator. Differential Revision: D45605441 |
|
This pull request was exported from Phabricator. Differential Revision: D45605441 |
|
This pull request was exported from Phabricator. Differential Revision: D45605441 |
|
This pull request was exported from Phabricator. Differential Revision: D45605441 |
|
This pull request was exported from Phabricator. Differential Revision: D45605441 |
|
This pull request was exported from Phabricator. Differential Revision: D45605441 |
|
This pull request was exported from Phabricator. Differential Revision: D45605441 |
|
This pull request was exported from Phabricator. Differential Revision: D45605441 |
|
This pull request was exported from Phabricator. Differential Revision: D45605441 |
|
This pull request was exported from Phabricator. Differential Revision: D45605441 |
|
This pull request was exported from Phabricator. Differential Revision: D45605441 |
…namic Libraries (#37274) Summary: Pull Request resolved: #37274 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. Reviewed By: dmytrorykun Differential Revision: D45605441 fbshipit-source-id: 0140cde491cd0823d056a8a35faf8710ef81f552
|
This pull request was exported from Phabricator. Differential Revision: D45605441 |
|
This pull request has been merged in b6b09a7. |
## PR concerning New Architecture support in the library 🎉 We at [Software Mansion](https://swmansion.com/) have been working on [improving support](https://blog.swmansion.com/sunrising-new-architecture-in-the-new-expensify-app-729d237a02f5) for the new architecture for quite a while now. If you need help with anything related to New Architecture, like: - [migrating your library](https://x.com/swmansion/status/1717512089323864275) - [migrating your app](Expensify/App#13767) - [investigating issues](https://github.com/facebook/react-native/pulls?q=sort%3Aupdated-desc+is%3Apr+author%3Aj-piasecki+is%3Aopen) - [improving performance](https://x.com/BBloniarz_/status/1808138585528303977) or you just want to ask any questions, hit us up on [projects@swmansion.com](mailto:projects@swmansion.com) --- ## Summary <!-- Simple summary of what was changed. --> PR adding `load` method needed for dynamic frameworks to work with the library. See react/react-native#37274 for more information.
## PR concerning New Architecture support in the library 🎉 We at [Software Mansion](https://swmansion.com/) have been working on [improving support](https://blog.swmansion.com/sunrising-new-architecture-in-the-new-expensify-app-729d237a02f5) for the new architecture for quite a while now. If you need help with anything related to New Architecture, like: - [migrating your library](https://x.com/swmansion/status/1717512089323864275) - [migrating your app](Expensify/App#13767) - [investigating issues](https://github.com/facebook/react-native/pulls?q=sort%3Aupdated-desc+is%3Apr+author%3Aj-piasecki+is%3Aopen) - [improving performance](https://x.com/BBloniarz_/status/1808138585528303977) or you just want to ask any questions, hit us up on [projects@swmansion.com](mailto:projects@swmansion.com) --- ## Summary <!-- Simple summary of what was changed. --> PR adding `load` method needed for dynamic frameworks to work with the library. See react/react-native#37274 for more information.
PR adding load method needed for dynamic frameworks to work with the library. See react/react-native#37274 for more information.
PR adding `load` method needed for dynamic frameworks to work with the library. See react/react-native#37274 for more information.
PR adding load method needed for dynamic frameworks to work with the library. See react/react-native#37274 for more information.
PR adding load method needed for dynamic frameworks to work with the library. See react/react-native#37274 for more information. (cherry picked from commit 29c98e2)
## Description <!-- Description and motivation for this PR. Include Fixes #<number> if this is fixing some issue. --> Fixes #2652 The `RNSFullWindowOverlay` component was not used with dynamic frameworks, leading to the incorrect use of a placeholder component. As highlighted in [this React Native PR](react/react-native#37274), all Fabric components must implement the `load` method to be correctly resolved. Although `RNSFullWindowOverlay.mm` already included this method, it was mistakenly placed in `RNSFullWindowOverlayContainer` instead of `RNSFullWindowOverlay`, where it should have been implemented. After correcting this placement, the reported issue is no longer reproducible 🎉. ## Changes <!-- Please describe things you've changed here, make a **high level** overview, if change is simple you can omit this section. For example: --> - moved `load` method from `RNSFullWindowOverlayContainer` to `RNSFullWindowOverlay` class ## Screenshots / GIFs ### Before  ### After  ## Test code and steps to reproduce <!-- Please include code that can be used to test this change and short description how this example should work. This snippet should be as minimal as possible and ready to be pasted into editor (don't exclude exports or remove "not important" parts of reproduction example) --> ## Checklist - [x] Included code example that can be used to test this change - [ ] Updated TS types - [ ] Updated documentation: <!-- For adding new props to native-stack --> - [ ] https://github.com/software-mansion/react-native-screens/blob/main/guides/GUIDE_FOR_LIBRARY_AUTHORS.md - [ ] https://github.com/software-mansion/react-native-screens/blob/main/native-stack/README.md - [ ] https://github.com/software-mansion/react-native-screens/blob/main/src/types.tsx - [ ] https://github.com/software-mansion/react-native-screens/blob/main/src/native-stack/types.tsx - [ ] Ensured that CI passes Co-authored-by: war-in <war-in@users.noreply.github.com>
## Description <!-- Description and motivation for this PR. Include Fixes #<number> if this is fixing some issue. --> Fixes #2652 The `RNSFullWindowOverlay` component was not used with dynamic frameworks, leading to the incorrect use of a placeholder component. As highlighted in [this React Native PR](react/react-native#37274), all Fabric components must implement the `load` method to be correctly resolved. Although `RNSFullWindowOverlay.mm` already included this method, it was mistakenly placed in `RNSFullWindowOverlayContainer` instead of `RNSFullWindowOverlay`, where it should have been implemented. After correcting this placement, the reported issue is no longer reproducible 🎉. ## Changes <!-- Please describe things you've changed here, make a **high level** overview, if change is simple you can omit this section. For example: --> - moved `load` method from `RNSFullWindowOverlayContainer` to `RNSFullWindowOverlay` class ## Screenshots / GIFs ### Before  ### After  ## Test code and steps to reproduce <!-- Please include code that can be used to test this change and short description how this example should work. This snippet should be as minimal as possible and ready to be pasted into editor (don't exclude exports or remove "not important" parts of reproduction example) --> ## Checklist - [x] Included code example that can be used to test this change - [ ] Updated TS types - [ ] Updated documentation: <!-- For adding new props to native-stack --> - [ ] https://github.com/software-mansion/react-native-screens/blob/main/guides/GUIDE_FOR_LIBRARY_AUTHORS.md - [ ] https://github.com/software-mansion/react-native-screens/blob/main/native-stack/README.md - [ ] https://github.com/software-mansion/react-native-screens/blob/main/src/types.tsx - [ ] https://github.com/software-mansion/react-native-screens/blob/main/src/native-stack/types.tsx - [ ] Ensured that CI passes Co-authored-by: war-in <war-in@users.noreply.github.com> (cherry picked from commit abb1e36)
PR adding load method needed for dynamic frameworks to work with the library. See react/react-native#37274 for more information.
The +load method in RNGestureHandlerButtonComponentView is unconditional, but its parent RCTViewComponentView correctly guards its +load behind #ifdef RCT_DYNAMIC_FRAMEWORKS. Without the guard, the child's +load runs even when dynamic frameworks are not used, causing conflicts with third-party SDKs (e.g. Akamai BMP) that also use +load — particularly on x86_64 simulators where the load order differs from arm64. This matches the pattern used by React Native core in RCTViewComponentView.mm (see react/react-native#37274).
The +load methods in RNCSafeAreaProviderComponentView and RNCSafeAreaViewComponentView are unconditional, but their parent RCTViewComponentView correctly guards its +load behind #ifdef RCT_DYNAMIC_FRAMEWORKS. Without the guard, these +load methods run even when dynamic frameworks are not used, causing conflicts with third-party SDKs (e.g. Akamai BMP) that also use +load — particularly on x86_64 simulators where the load order differs from arm64. This matches the pattern used by React Native core in RCTViewComponentView.mm (see react/react-native#37274).
The +load methods in 12 ComponentView files are unconditional, but their parent RCTViewComponentView correctly guards its +load behind #ifdef RCT_DYNAMIC_FRAMEWORKS. Without the guard, these +load methods run even when dynamic frameworks are not used, causing conflicts with third-party SDKs (e.g. Akamai BMP) that also use +load — particularly on x86_64 simulators where the load order differs from arm64. This matches the pattern used by React Native core in RCTViewComponentView.mm (see react/react-native#37274). Note: UIViewController+RNScreens.mm is intentionally NOT changed as its +load performs method swizzling that is functionally required.
## Summary The `+load` method in `RNGestureHandlerButtonComponentView` is unconditional, but its parent `RCTViewComponentView` correctly guards its `+load` behind `#ifdef RCT_DYNAMIC_FRAMEWORKS`. Without the guard, the child's `+load` runs even when dynamic frameworks are not used, causing conflicts with third-party SDKs (e.g. Akamai BMP) that also use `+load` — particularly on x86_64 simulators where the load order differs from arm64. This matches the pattern used by React Native core in `RCTViewComponentView.mm` (see react/react-native#37274). ## Test plan - Build xcframework with static linking (no `USE_FRAMEWORKS=dynamic`) - Verify `RNGestureHandlerButtonComponentView +load` is not in the binary (`nm` check) - Run on x86_64 simulator alongside Akamai BMP — no crash at launch - Run on arm64 simulator — gesture handler works normally
## Summary The `+load` method in `RNGestureHandlerButtonComponentView` is unconditional, but its parent `RCTViewComponentView` correctly guards its `+load` behind `#ifdef RCT_DYNAMIC_FRAMEWORKS`. Without the guard, the child's `+load` runs even when dynamic frameworks are not used, causing conflicts with third-party SDKs (e.g. Akamai BMP) that also use `+load` — particularly on x86_64 simulators where the load order differs from arm64. This matches the pattern used by React Native core in `RCTViewComponentView.mm` (see react/react-native#37274). ## Test plan - Build xcframework with static linking (no `USE_FRAMEWORKS=dynamic`) - Verify `RNGestureHandlerButtonComponentView +load` is not in the binary (`nm` check) - Run on x86_64 simulator alongside Akamai BMP — no crash at launch - Run on arm64 simulator — gesture handler works normally
## Summary The `+load` method in `RNGestureHandlerButtonComponentView` is unconditional, but its parent `RCTViewComponentView` correctly guards its `+load` behind `#ifdef RCT_DYNAMIC_FRAMEWORKS`. Without the guard, the child's `+load` runs even when dynamic frameworks are not used, causing conflicts with third-party SDKs (e.g. Akamai BMP) that also use `+load` — particularly on x86_64 simulators where the load order differs from arm64. This matches the pattern used by React Native core in `RCTViewComponentView.mm` (see react/react-native#37274). ## Test plan - Build xcframework with static linking (no `USE_FRAMEWORKS=dynamic`) - Verify `RNGestureHandlerButtonComponentView +load` is not in the binary (`nm` check) - Run on x86_64 simulator alongside Akamai BMP — no crash at launch - Run on arm64 simulator — gesture handler works normally Co-authored-by: m-bert <63123542+m-bert@users.noreply.github.com>
The +load methods in 12 ComponentView files are unconditional, but their parent RCTViewComponentView correctly guards its +load behind #ifdef RCT_DYNAMIC_FRAMEWORKS. Without the guard, these +load methods run even when dynamic frameworks are not used, causing conflicts with third-party SDKs (e.g. Akamai BMP) that also use +load — particularly on x86_64 simulators where the load order differs from arm64. This matches the pattern used by React Native core in RCTViewComponentView.mm (see react/react-native#37274). Note: UIViewController+RNScreens.mm is intentionally NOT changed as its +load performs method swizzling that is functionally required.
The +load methods in 12 ComponentView files are unconditional, but their parent RCTViewComponentView correctly guards its +load behind run even when dynamic frameworks are not used, causing conflicts with third-party SDKs (e.g. Akamai BMP) that also use +load — particularly on x86_64 simulators where the load order differs from arm64. This matches the pattern used by React Native core in RCTViewComponentView.mm (see react/react-native#37274). Note: UIViewController+RNScreens.mm is intentionally NOT changed as its +load performs method swizzling that is functionally required.
## Summary
12 ComponentView files had unconditional `+load { [super load]; }`
methods, but their parent `RCTViewComponentView` correctly guards its
`+load` behind `#ifdef RCT_DYNAMIC_FRAMEWORKS`.
Without the guard, these `+load` methods run even when dynamic
frameworks are not used, causing conflicts with third-party SDKs (e.g.
Akamai BMP) that also use `+load` — particularly on x86_64 simulators
where the load order differs from arm64.
This matches the pattern used by React Native core in
`RCTViewComponentView.mm` (see react/react-native#37274).
**Note:** `UIViewController+RNScreens.mm` is intentionally NOT changed
as its `+load` performs method swizzling that is functionally required.
### Changes
1. **Guarded existing `+load` methods** — wrapped 12 existing
unconditional `+load` calls with `#ifdef RCT_DYNAMIC_FRAMEWORKS`.
2. **Added missing guarded `+load` methods** — 9 additional
ComponentView files (gamma, tabs) were missing `+load` entirely, which
would break component registration when using dynamic frameworks. Added
guarded `+load` to these files.
3. **Relocated `+load` to end of `@implementation`** — moved all `+load`
methods to a dedicated `#pragma mark - Dynamic frameworks support`
section just before `@end` for consistency and readability.
4. **Normalized `#endif` comments** — ensured all `#endif` directives
have consistent trailing comments (e.g. `#endif //
RCT_DYNAMIC_FRAMEWORKS`).
### Affected files
**Existing `+load` guarded (12 files):**
- `RNSScreen.mm`
- `RNSScreenStack.mm`
- `RNSScreenContainer.mm`
- `RNSScreenNavigationContainer.mm`
- `RNSModalScreen.mm`
- `RNSFullWindowOverlay.mm`
- `RNSScreenFooter.mm`
- `RNSSafeAreaViewComponentView.mm`
- `RNSSearchBar.mm`
- `RNSScreenContentWrapper.mm`
- `RNSScreenStackHeaderConfig.mm`
- `RNSScreenStackHeaderSubview.mm`
**New guarded `+load` added (9 files):**
- `RNSScrollViewMarkerComponentView.mm`
- `RNSSplitHostComponentView.mm`
- `RNSSplitScreenComponentView.mm`
- `RNSStackHostComponentView.mm`
- `RNSStackScreenComponentView.mm`
- `RNSTabsHostComponentView.mm`
- `RNSTabsScreenComponentView.mm`
- `RNSTabsBottomAccessoryComponentView.mm`
- `RNSTabsBottomAccessoryContentComponentView.mm`
## Test plan
- Build xcframework with static linking (no `USE_FRAMEWORKS=dynamic`)
- Verify ComponentView `+load` methods are not in the binary (`nm`
check)
- Run on x86_64 simulator alongside Akamai BMP — no crash at launch
- Run on arm64 simulator — screens navigation works normally
---------
Co-authored-by: Kacper Kafara <kacperkafara@gmail.com>
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
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