Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore(Android): add autolinking on Fabric #1585

Merged
merged 36 commits into from Sep 19, 2022
Merged

Conversation

kkafar
Copy link
Member

@kkafar kkafar commented Sep 10, 2022

Description

This PR integrates the library with Android autolinking mechanism 🥳

Up to this moment, react-native-screens had custom linking mechanism which builded rnscreens_modules & rnscreens_common shared libraries and loaded them during runtime, leveraging JNI's OnLoad method to add our custom component descriptors providers to ComponentDescriptorProviderRegistry instance. Since this PR forward, this custom loading mechanism is no longer needed as it shall be done by RNCLI autolinking.

See my comments below this PR description to see comments on fragile changes.

IMPORTANT: This PR requires @react-native-community/cli 9.1.0 or newer (support for cmakeListsPath in react-native.config.js & Android autolinking). This version is shipped with react-native since 0.70.0 => with merging of this PR we drop support for older react-native versions on Fabric.

See #1595 for additional commentary on important changes & implementation details.

I also recommend to go through discussion under this description to gain better understanding of changes.

Changes

  • Removed custom extrenalNativeBuild configuration from library's gradle build.
  • Removed custom loading mechanism that was used to load rnscreen_modules shared library.
  • Removed code responsible for building rnscreens_modules SO.
  • Added custom CMake build for react_codegen_rnscreens target (replacement of rnscreen_modules). See (1) below.
  • Added RNCLI configuration. Note that now all library's component descriptors must be enumerated manually. See (2) below.

(1)

Autolinking expects react_codegen_rnscreens to be the name of the library. The name is autogenerated.

I believe it would be possible to create separate target containing only custom cpp code with adding a line like:

target_link_libraries(${CMAKE_PROJECT_NAME} rnscreens_modules)

in our custom CMakeLists.txt so react_cdegen_rnscreens contains only codegened symbols but I did not test that.

(2)

If component has interfaceOnly codegen config option set to true codegen does not generate part of the required code, including component descriptor (CD). This is the case for ScreenNativeComponent. This leads to its manually created CD not being picked up by autolinking ==> we need to somehow inform RNCLI that this CD exists. This is done by specifying componentDescriptors option in react-native.config.js file. AFAIK it does not allow to extend set of codegen'd CDs, it only allows to overwrite it, hence we need to specify all CDs manually.

Test code and steps to reproduce

Build any of FabricExample applications in the repository (or create fresh React Native app) and see that they work properly

Checklist

  • Ensured that CI passes

For now it is only partially filtered (there is also code for other
    components for now). I'm not sure whether I should leave all the
codegened code or leave only the RNSScreen part.
As we provide custom implementation
Setting `componentDescriptors` causes RNCLI to not search for
autogenerated ones -> we need to specify all of them manually
This CMake builds both custom cpp code & generated one.
It seems to me, that it must be done this way as project name recognized
by autogenerated RN CLI cmake is `react_codegen_rnscreens` and we can
not change that => only this library is included in final build.
IMPORTANT: this causes our custom `rnscreens.h` header to take
precedence over its codegened counterpart when imported in following way
in `rncli.cpp`:

```c++
```

This is important beacuse it allows us to inject
`RNSScreenComponentDescriptor` symbol into `rncli.cpp` translation unit
scope.
We no longer build this target as we want to rely on new Android
autolinking.
libreact_codegen_rnscreens.so library

This symbol for some, unknown yet reason, is not visible during linking
of lib<project-name>.so (exactly during linking rncli.cpp.o file). We
enforce desired visibility with compiler attributte. Note however that
this solution should be only temporary as the exact reason should be
tracked down and the issue shall be fixed with more generic approach.
This file is not only no longer used, but also it does not contain valid
configuration for our library.

This file was replaced with common/cpp/CMakeLists.txt as we migrated to
CMake build system.
Up to this point, some paths were hardcoded, this is no longer the case.
This is temporary workaround as `rnscreens.{h,cpp}` files are not part
of common cpp code - they are android specific I believe. They must be
moved to android JNI directory along with CMakeLists.txt
specific directory

These files are not shared between iOS & Android platforms.
@kkafar kkafar marked this pull request as ready for review September 15, 2022 17:04
set(RNS_COMMON_DIR ${RNS_ANDROID_DIR}/../common/cpp)
set(RNS_GENERATED_DIR ${RNS_ANDROID_DIR}/build/generated)
set(RNS_GENERATED_JNI_DIR ${RNS_GENERATED_DIR}/source/codegen/jni)
set(RNS_GENERATED_REACT_DIR ${RNS_GENERATED_JNI_DIR}/react/renderer/components/rnscreens)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it be possible to extract rnscreens to a variable so that library authors could change only that variable for their usecase?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess I could do it, but it comes down to simply using find & replace option in code editor. I will, however refine variable names and do some cleanup.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So I went with your suggestion. All it takes now is to change LIB_LITERAL constant. However some further customisation may be required as you noticed in RNSVG (adding custom dependencies etc.)

android/src/main/jni/CMakeLists.txt Outdated Show resolved Hide resolved
android/src/main/jni/rnscreens.h Show resolved Hide resolved
android/src/main/jni/CMakeLists.txt Outdated Show resolved Hide resolved
android/src/main/jni/CMakeLists.txt Outdated Show resolved Hide resolved
Copy link
Member

@tomekzaw tomekzaw left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚀

@kkafar kkafar merged commit 5a24879 into main Sep 19, 2022
@kkafar kkafar deleted the @kkafar/fabric-autolinking branch September 19, 2022 08:39
Copy link
Member

@WoLewicki WoLewicki left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added some comments. Sorry for late review 😅

react_render_mapbuffer
rrc_view
turbomodulejsijni
yoga
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Based on the changes needed in rnsvg, maybe it would be good to add a comment that you should add here all libraries that your custom state depend on.

android/src/main/jni/rnscreens.cpp Show resolved Hide resolved
namespace facebook {
namespace react {

JSI_EXPORT
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be nice to add information why it is needed at all.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

kkafar added a commit that referenced this pull request Sep 19, 2022
## Description

Update supported React Native version for Fabric in library's main
readme.

Support for older versions has been dropped as we added autolinking in
#1585 (it [requires `@react-native-community/cli` 9.1.0 or
newer](https://github.com/react-native-community/cli/releases/tag/v9.1.0)
(support for `cmakeListsPath` in config) which is shipped with React
Native since 0.70.0)



## Changes

Since 3.18.0 Fabric will be supported only with React Native 0.70.0 or
newer.


## Test code and steps to reproduce

--

## Checklist

- [ ] Ensured that CI passes
kkafar added a commit that referenced this pull request Sep 19, 2022
## Description

Add code comments for few changes introduced in #1585. 

## Changes

Just few code comments. See the changes.


## Test code and steps to reproduce

--

## Checklist

- [x] Ensured that CI passes
@kkafar kkafar mentioned this pull request Sep 23, 2022
1 task
kkafar added a commit that referenced this pull request Sep 23, 2022
## Description

The `RNScreensComponentsRegistry` class was used for custom linking
(loading of `rnscreen_modules` shared library to java runtime). With
merge of #1585 it became redundant.

## Changes

Removed unused class & its source file.


## Test code and steps to reproduce

Just build the application and see that everything works as usual.

## Checklist

- [ ] Ensured that CI passes
kkafar added a commit that referenced this pull request Oct 11, 2022
## Description

Autolinking was added with #1585 and it added `react-native.config.js`
file with codegen configuration, **but** it did not add this file to npm
include list causing its absence in final released package...

Fixes #1608

## Changes

Added `react-native.config.js` to npm file list in main `package.json`


## Test code and steps to reproduce

See #1608 for reproductions.

## Checklist

- [x] Ensured that CI passes
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants