The iOS implementation provides native navigation using UIKit view controllers, coordinated through a bridge module that receives commands from JavaScript.
Files: RNNAppDelegate.h/mm
Base class that user's AppDelegate must extend. Handles React Native and navigation initialization:
// AppDelegate.h - User extends RNNAppDelegate
#import "RNNAppDelegate.h"
@interface AppDelegate : RNNAppDelegate
@end
// AppDelegate.m - User implements sourceURLForBridge
@implementation AppDelegate
- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge {
return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index"];
}
@endWhat RNNAppDelegate does:
- Sets up React Native feature flags (Fabric, TurboModules, Bridgeless)
- Creates
RCTRootViewFactoryandReactHost - Calls
[ReactNativeNavigation bootstrapWithHost:]to initialize navigation - Handles RN version differences (0.77, 0.78, 0.79+) via compile-time macros
File: ReactNativeNavigation.h/mm
Public API for native initialization:
// New architecture (0.77+)
[ReactNativeNavigation bootstrapWithHost:reactHost];
// Legacy bridge
[ReactNativeNavigation bootstrapWithBridge:bridge];
// Register native screens
[ReactNativeNavigation registerExternalComponent:@"NativeScreen"
callback:^(NSDictionary *props, RCTBridge *bridge) {
return [[MyNativeVC alloc] init];
}];The autolink/postlink/postLinkIOS.js script automates setup:
| Linker | What it does |
|---|---|
AppDelegateLinker |
Changes AppDelegate to extend RNNAppDelegate, imports ReactNativeNavigation, removes RCTRootView setup |
PodfileLinker |
Adds required pods configuration |
PlistLinker |
Updates Info.plist if needed |
AppDelegateLinker transformations:
- Swift:
class AppDelegate: RCTAppDelegate→class AppDelegate: RNNAppDelegate - Obj-C header:
@interface AppDelegate : RCTAppDelegate→@interface AppDelegate : RNNAppDelegate - Imports
<ReactNativeNavigation/ReactNativeNavigation.h> - Removes manual RCTRootView/window setup (navigation manages the window)
ios/
├── RNNBridgeModule.h/mm # Bridge entry point (legacy architecture)
├── RNNBridgeManager.h/mm # Bridge initialization
├── RNNCommandsHandler.h/mm # Command dispatcher
├── RNNEventEmitter.h/mm # Event emission to JS
├── RNNLayoutManager.h/mm # View controller tracking
├── RNNLayoutNode.h/mm # Layout tree parsing
├── RNNNavigationOptions.h/mm # Options model
├── RNNComponentViewController.h/mm # React component screen
├── RNNStackController.h/mm # Stack navigation
├── RNNBottomTabsController.h/mm # Tab navigation
├── RNNSideMenuViewController.h/mm # Side menu
├── RNNTopTabsViewController.h/mm # Top tabs
├── RNNSplitViewController.h/mm # Split view (iPad)
├── RNNModalManager.h/mm # Modal presentation
├── RNNOverlayManager.h/mm # Overlay management
├── TurboModules/ # New architecture entry points
│ ├── RNNTurboModule.h/mm # TurboModule spec implementation
│ ├── RNNTurboManager.h/mm # Manager for host, window, external components
│ ├── RNNTurboCommandsHandler.h/mm # TurboModule command routing
│ └── RNNTurboEventEmitter.h/mm # Event emission for new arch
├── Utils/ # Utility classes
├── RNNSideMenu/ # MMDrawerController integration
└── ReactNativeNavigation.xcodeproj/
The library supports both the legacy bridge and new TurboModule architecture:
- Legacy (Bridge):
RNNBridgeModulereceives commands viaRCT_EXPORT_METHOD - New Architecture:
RNNTurboModule(inTurboModules/) receives commands directly
Both entry points delegate to RNNCommandsHandler for command execution.
┌────────────────────────────────────────────────────────────┐
│ JavaScript (TurboModule) │
└─────────────────────────┬──────────────────────────────────┘
│
┌─────────────────────────▼──────────────────────────────────┐
│ RNNBridgeModule (bridge) / RNNTurboModule (new arch) │
│ - setRoot, push, pop, showModal, dismissModal, etc. │
└─────────────────────────┬──────────────────────────────────┘
│
┌─────────────────────────▼──────────────────────────────────┐
│ RNNCommandsHandler │
│ - Validates commands, manages layout lifecycle │
│ - Coordinates with managers │
└──────┬──────────────┬──────────────┬──────────────┬────────┘
│ │ │ │
┌──────▼─────┐ ┌──────▼─────┐ ┌──────▼─────┐ ┌─────▼──────┐
│RNNLayout │ │RNNModal │ │RNNOverlay │ │RNNViewController│
│Manager │ │Manager │ │Manager │ │Factory │
└────────────┘ └────────────┘ └────────────┘ └────────────┘
All navigation view controllers conform to RNNLayoutProtocol:
UIViewController
├── RNNComponentViewController # React component screen
├── RNNExternalViewController # Native screen wrapper
└── RNNSplashScreenViewController # Launch screen
UINavigationController
└── RNNStackController # Stack navigation
UITabBarController
└── RNNBottomTabsController # Bottom tabs
UIViewController (custom)
├── RNNTopTabsViewController # Horizontal top tabs
└── RNNSideMenuChildViewController # Drawer child
MMDrawerController
└── RNNSideMenuViewController # Side menu/drawer
UISplitViewController
└── RNNSplitViewController # Master-detail (iPad)
Entry point for JavaScript commands (legacy architecture). Exports methods via RCT_EXPORT_METHOD:
RCT_EXPORT_METHOD(setRoot:(NSString*)commandId layout:(NSDictionary*)layout
resolver:(RCTPromiseResolveBlock)resolve
rejecter:(RCTPromiseRejectBlock)reject);RNNBridgeModule returns the main queue as its methodQueue; RNNTurboModule uses RCTExecuteOnMainQueue for each command to ensure UI operations run on the main thread.
Initializes bridge infrastructure:
- Creates RNNLayoutManager, RNNModalManager, RNNOverlayManager
- Creates RNNViewControllerFactory, RNNCommandsHandler
- Provides extra modules to React bridge
- Handles JavaScript reload events
Central command dispatcher implementing all navigation operations:
setRoot:- Replace root view controllerpush:componentId:layout:- Push to stackpop:componentId:- Pop from stackshowModal:- Present modaldismissModal:- Dismiss modalshowOverlay:- Show overlay windowdismissOverlay:- Hide overlay
Tracks active view controllers:
addPendingViewController:- Register during creationremovePendingViewController:- Cleanup after presentationfindComponentForId:- Lookup by componentId
Parses JSON layout from JavaScript:
- Determines type via predicates:
isComponent,isStack,isTabs, etc. - Holds
type,nodeId,data(options),children
Creates view controllers from RNNLayoutNode:
createStack:→ RNNStackControllercreateBottomTabs:→ RNNBottomTabsControllercreateComponent:→ RNNComponentViewControllercreateSideMenu:→ RNNSideMenuViewController
Protocol all navigation controllers implement:
@protocol RNNLayoutProtocol
- (instancetype)initWithLayoutInfo:(RNNLayoutInfo*)layoutInfo
creator:(id<RNNComponentViewCreator>)creator
options:(RNNNavigationOptions*)options
defaultOptions:(RNNNavigationOptions*)defaultOptions
presenter:(RNNBasePresenter*)presenter
eventEmitter:(RNNEventEmitter*)eventEmitter
childViewControllers:(NSArray*)childViewControllers;
- (void)render;
- (UIViewController*)getCurrentChild;
- (void)mergeOptions:(RNNNavigationOptions*)options;
- (RNNNavigationOptions*)resolveOptions;
- (void)setDefaultOptions:(RNNNavigationOptions*)defaultOptions;
- (void)onChildWillAppear;
- (void)readyForPresentation;
- (CGFloat)getTopBarHeight;
- (CGFloat)getBottomTabsHeight;
@endAdditional methods provided via UIViewController+LayoutProtocol category:
destroy,topMostViewController,stackcomponentWillAppear,componentDidAppear,componentDidDisappearscreenPopped,prepareForTransitionresolveOptionsWithDefault,mergeChildOptions:child:
Each view controller type has a corresponding presenter that applies options:
| Controller | Presenter |
|---|---|
| RNNComponentViewController | RNNComponentPresenter |
| RNNStackController | RNNStackPresenter + TopBarPresenter |
| RNNBottomTabsController | RNNBottomTabsPresenter + BottomTabPresenter |
| RNNSideMenuViewController | RNNSideMenuPresenter |
| RNNSplitViewController | RNNSplitViewControllerPresenter |
Base class with lifecycle methods:
applyOptionsOnInit:- Initial setupapplyOptions:- Apply current optionsmergeOptions:resolvedOptions:- Runtime updatescomponentWillAppear,componentDidAppear,componentDidDisappear
Wraps RCTRootView (legacy) or RCTSurfaceHostingView (new architecture):
- Implements
RNNComponentProtocol - Manages
componentId,componentType,moduleName - Lifecycle:
componentWillAppear,componentDidAppear,componentDidDisappear
Creates RNNReactView instances:
- Supports component types: Component, TopBarTitle, TopBarButton, TopBarBackground
- Handles size flexibility for flexible layouts
Caches created React component instances:
createComponentIfNotExists:parentComponentId:componentType:reactViewReadyBlock:removeComponent:,clearComponentsForParentId:
Master options object containing all configuration:
@interface RNNNavigationOptions : RNNOptions
@property RNNTopBarOptions* topBar;
@property RNNBottomTabsOptions* bottomTabs;
@property RNNBottomTabOptions* bottomTab;
@property RNNTopTabsOptions* topTabs;
@property RNNSideMenuOptions* sideMenu;
@property RNNOverlayOptions* overlay;
@property RNNAnimationsOptions* animations;
@property RNNStatusBarOptions* statusBar;
@property RNNLayoutOptions* layout;
@property RNNModalOptions* modal;
@property RNNPreviewOptions* preview;
@property RNNSplitViewOptions* splitView;
@endOptions merge in hierarchy:
- Component's own options
- Parent controller options (loop through chain)
- Default options (from
setDefaultOptions)
Sends events to JavaScript via RCTEventEmitter:
| Event | Method |
|---|---|
| Component lifecycle | sendComponentWillAppear:, sendComponentDidAppear:, sendComponentDidDisappear: |
| Button press | sendOnNavigationButtonPressed:buttonId: |
| Command completion | sendOnNavigationCommandCompletion:commandId: |
| Tab events | sendBottomTabSelected:unselected:, sendBottomTabLongPressed:, sendBottomTabPressed: |
| Modal events | sendModalsDismissedEvent:numberOfModalsDismissed:, sendModalAttemptedToDismissEvent: |
| Screen events | sendScreenPoppedEvent: |
| Search | sendOnSearchBarUpdated:text:isFocused:, sendOnSearchBarCancelPressed: |
| Preview | sendOnPreviewCompleted:previewComponentId: |
Concrete implementation that sends onAppLaunched on initialization.
- Tracks presented modals array
- Supports custom transition animations via ScreenAnimationController
- Handles presentationController delegate for adaptive presentation
- Manages UIWindow instances for overlays
- Each overlay gets its own RNNOverlayWindow
- Maintains previous window reference for restoration
- Controls window level and accessibility
Implements UIViewControllerAnimatedTransitioning:
- Custom push/pop/modal transitions
- Content transitions (RNNEnterExitAnimation)
- Element transitions (ElementTransitionOptions)
- Shared element transitions (SharedElementTransitionOptions)
ElementAnimator- Individual element animationsSharedElementAnimator- Cross-screen shared elements- Transition types: Alpha, Scale, Translation, Frame, Bounds, Color, CornerRadius
Animates window root replacement using CABasicAnimation.
- Subclass of UINavigationController
- Push/pop with custom animations
- Back button customization
- Uses StackControllerDelegate for bar delegate handling
// Extension methods
@interface UINavigationController (RNNCommands)
- (void)push:(UIViewController*)vc onTop:(UIViewController*)onTopVC
animated:(BOOL)animated completion:(void(^)(void))completion rejection:(RCTPromiseRejectBlock)rejection;
- (void)popAnimated:(BOOL)animated completion:(void(^)(NSString*))completion rejection:(RCTPromiseRejectBlock)rejection;
@end- Subclass of UITabBarController
- Tab attachment modes: Together, OnSwitchToTab, AfterInitialTab
- Long-press gesture support
- Badge and dot indicator support
- Uses MMDrawerController (third-party)
- Center, left, right child containers
- Configurable open modes and widths
- Custom horizontal tab implementation
- Not based on UITabBarController
- Manual content switching
- UISplitViewController subclass
- Master-detail for iPad
Registry for native (non-React) view controllers.
Wraps native UIViewController for integration:
[ReactNativeNavigation registerExternalComponent:@"NativeScreen"
callback:^(NSDictionary *props, RCTBridge *bridge) {
return [[MyNativeViewController alloc] init];
}];| File | Purpose |
|---|---|
RNNBridgeModule.h/mm |
Bridge entry point (legacy) |
TurboModules/RNNTurboModule.mm |
TurboModule entry point (new arch) |
TurboModules/RNNTurboCommandsHandler.mm |
TurboModule command routing |
RNNCommandsHandler.h/mm |
Command execution |
RNNLayoutManager.h/mm |
Controller tracking |
RNNViewControllerFactory.h/mm |
Controller creation |
RNNComponentViewController.h/mm |
React screen |
RNNStackController.h/mm |
Stack navigation |
RNNBottomTabsController.h/mm |
Tab navigation |
RNNNavigationOptions.h/mm |
Options model |
RNNBasePresenter.h/mm |
Presenter base |
TopBarPresenter.h/mm |
Top bar styling |
RNNReactView.h/mm |
React view wrapper |
ScreenAnimationController.h/mm |
Custom transitions |