react-native-navigation icon indicating copy to clipboard operation
react-native-navigation copied to clipboard

RN 0.74 Bridgeless support

Open TheLonelyAstronaut opened this issue 1 year ago • 11 comments

Description

This PR adds support of new stable Bridgeless mode and partial migration from deprecated components. Still need some additional work to make iOS work, but all major issues was resolved with two first commits. To get this work properly, we need to wait this changes in next RN release, that's why RNN bridgeless will only work with RN 0.74.2 and higher (This changes are from Expo team cause they also need such functionality).

What was done

Common:

  • Migrated to Yarn3 (following RN)
  • Added codegen for TurboModules API
  • Turbomodules for RNNEventEmitter and RNNCommandsModule
  • JS CommandsModule architecture-independent implementation (transforms sync to async Turbomodule call if using legacy methods, this should help to update library in production app without any JS changes)

iOS:

  • waitForRender is YES by default for new architecture
  • File structure now separates files by purpose (this helps separate RN-dependent components from independent abstractions)
  • Migration to C++20
  • Migration to ObjectiveC++
  • RNNEventEmitter is a base class now. RNNBridgeEventEmitter and RNNTurboEventEmitter are children of this class
  • RNNReactView was migrated to RCTSurfaceHostingView (in new architecture mode)
  • RNNAppDelegate now extends RCTAppDelegate
  • RNNAppDelegate now uses RCTRootViewFactory and RCTHost instead of RCTBridge (In new architecture mode with bridgeless support)
  • Added RNNTurboCommandsHandler as proxy for RNNCommandsHandler
  • Added ReactNativeNavigation:bootstrapWithHost: for bridgeless mode
  • Added conditional RCTHost (bridgeless) support for almost all core classes (need some work for SurfaceAnimationController), guarded by preprocessors:
#ifdef RCT_NEW_ARCH_ENABLED // new architecture branch
    if (_host != nil) {
        [_host callSomething]; // bridgeless mode
    } else {
        [_bridge callSomething]; // bridge support
    }
#else // old architecture branch
    [_bridge callSomething]; 
#endif

TODO

Common:

  • [ ] Add detailed description
  • [ ] Prettify code
  • [x] [Playground] Remove libs that does not support Bridgeless
  • [x] [Playground] Migrate to Reanimated v3 to support Bridgeless

iOS:

  • [x] Bridgeless mode with bridge support for both old and new architectures
  • [ ] LeakChecker warnings in some flows
  • [ ] [New Architecture] find element by ID for shared element transition without UIManager
  • [ ] [New Architecture] setRoot failure cause of recursive invalidate call in RCTSurfaceHostingView instance
  • [ ] [Bridgeless] use RCTHost -> DidReceiveReloadCommand in RNNTurboModuleManager instead of bridge events
  • [ ] [Bridgeless] Test SurfaceAnimationController -> observer with RCTHost instead of _bridge.uiManager

Android:

  • [ ] Bridgeless mode with bridge support for both old and new architectures

TheLonelyAstronaut avatar Apr 30 '24 17:04 TheLonelyAstronaut

🚀

image

TheLonelyAstronaut avatar May 02 '24 15:05 TheLonelyAstronaut

Thanks for a great PR! But could you please check one more thing: what happens if Navigation.setRoot is called once again? (for example, when any button on the root screen calls this method)

Arkkeeper avatar May 05 '24 14:05 Arkkeeper

@Arkkeeper sure, I'll check this, but it could be a bit buggy (PR is still a draft/PoC, im planning to finish with iOS next week and start android), hope to resolve all the issues

TheLonelyAstronaut avatar May 05 '24 14:05 TheLonelyAstronaut

There is an interesting moment regarding new architecture: RCTEventEmitter fires 'didApper' event before component actually was created (event JS component class constructor was not been called yet).

Native call is triggered by viewDidApper lifecycle iOS event when native navigator is ready, but react view is still not, that's why after loading of react view we are getting correct view, but no event about appear status.

I think it's because of synchronous nature of new architecture, cause with old architecture we sending events from native before first render, but they emitted in JS only after render. Workaround - waitForRender: true by default with Fabric/New Architecture, but it could be reverted by setting navigation options.

TheLonelyAstronaut avatar May 06 '24 15:05 TheLonelyAstronaut

iOS example app now works fine for both old and new archs (with and without bridge) 🎉

Working on ToDo list right now

TheLonelyAstronaut avatar May 08 '24 09:05 TheLonelyAstronaut

After porting SharedElementTransition example to Reanimated 3 (to support bridgeless), i found that new Reaniamted does not support multiple surfaces yet (one native screen - one surface)

image

To fix this locally, we actually need to change assertion to if branch and return nullptr as result of commit lambda

image

TheLonelyAstronaut avatar May 10 '24 06:05 TheLonelyAstronaut

Looking forward to this one 🎉🎉

enahum avatar May 25 '24 11:05 enahum

@TheLonelyAstronaut can you share an update on your progress?

enahum avatar Jun 11 '24 22:06 enahum

Bump, looking forward for this.

lukutism avatar Jun 17 '24 12:06 lukutism

@TheLonelyAstronaut Hi, any progress ? If you are busy, can you describe what is left to be done, I could take over. Thanks :)

lukutism avatar Jul 16 '24 14:07 lukutism

@lukutism Hi, no progress yet, i have very complex task on my job right now. You could start Android implementation, I did only iOS things

TheLonelyAstronaut avatar Jul 22 '24 10:07 TheLonelyAstronaut