Skip to content

Add support for distributed registration of Fabric Components with Dynamic Libraries - #37274

Closed
cipolleschi wants to merge 1 commit into
react:mainfrom
cipolleschi:export-D45605441
Closed

Add support for distributed registration of Fabric Components with Dynamic Libraries#37274
cipolleschi wants to merge 1 commit into
react:mainfrom
cipolleschi:export-D45605441

Conversation

@cipolleschi

Copy link
Copy Markdown
Contributor

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

@facebook-github-bot facebook-github-bot added CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. p: Facebook Partner: Facebook Partner fb-exported labels May 5, 2023
@facebook-github-bot

Copy link
Copy Markdown
Contributor

This pull request was exported from Phabricator. Differential Revision: D45605441

@analysis-bot

analysis-bot commented May 5, 2023

Copy link
Copy Markdown
Platform Engine Arch Size (bytes) Diff
android hermes arm64-v8a 8,732,593 +0
android hermes armeabi-v7a 8,043,926 +1
android hermes x86 9,221,937 -3
android hermes x86_64 9,074,914 +2
android jsc arm64-v8a 9,297,787 +1
android jsc armeabi-v7a 8,486,553 +1
android jsc x86 9,358,533 +1
android jsc x86_64 9,615,112 -1

Base commit: d8ced6f
Branch: main

@facebook-github-bot

Copy link
Copy Markdown
Contributor

This pull request was exported from Phabricator. Differential Revision: D45605441

14 similar comments
@facebook-github-bot

Copy link
Copy Markdown
Contributor

This pull request was exported from Phabricator. Differential Revision: D45605441

@facebook-github-bot

Copy link
Copy Markdown
Contributor

This pull request was exported from Phabricator. Differential Revision: D45605441

@facebook-github-bot

Copy link
Copy Markdown
Contributor

This pull request was exported from Phabricator. Differential Revision: D45605441

@facebook-github-bot

Copy link
Copy Markdown
Contributor

This pull request was exported from Phabricator. Differential Revision: D45605441

@facebook-github-bot

Copy link
Copy Markdown
Contributor

This pull request was exported from Phabricator. Differential Revision: D45605441

@facebook-github-bot

Copy link
Copy Markdown
Contributor

This pull request was exported from Phabricator. Differential Revision: D45605441

@facebook-github-bot

Copy link
Copy Markdown
Contributor

This pull request was exported from Phabricator. Differential Revision: D45605441

@facebook-github-bot

Copy link
Copy Markdown
Contributor

This pull request was exported from Phabricator. Differential Revision: D45605441

@facebook-github-bot

Copy link
Copy Markdown
Contributor

This pull request was exported from Phabricator. Differential Revision: D45605441

@facebook-github-bot

Copy link
Copy Markdown
Contributor

This pull request was exported from Phabricator. Differential Revision: D45605441

@facebook-github-bot

Copy link
Copy Markdown
Contributor

This pull request was exported from Phabricator. Differential Revision: D45605441

@facebook-github-bot

Copy link
Copy Markdown
Contributor

This pull request was exported from Phabricator. Differential Revision: D45605441

@facebook-github-bot

Copy link
Copy Markdown
Contributor

This pull request was exported from Phabricator. Differential Revision: D45605441

@facebook-github-bot

Copy link
Copy Markdown
Contributor

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
@facebook-github-bot

Copy link
Copy Markdown
Contributor

This pull request was exported from Phabricator. Differential Revision: D45605441

@facebook-github-bot facebook-github-bot added the Merged This PR has been merged. label May 15, 2023
@facebook-github-bot

Copy link
Copy Markdown
Contributor

This pull request has been merged in b6b09a7.

jakex7 pushed a commit to software-mansion/react-native-svg that referenced this pull request Aug 23, 2024
## 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.
kirillzyusko pushed a commit to kirillzyusko/react-native-keyboard-controller that referenced this pull request Aug 23, 2024
## 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.
WoLewicki added a commit to software-mansion/react-native-screens that referenced this pull request Aug 26, 2024
PR adding load method needed for dynamic frameworks to work with the library. See react/react-native#37274 for more information.
WoLewicki added a commit to software-mansion/react-native-gesture-handler that referenced this pull request Aug 30, 2024
PR adding `load` method needed for dynamic frameworks to work with the library. See react/react-native#37274 for more information.
ja1ns pushed a commit to WiseOwlTech/react-native-screens that referenced this pull request Oct 9, 2024
PR adding load method needed for dynamic frameworks to work with the library. See react/react-native#37274 for more information.
kkafar pushed a commit to software-mansion/react-native-screens that referenced this pull request Oct 25, 2024
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)
kkafar pushed a commit to software-mansion/react-native-screens that referenced this pull request Mar 12, 2025
## 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

![before](https://github.com/user-attachments/assets/62af4ba7-6d77-492c-a44d-444fa944b070)

### After

![after](https://github.com/user-attachments/assets/54272109-ea97-4363-a453-d945e5b1b39c)

## 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>
kkafar pushed a commit to software-mansion/react-native-screens that referenced this pull request Mar 12, 2025
## 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

![before](https://github.com/user-attachments/assets/62af4ba7-6d77-492c-a44d-444fa944b070)

### After

![after](https://github.com/user-attachments/assets/54272109-ea97-4363-a453-d945e5b1b39c)

## 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)
jamesdev-king added a commit to jamesdev-king/flutter_ui_challenge_flight_search that referenced this pull request Aug 1, 2025
PR adding load method needed for dynamic frameworks to work with the library. See react/react-native#37274 for more information.
DavidDuarte22 added a commit to DavidDuarte22/react-native-gesture-handler that referenced this pull request Mar 31, 2026
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).
DavidDuarte22 added a commit to DavidDuarte22/react-native-safe-area-context that referenced this pull request Mar 31, 2026
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).
DavidDuarte22 added a commit to DavidDuarte22/react-native-screens that referenced this pull request Mar 31, 2026
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.
m-bert pushed a commit to software-mansion/react-native-gesture-handler that referenced this pull request Apr 2, 2026
## 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
m-bert pushed a commit to software-mansion/react-native-gesture-handler that referenced this pull request Apr 2, 2026
## 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
Copilot AI pushed a commit to software-mansion/react-native-gesture-handler that referenced this pull request Apr 2, 2026
## 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>
kkafar pushed a commit to DavidDuarte22/react-native-screens that referenced this pull request Apr 7, 2026
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.
kkafar pushed a commit to DavidDuarte22/react-native-screens that referenced this pull request Apr 15, 2026
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.
kkafar added a commit to software-mansion/react-native-screens that referenced this pull request Apr 15, 2026
## 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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. fb-exported Merged This PR has been merged. p: Facebook Partner: Facebook Partner

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants