feat(smart-app): implement complete mobile app MVP

- App.tsx: full navigation (Auth stack + Main tabs with 5 screens)
- Auth: LoginScreen, RegisterScreen, ForgotPasswordScreen
- HomeScreen: dashboard with IoT metrics, weather widget, alerts, quick actions, sensors
- MapScreen: interactive map with layer toggles (6 layers)
- MarketplaceScreen: categories (6), products (5), search
- ChatScreen: AI chat with quick prompts (4), bot responses
- ProfileScreen: user info, stats, menu (9 items), logout
- AlertsScreen: alert list with severity, acknowledge
- SensorsScreen: sensor list with type filters (6 types), search
- ZonesScreen: zone cards with stats
- SettingsScreen: language picker (FR/EN/ES/DE), privacy, about
- Stores: iotStore (sensors, zones, alerts), notificationStore, uiStore + i18n
- Hooks: useSensors, useAlerts, useNotifications, useLocation
- Components: Card, Button, LoadingSpinner, ErrorBoundary, Header
- Services: iotService, notificationService (with axios API client)
- Utils: formatters (temp, AQI, noise, dates), validators (email, password, IBAN)
- Theme: colors.ts with full design system (Blue Ocean palette)
- Ditto: fixed MongoDB connection, new JWT secrets, official gateway image
This commit is contained in:
Eric FELIXINE
2026-06-01 18:00:35 -04:00
parent 08ca495bde
commit e30ae8ed09
35578 changed files with 3703534 additions and 43 deletions

View File

@@ -0,0 +1,162 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import <React/RCTBridgeDelegate.h>
#import <UIKit/UIKit.h>
#import "RCTRootViewFactory.h"
@class RCTBridge;
@protocol RCTBridgeDelegate;
@protocol RCTComponentViewProtocol;
@class RCTRootView;
@class RCTSurfacePresenterBridgeAdapter;
NS_ASSUME_NONNULL_BEGIN
/**
* The RCTAppDelegate is an utility class that implements some base configurations for all the React Native apps.
* It is not mandatory to use it, but it could simplify your AppDelegate code.
*
* To use it, you just need to make your AppDelegate a subclass of RCTAppDelegate:
*
* ```objc
* #import <React/RCTAppDelegate.h>
* @interface AppDelegate: RCTAppDelegate
* @end
* ```
*
* All the methods implemented by the RCTAppDelegate can be overridden by your AppDelegate if you need to provide a
custom implementation.
* If you need to customize the default implementation, you can invoke `[super <method_name>]` and use the returned
object.
*
* Overridable methods
* Shared:
* - (RCTBridge *)createBridgeWithDelegate:(id<RCTBridgeDelegate>)delegate launchOptions:(NSDictionary
*)launchOptions;
* - (UIView *)createRootViewWithBridge:(RCTBridge *)bridge moduleName:(NSString*)moduleName initProps:(NSDictionary
*)initProps;
* - (UIViewController *)createRootViewController;
* - (void)setRootView:(UIView *)rootView toRootViewController:(UIViewController *)rootViewController;
* New Architecture:
* - (BOOL)turboModuleEnabled;
* - (BOOL)fabricEnabled;
* - (NSDictionary *)prepareInitialProps
* - (Class)getModuleClassFromName:(const char *)name
* - (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:(const std::string &)name
jsInvoker:(std::shared_ptr<facebook::react::CallInvoker>)jsInvoker
* - (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:(const std::string &)name
initParams:
(const facebook::react::ObjCTurboModule::InitParams &)params
* - (id<RCTTurboModule>)getModuleInstanceFromClass:(Class)moduleClass
*/
@interface RCTAppDelegate : UIResponder <UIApplicationDelegate, UISceneDelegate, RCTBridgeDelegate>
/// The window object, used to render the UViewControllers
@property (nonatomic, strong, nonnull) UIWindow *window;
@property (nonatomic, nullable) RCTBridge *bridge;
@property (nonatomic, strong, nullable) NSString *moduleName;
@property (nonatomic, strong, nullable) NSDictionary *initialProps;
@property (nonatomic, strong, nonnull) RCTRootViewFactory *rootViewFactory;
@property (nonatomic, nullable) RCTSurfacePresenterBridgeAdapter *bridgeAdapter;
/**
* It creates a `RCTBridge` using a delegate and some launch options.
* By default, it is invoked passing `self` as a delegate.
* You can override this function to customize the logic that creates the RCTBridge
*
* @parameter: delegate - an object that implements the `RCTBridgeDelegate` protocol.
* @parameter: launchOptions - a dictionary with a set of options.
*
* @returns: a newly created instance of RCTBridge.
*/
- (RCTBridge *)createBridgeWithDelegate:(id<RCTBridgeDelegate>)delegate launchOptions:(NSDictionary *)launchOptions;
/**
* It creates a `UIView` starting from a bridge, a module name and a set of initial properties.
* By default, it is invoked using the bridge created by `createBridgeWithDelegate:launchOptions` and
* the name in the `self.moduleName` variable.
* You can override this function to customize the logic that creates the Root View.
*
* @parameter: bridge - an instance of the `RCTBridge` object.
* @parameter: moduleName - the name of the app, used by Metro to resolve the module.
* @parameter: initProps - a set of initial properties.
*
* @returns: a UIView properly configured with a bridge for React Native.
*/
- (UIView *)createRootViewWithBridge:(RCTBridge *)bridge
moduleName:(NSString *)moduleName
initProps:(NSDictionary *)initProps;
/**
* This method can be used to customize the rootView that is passed to React Native.
* A typical example is to override this method in the AppDelegate to change the background color.
* To achieve this, add in your `AppDelegate.mm`:
* ```
* - (void)customizeRootView:(RCTRootView *)rootView
* {
* rootView.backgroundColor = [UIColor colorWithDynamicProvider:^UIColor *(UITraitCollection *traitCollection) {
* if ([traitCollection userInterfaceStyle] == UIUserInterfaceStyleDark) {
* return [UIColor blackColor];
* } else {
* return [UIColor whiteColor];
* }
* }];
* }
* ```
*
* @parameter: rootView - The root view to customize.
*/
- (void)customizeRootView:(RCTRootView *)rootView;
/**
* It creates the RootViewController.
* By default, it creates a new instance of a `UIViewController`.
* You can override it to provide your own initial ViewController.
*
* @return: an instance of `UIViewController`.
*/
- (UIViewController *)createRootViewController;
/**
* It assigns the rootView to the rootViewController
* By default, it assigns the rootView to the view property of the rootViewController
* If you are not using a simple UIViewController, then there could be other methods to use to setup the rootView.
* For example: UISplitViewController requires `setViewController(_:for:)`
*/
- (void)setRootView:(UIView *)rootView toRootViewController:(UIViewController *)rootViewController;
/// This method returns a map of Component Descriptors and Components classes that needs to be registered in the
/// new renderer. The Component Descriptor is a string which represent the name used in JS to refer to the native
/// component. The default implementation returns an empty dictionary. Subclasses can override this method to register
/// the required components.
///
/// @return a dictionary that associate a component for the new renderer with his descriptor.
- (NSDictionary<NSString *, Class<RCTComponentViewProtocol>> *)thirdPartyFabricComponents;
/// This method controls whether the `turboModules` feature of the New Architecture is turned on or off.
///
/// @note: This is required to be rendering on Fabric (i.e. on the New Architecture).
/// @return: `true` if the Turbo Native Module are enabled. Otherwise, it returns `false`.
- (BOOL)turboModuleEnabled;
/// This method controls whether the App will use the Fabric renderer of the New Architecture or not.
///
/// @return: `true` if the Fabric Renderer is enabled. Otherwise, it returns `false`.
- (BOOL)fabricEnabled;
/// This method controls whether React Native's new initialization layer is enabled.
///
/// @return: `true` if the new initialization layer is enabled. Otherwise returns `false`.
- (BOOL)bridgelessEnabled;
/// Return the bundle URL for the main bundle.
- (NSURL *__nullable)bundleURL;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,261 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import "RCTAppDelegate.h"
#import <React/RCTCxxBridgeDelegate.h>
#import <React/RCTLog.h>
#import <React/RCTRootView.h>
#import <React/RCTSurfacePresenterBridgeAdapter.h>
#import <React/RCTUtils.h>
#import <react/renderer/runtimescheduler/RuntimeScheduler.h>
#import "RCTAppSetupUtils.h"
#if RN_DISABLE_OSS_PLUGIN_HEADER
#import <RCTTurboModulePlugin/RCTTurboModulePlugin.h>
#else
#import <React/CoreModulesPlugins.h>
#endif
#import <React/RCTBundleURLProvider.h>
#import <React/RCTComponentViewFactory.h>
#import <React/RCTComponentViewProtocol.h>
#import <React/RCTFabricSurface.h>
#import <React/RCTSurfaceHostingProxyRootView.h>
#import <React/RCTSurfacePresenter.h>
#import <ReactCommon/RCTContextContainerHandling.h>
#if USE_HERMES
#import <ReactCommon/RCTHermesInstance.h>
#else
#import <ReactCommon/RCTJscInstance.h>
#endif
#import <ReactCommon/RCTHost+Internal.h>
#import <ReactCommon/RCTHost.h>
#import <ReactCommon/RCTTurboModuleManager.h>
#import <react/config/ReactNativeConfig.h>
#import <react/renderer/runtimescheduler/RuntimeScheduler.h>
#import <react/renderer/runtimescheduler/RuntimeSchedulerCallInvoker.h>
#import <react/runtime/JSRuntimeFactory.h>
@interface RCTAppDelegate () <RCTComponentViewFactoryComponentProvider, RCTTurboModuleManagerDelegate>
@end
@implementation RCTAppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
RCTSetNewArchEnabled([self newArchEnabled]);
RCTAppSetupPrepareApp(application, self.turboModuleEnabled);
self.rootViewFactory = [self createRCTRootViewFactory];
UIView *rootView = [self.rootViewFactory viewWithModuleName:self.moduleName
initialProperties:self.initialProps
launchOptions:launchOptions];
if (self.newArchEnabled || self.fabricEnabled) {
[RCTComponentViewFactory currentComponentViewFactory].thirdPartyFabricComponentsProvider = self;
}
[self _logWarnIfCreateRootViewWithBridgeIsOverridden];
[self customizeRootView:(RCTRootView *)rootView];
self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
UIViewController *rootViewController = [self createRootViewController];
[self setRootView:rootView toRootViewController:rootViewController];
self.window.rootViewController = rootViewController;
self.window.windowScene.delegate = self;
[self.window makeKeyAndVisible];
return YES;
}
- (void)applicationDidEnterBackground:(UIApplication *)application
{
// Noop
}
- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge
{
[NSException raise:@"RCTBridgeDelegate::sourceURLForBridge not implemented"
format:@"Subclasses must implement a valid sourceURLForBridge method"];
return nil;
}
- (RCTBridge *)createBridgeWithDelegate:(id<RCTBridgeDelegate>)delegate launchOptions:(NSDictionary *)launchOptions
{
return [[RCTBridge alloc] initWithDelegate:delegate launchOptions:launchOptions];
}
- (UIView *)createRootViewWithBridge:(RCTBridge *)bridge
moduleName:(NSString *)moduleName
initProps:(NSDictionary *)initProps
{
BOOL enableFabric = self.fabricEnabled;
UIView *rootView = RCTAppSetupDefaultRootView(bridge, moduleName, initProps, enableFabric);
rootView.backgroundColor = [UIColor systemBackgroundColor];
return rootView;
}
// TODO T173939093 - Remove _logWarnIfCreateRootViewWithBridgeIsOverridden after 0.74 is cut
- (void)_logWarnIfCreateRootViewWithBridgeIsOverridden
{
SEL selector = @selector(createRootViewWithBridge:moduleName:initProps:);
IMP baseClassImp = method_getImplementation(class_getInstanceMethod([RCTAppDelegate class], selector));
IMP currentClassImp = method_getImplementation(class_getInstanceMethod([self class], selector));
if (currentClassImp != baseClassImp) {
NSString *warnMessage =
@"If you are using the `createRootViewWithBridge` to customize the root view appearence,"
"for example to set the backgroundColor, please migrate to `customiseView` method.\n"
"The `createRootViewWithBridge` method is not invoked in bridgeless.";
RCTLogWarn(@"%@", warnMessage);
}
}
- (UIViewController *)createRootViewController
{
return [UIViewController new];
}
- (void)setRootView:(UIView *)rootView toRootViewController:(UIViewController *)rootViewController
{
rootViewController.view = rootView;
}
- (void)customizeRootView:(RCTRootView *)rootView
{
// Override point for customization after application launch.
}
#pragma mark - UISceneDelegate
- (void)windowScene:(UIWindowScene *)windowScene
didUpdateCoordinateSpace:(id<UICoordinateSpace>)previousCoordinateSpace
interfaceOrientation:(UIInterfaceOrientation)previousInterfaceOrientation
traitCollection:(UITraitCollection *)previousTraitCollection API_AVAILABLE(ios(13.0))
{
[[NSNotificationCenter defaultCenter] postNotificationName:RCTWindowFrameDidChangeNotification object:self];
}
#pragma mark - New Arch Enabled settings
- (BOOL)newArchEnabled
{
#if RCT_NEW_ARCH_ENABLED
return YES;
#else
return NO;
#endif
}
- (BOOL)turboModuleEnabled
{
return [self newArchEnabled];
}
- (BOOL)fabricEnabled
{
return [self newArchEnabled];
}
- (BOOL)bridgelessEnabled
{
return [self newArchEnabled];
}
- (NSURL *)bundleURL
{
[NSException raise:@"RCTAppDelegate::bundleURL not implemented"
format:@"Subclasses must implement a valid getBundleURL method"];
return nullptr;
}
#pragma mark - Bridge and Bridge Adapter properties
- (RCTBridge *)bridge
{
return self.rootViewFactory.bridge;
}
- (RCTSurfacePresenterBridgeAdapter *)bridgeAdapter
{
return self.rootViewFactory.bridgeAdapter;
}
- (void)setBridge:(RCTBridge *)bridge
{
self.rootViewFactory.bridge = bridge;
}
- (void)setBridgeAdapter:(RCTSurfacePresenterBridgeAdapter *)bridgeAdapter
{
self.rootViewFactory.bridgeAdapter = bridgeAdapter;
}
#pragma mark - RCTTurboModuleManagerDelegate
- (Class)getModuleClassFromName:(const char *)name
{
#if RN_DISABLE_OSS_PLUGIN_HEADER
return RCTTurboModulePluginClassProvider(name);
#else
return RCTCoreModulesClassProvider(name);
#endif
}
- (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:(const std::string &)name
jsInvoker:(std::shared_ptr<facebook::react::CallInvoker>)jsInvoker
{
return nullptr;
}
- (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:(const std::string &)name
initParams:
(const facebook::react::ObjCTurboModule::InitParams &)params
{
return nullptr;
}
- (id<RCTTurboModule>)getModuleInstanceFromClass:(Class)moduleClass
{
return RCTAppSetupDefaultModuleFromClass(moduleClass);
}
#pragma mark - RCTComponentViewFactoryComponentProvider
- (NSDictionary<NSString *, Class<RCTComponentViewProtocol>> *)thirdPartyFabricComponents
{
return @{};
}
- (RCTRootViewFactory *)createRCTRootViewFactory
{
__weak __typeof(self) weakSelf = self;
RCTBundleURLBlock bundleUrlBlock = ^{
RCTAppDelegate *strongSelf = weakSelf;
return strongSelf.bundleURL;
};
RCTRootViewFactoryConfiguration *configuration =
[[RCTRootViewFactoryConfiguration alloc] initWithBundleURLBlock:bundleUrlBlock
newArchEnabled:self.fabricEnabled
turboModuleEnabled:self.turboModuleEnabled
bridgelessEnabled:self.bridgelessEnabled];
configuration.createRootViewWithBridge = ^UIView *(RCTBridge *bridge, NSString *moduleName, NSDictionary *initProps)
{
return [weakSelf createRootViewWithBridge:bridge moduleName:moduleName initProps:initProps];
};
configuration.createBridgeWithDelegate = ^RCTBridge *(id<RCTBridgeDelegate> delegate, NSDictionary *launchOptions)
{
return [weakSelf createBridgeWithDelegate:delegate launchOptions:launchOptions];
};
return [[RCTRootViewFactory alloc] initWithConfiguration:configuration andTurboModuleManagerDelegate:self];
}
@end

View File

@@ -0,0 +1,55 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import <Foundation/Foundation.h>
#import <React/RCTBridge.h>
#import <React/RCTRootView.h>
#ifdef __cplusplus
#import <memory>
#if USE_HERMES
#if __has_include(<jsireact/HermesExecutorFactory.h>)
#import <jsireact/HermesExecutorFactory.h>
#elif __has_include(<reacthermes/HermesExecutorFactory.h>)
#import <reacthermes/HermesExecutorFactory.h>
#endif
#else // USE_HERMES
#import <React/JSCExecutorFactory.h>
#endif // USE_HERMES
#import <ReactCommon/RCTTurboModuleManager.h>
// Forward declaration to decrease compilation coupling
namespace facebook::react {
class RuntimeScheduler;
}
RCT_EXTERN id<RCTTurboModule> RCTAppSetupDefaultModuleFromClass(Class moduleClass);
std::unique_ptr<facebook::react::JSExecutorFactory> RCTAppSetupDefaultJsExecutorFactory(
RCTBridge *bridge,
RCTTurboModuleManager *turboModuleManager,
const std::shared_ptr<facebook::react::RuntimeScheduler> &runtimeScheduler);
std::unique_ptr<facebook::react::JSExecutorFactory> RCTAppSetupJsExecutorFactoryForOldArch(
RCTBridge *bridge,
const std::shared_ptr<facebook::react::RuntimeScheduler> &runtimeScheduler);
#endif // __cplusplus
RCT_EXTERN_C_BEGIN
void RCTAppSetupPrepareApp(UIApplication *application, BOOL turboModuleEnabled);
UIView *RCTAppSetupDefaultRootView(
RCTBridge *bridge,
NSString *moduleName,
NSDictionary *initialProperties,
BOOL fabricEnabled);
RCT_EXTERN_C_END

View File

@@ -0,0 +1,177 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import "RCTAppSetupUtils.h"
#import <React/RCTJSIExecutorRuntimeInstaller.h>
#import <react/renderer/runtimescheduler/RuntimeScheduler.h>
#import <react/renderer/runtimescheduler/RuntimeSchedulerBinding.h>
// Turbo Module
#import <React/RCTBundleAssetImageLoader.h>
#import <React/RCTDataRequestHandler.h>
#import <React/RCTFileRequestHandler.h>
#import <React/RCTGIFImageDecoder.h>
#import <React/RCTHTTPRequestHandler.h>
#import <React/RCTImageLoader.h>
#import <React/RCTNetworking.h>
// Fabric
#import <React/RCTFabricSurface.h>
#import <React/RCTSurfaceHostingProxyRootView.h>
// jsinspector-modern
#import <jsinspector-modern/InspectorFlags.h>
#if __has_include(<React-Codegen/RCTModulesConformingToProtocolsProvider.h>)
#define USE_OSS_CODEGEN 1
#import <React-Codegen/RCTModulesConformingToProtocolsProvider.h>
#elif __has_include(<React_Codegen/RCTModulesConformingToProtocolsProvider.h>)
#define USE_OSS_CODEGEN 1
#import <React_Codegen/RCTModulesConformingToProtocolsProvider.h>
#else
// Meta internal system do not generate the RCTModulesConformingToProtocolsProvider.h file
#define USE_OSS_CODEGEN 0
#endif
void RCTAppSetupPrepareApp(UIApplication *application, BOOL turboModuleEnabled)
{
RCTEnableTurboModule(turboModuleEnabled);
#if DEBUG
// Disable idle timer in dev builds to avoid putting application in background and complicating
// Metro reconnection logic. Users only need this when running the application using our CLI tooling.
application.idleTimerDisabled = YES;
#endif
}
UIView *
RCTAppSetupDefaultRootView(RCTBridge *bridge, NSString *moduleName, NSDictionary *initialProperties, BOOL fabricEnabled)
{
if (fabricEnabled) {
id<RCTSurfaceProtocol> surface = [[RCTFabricSurface alloc] initWithBridge:bridge
moduleName:moduleName
initialProperties:initialProperties];
return [[RCTSurfaceHostingProxyRootView alloc] initWithSurface:surface];
}
return [[RCTRootView alloc] initWithBridge:bridge moduleName:moduleName initialProperties:initialProperties];
}
id<RCTTurboModule> RCTAppSetupDefaultModuleFromClass(Class moduleClass)
{
// private block used to filter out modules depending on protocol conformance
NSArray * (^extractModuleConformingToProtocol)(RCTModuleRegistry *, Protocol *) =
^NSArray *(RCTModuleRegistry *moduleRegistry, Protocol *protocol)
{
NSArray<NSString *> *classNames = @[];
#if USE_OSS_CODEGEN
if (protocol == @protocol(RCTImageURLLoader)) {
classNames = [RCTModulesConformingToProtocolsProvider imageURLLoaderClassNames];
} else if (protocol == @protocol(RCTImageDataDecoder)) {
classNames = [RCTModulesConformingToProtocolsProvider imageDataDecoderClassNames];
} else if (protocol == @protocol(RCTURLRequestHandler)) {
classNames = [RCTModulesConformingToProtocolsProvider URLRequestHandlerClassNames];
}
#endif
NSMutableArray *modules = [NSMutableArray new];
for (NSString *className in classNames) {
const char *cModuleName = [className cStringUsingEncoding:NSUTF8StringEncoding];
id moduleFromLibrary = [moduleRegistry moduleForName:cModuleName];
if (![moduleFromLibrary conformsToProtocol:protocol]) {
continue;
}
[modules addObject:moduleFromLibrary];
}
return modules;
};
// Set up the default RCTImageLoader and RCTNetworking modules.
if (moduleClass == RCTImageLoader.class) {
return [[moduleClass alloc] initWithRedirectDelegate:nil
loadersProvider:^NSArray<id<RCTImageURLLoader>> *(RCTModuleRegistry *moduleRegistry) {
NSArray *imageURLLoaderModules =
extractModuleConformingToProtocol(moduleRegistry, @protocol(RCTImageURLLoader));
return [@[ [RCTBundleAssetImageLoader new] ] arrayByAddingObjectsFromArray:imageURLLoaderModules];
}
decodersProvider:^NSArray<id<RCTImageDataDecoder>> *(RCTModuleRegistry *moduleRegistry) {
NSArray *imageDataDecoder = extractModuleConformingToProtocol(moduleRegistry, @protocol(RCTImageDataDecoder));
return [@[ [RCTGIFImageDecoder new] ] arrayByAddingObjectsFromArray:imageDataDecoder];
}];
} else if (moduleClass == RCTNetworking.class) {
return [[moduleClass alloc]
initWithHandlersProvider:^NSArray<id<RCTURLRequestHandler>> *(RCTModuleRegistry *moduleRegistry) {
NSArray *URLRequestHandlerModules =
extractModuleConformingToProtocol(moduleRegistry, @protocol(RCTURLRequestHandler));
return [@[
[RCTHTTPRequestHandler new],
[RCTDataRequestHandler new],
[RCTFileRequestHandler new],
[moduleRegistry moduleForName:"BlobModule"],
] arrayByAddingObjectsFromArray:URLRequestHandlerModules];
}];
}
// No custom initializer here.
return [moduleClass new];
}
std::unique_ptr<facebook::react::JSExecutorFactory> RCTAppSetupDefaultJsExecutorFactory(
RCTBridge *bridge,
RCTTurboModuleManager *turboModuleManager,
const std::shared_ptr<facebook::react::RuntimeScheduler> &runtimeScheduler)
{
// Necessary to allow NativeModules to lookup TurboModules
[bridge setRCTTurboModuleRegistry:turboModuleManager];
#if RCT_DEV
/**
* Instantiating DevMenu has the side-effect of registering
* shortcuts for CMD + d, CMD + i, and CMD + n via RCTDevMenu.
* Therefore, when TurboModules are enabled, we must manually create this
* NativeModule.
*/
[turboModuleManager moduleForName:"RCTDevMenu"];
#endif // end RCT_DEV
#if USE_HERMES
return std::make_unique<facebook::react::HermesExecutorFactory>(
#else
return std::make_unique<facebook::react::JSCExecutorFactory>(
#endif // USE_HERMES
facebook::react::RCTJSIExecutorRuntimeInstaller(
[turboModuleManager, bridge, runtimeScheduler](facebook::jsi::Runtime &runtime) {
if (!bridge || !turboModuleManager) {
return;
}
if (runtimeScheduler) {
facebook::react::RuntimeSchedulerBinding::createAndInstallIfNeeded(runtime, runtimeScheduler);
}
[turboModuleManager installJSBindings:runtime];
}));
}
std::unique_ptr<facebook::react::JSExecutorFactory> RCTAppSetupJsExecutorFactoryForOldArch(
RCTBridge *bridge,
const std::shared_ptr<facebook::react::RuntimeScheduler> &runtimeScheduler)
{
#if USE_HERMES
return std::make_unique<facebook::react::HermesExecutorFactory>(
#else
return std::make_unique<facebook::react::JSCExecutorFactory>(
#endif // USE_HERMES
facebook::react::RCTJSIExecutorRuntimeInstaller([bridge, runtimeScheduler](facebook::jsi::Runtime &runtime) {
if (!bridge) {
return;
}
if (runtimeScheduler) {
facebook::react::RuntimeSchedulerBinding::createAndInstallIfNeeded(runtime, runtimeScheduler);
}
}));
}

View File

@@ -0,0 +1,133 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import <React/RCTBridge.h>
#import <React/RCTRootView.h>
#import <React/RCTUtils.h>
@protocol RCTCxxBridgeDelegate;
@protocol RCTComponentViewFactoryComponentProvider;
@protocol RCTTurboModuleManagerDelegate;
@class RCTBridge;
@class RCTRootView;
@class RCTSurfacePresenterBridgeAdapter;
NS_ASSUME_NONNULL_BEGIN
#pragma mark - Blocks' definitions
typedef UIView *_Nonnull (
^RCTCreateRootViewWithBridgeBlock)(RCTBridge *bridge, NSString *moduleName, NSDictionary *initProps);
typedef RCTBridge *_Nonnull (
^RCTCreateBridgeWithDelegateBlock)(id<RCTBridgeDelegate> delegate, NSDictionary *launchOptions);
typedef NSURL *_Nullable (^RCTSourceURLForBridgeBlock)(RCTBridge *bridge);
typedef NSURL *_Nullable (^RCTBundleURLBlock)(void);
typedef NSArray<id<RCTBridgeModule>> *_Nonnull (^RCTExtraModulesForBridgeBlock)(RCTBridge *bridge);
typedef NSDictionary<NSString *, Class> *_Nonnull (^RCTExtraLazyModuleClassesForBridge)(RCTBridge *bridge);
typedef BOOL (^RCTBridgeDidNotFindModuleBlock)(RCTBridge *bridge, NSString *moduleName);
#pragma mark - RCTRootViewFactory Configuration
@interface RCTRootViewFactoryConfiguration : NSObject
/// This property controls whether the App will use the Fabric renderer of the New Architecture or not.
@property (nonatomic, assign, readonly) BOOL fabricEnabled;
/// This property controls whether React Native's new initialization layer is enabled.
@property (nonatomic, assign, readonly) BOOL bridgelessEnabled;
/// This method controls whether the `turboModules` feature of the New Architecture is turned on or off
@property (nonatomic, assign, readonly) BOOL turboModuleEnabled;
/// Return the bundle URL for the main bundle.
@property (nonatomic, nonnull) RCTBundleURLBlock bundleURLBlock;
/**
* Use this method to initialize a new instance of `RCTRootViewFactoryConfiguration` by passing a `bundleURL`
*
* Which is the location of the JavaScript source file. When running from the packager
* this should be an absolute URL, e.g. `http://localhost:8081/index.ios.bundle`.
* When running from a locally bundled JS file, this should be a `file://` url
* pointing to a path inside the app resources, e.g. `file://.../main.jsbundle`.
*
*/
- (instancetype)initWithBundleURLBlock:(RCTBundleURLBlock)bundleURLBlock
newArchEnabled:(BOOL)newArchEnabled
turboModuleEnabled:(BOOL)turboModuleEnabled
bridgelessEnabled:(BOOL)bridgelessEnabled NS_DESIGNATED_INITIALIZER;
- (instancetype)initWithBundleURL:(NSURL *)bundleURL
newArchEnabled:(BOOL)newArchEnabled
turboModuleEnabled:(BOOL)turboModuleEnabled
bridgelessEnabled:(BOOL)bridgelessEnabled __deprecated;
/**
* Block that allows to override logic of creating root view instance.
* It creates a `UIView` starting from a bridge, a module name and a set of initial properties.
* By default, it is invoked using the bridge created by `RCTCreateBridgeWithDelegateBlock` (or the default
* implementation) and the `moduleName` variable comes from `viewWithModuleName:initialProperties:launchOptions` of
* `RCTRootViewFactory`.
*
* @parameter: bridge - an instance of the `RCTBridge` object.
* @parameter: moduleName - the name of the app, used by Metro to resolve the module.
* @parameter: initProps - a set of initial properties.
*
* @returns: a UIView properly configured with a bridge for React Native.
*/
@property (nonatomic, nullable) RCTCreateRootViewWithBridgeBlock createRootViewWithBridge;
/**
* Block that allows to override default behavior of creating bridge.
* It should return `RCTBridge` using a delegate and some launch options.
*
* By default, it is invoked passing `self` as a delegate.
*
* @parameter: delegate - an object that implements the `RCTBridgeDelegate` protocol.
* @parameter: launchOptions - a dictionary with a set of options.
*
* @returns: a newly created instance of RCTBridge.
*/
@property (nonatomic, nullable) RCTCreateBridgeWithDelegateBlock createBridgeWithDelegate;
@end
#pragma mark - RCTRootViewFactory
/**
* The RCTRootViewFactory is an utility class that encapsulates the logic of creating a new RCTRootView based on the
* current state of the environment. It allows you to initialize your app root view for old architecture, new
* architecture and bridgless mode.
*
* This class is used to initalize rootView in RCTAppDelegate, but you can also use it separately.
*
* Create a new instance of this class (make sure to retain it) and call the
* `viewWithModuleName:initialProperties:launchOptions` method to create new RCTRootView.
*/
@interface RCTRootViewFactory : NSObject
@property (nonatomic, strong, nullable) RCTBridge *bridge;
@property (nonatomic, strong, nullable) RCTSurfacePresenterBridgeAdapter *bridgeAdapter;
- (instancetype)initWithConfiguration:(RCTRootViewFactoryConfiguration *)configuration
andTurboModuleManagerDelegate:(id<RCTTurboModuleManagerDelegate>)turboModuleManagerDelegate;
/**
* This method can be used to create new RCTRootViews on demand.
*
* @parameter: moduleName - the name of the app, used by Metro to resolve the module.
* @parameter: initialProperties - a set of initial properties.
* @parameter: launchOptions - a dictionary with a set of options.
*/
- (UIView *_Nonnull)viewWithModuleName:(NSString *)moduleName
initialProperties:(NSDictionary *__nullable)initialProperties
launchOptions:(NSDictionary *__nullable)launchOptions;
- (UIView *_Nonnull)viewWithModuleName:(NSString *)moduleName
initialProperties:(NSDictionary *__nullable)initialProperties;
- (UIView *_Nonnull)viewWithModuleName:(NSString *)moduleName;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,268 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import "RCTRootViewFactory.h"
#import <React/RCTCxxBridgeDelegate.h>
#import <React/RCTLog.h>
#import <React/RCTRootView.h>
#import <React/RCTSurfacePresenterBridgeAdapter.h>
#import <React/RCTUtils.h>
#import <react/renderer/runtimescheduler/RuntimeScheduler.h>
#import "RCTAppDelegate.h"
#import "RCTAppSetupUtils.h"
#if RN_DISABLE_OSS_PLUGIN_HEADER
#import <RCTTurboModulePlugin/RCTTurboModulePlugin.h>
#else
#import <React/CoreModulesPlugins.h>
#endif
#import <React/RCTBundleURLProvider.h>
#import <React/RCTComponentViewFactory.h>
#import <React/RCTComponentViewProtocol.h>
#import <React/RCTFabricSurface.h>
#import <React/RCTSurfaceHostingProxyRootView.h>
#import <React/RCTSurfacePresenter.h>
#import <ReactCommon/RCTContextContainerHandling.h>
#if USE_HERMES
#import <ReactCommon/RCTHermesInstance.h>
#else
#import <ReactCommon/RCTJscInstance.h>
#endif
#import <ReactCommon/RCTHost+Internal.h>
#import <ReactCommon/RCTHost.h>
#import <ReactCommon/RCTTurboModuleManager.h>
#import <react/config/ReactNativeConfig.h>
#import <react/renderer/runtimescheduler/RuntimeScheduler.h>
#import <react/renderer/runtimescheduler/RuntimeSchedulerCallInvoker.h>
#import <react/runtime/JSRuntimeFactory.h>
static NSString *const kRNConcurrentRoot = @"concurrentRoot";
static NSDictionary *updateInitialProps(NSDictionary *initialProps, BOOL isFabricEnabled)
{
NSMutableDictionary *mutableProps = initialProps != NULL ? [initialProps mutableCopy] : [NSMutableDictionary new];
// Hardcoding the Concurrent Root as it it not recommended to
// have the concurrentRoot turned off when Fabric is enabled.
mutableProps[kRNConcurrentRoot] = @(isFabricEnabled);
return mutableProps;
}
@implementation RCTRootViewFactoryConfiguration
- (instancetype)initWithBundleURL:(NSURL *)bundleURL
newArchEnabled:(BOOL)newArchEnabled
turboModuleEnabled:(BOOL)turboModuleEnabled
bridgelessEnabled:(BOOL)bridgelessEnabled
{
return [self
initWithBundleURLBlock:^{
return bundleURL;
}
newArchEnabled:newArchEnabled
turboModuleEnabled:turboModuleEnabled
bridgelessEnabled:bridgelessEnabled];
}
- (instancetype)initWithBundleURLBlock:(RCTBundleURLBlock)bundleURLBlock
newArchEnabled:(BOOL)newArchEnabled
turboModuleEnabled:(BOOL)turboModuleEnabled
bridgelessEnabled:(BOOL)bridgelessEnabled
{
if (self = [super init]) {
_bundleURLBlock = bundleURLBlock;
_fabricEnabled = newArchEnabled;
_turboModuleEnabled = turboModuleEnabled;
_bridgelessEnabled = bridgelessEnabled;
}
return self;
}
@end
@interface RCTRootViewFactory () <RCTContextContainerHandling> {
std::shared_ptr<const facebook::react::ReactNativeConfig> _reactNativeConfig;
facebook::react::ContextContainer::Shared _contextContainer;
}
@end
@interface RCTRootViewFactory () <RCTCxxBridgeDelegate> {
std::shared_ptr<facebook::react::RuntimeScheduler> _runtimeScheduler;
}
@end
@implementation RCTRootViewFactory {
RCTHost *_reactHost;
RCTRootViewFactoryConfiguration *_configuration;
__weak id<RCTTurboModuleManagerDelegate> _turboModuleManagerDelegate;
}
- (instancetype)initWithConfiguration:(RCTRootViewFactoryConfiguration *)configuration
andTurboModuleManagerDelegate:(id<RCTTurboModuleManagerDelegate>)turboModuleManagerDelegate
{
if (self = [super init]) {
_configuration = configuration;
_contextContainer = std::make_shared<facebook::react::ContextContainer const>();
_reactNativeConfig = std::make_shared<facebook::react::EmptyReactNativeConfig const>();
_contextContainer->insert("ReactNativeConfig", _reactNativeConfig);
_turboModuleManagerDelegate = turboModuleManagerDelegate;
}
return self;
}
- (UIView *)viewWithModuleName:(NSString *)moduleName initialProperties:(NSDictionary *)initialProperties
{
return [self viewWithModuleName:moduleName initialProperties:initialProperties launchOptions:nil];
}
- (UIView *)viewWithModuleName:(NSString *)moduleName
{
return [self viewWithModuleName:moduleName initialProperties:nil launchOptions:nil];
}
- (UIView *)viewWithModuleName:(NSString *)moduleName
initialProperties:(NSDictionary *)initialProperties
launchOptions:(NSDictionary *)launchOptions
{
NSDictionary *initProps = updateInitialProps(initialProperties, self->_configuration.fabricEnabled);
if (self->_configuration.bridgelessEnabled) {
// Enable native view config interop only if both bridgeless mode and Fabric is enabled.
RCTSetUseNativeViewConfigsInBridgelessMode(self->_configuration.fabricEnabled);
// Enable TurboModule interop by default in Bridgeless mode
RCTEnableTurboModuleInterop(YES);
RCTEnableTurboModuleInteropBridgeProxy(YES);
[self createReactHostIfNeeded:launchOptions];
RCTFabricSurface *surface = [_reactHost createSurfaceWithModuleName:moduleName initialProperties:initProps];
RCTSurfaceHostingProxyRootView *surfaceHostingProxyRootView = [[RCTSurfaceHostingProxyRootView alloc]
initWithSurface:surface
sizeMeasureMode:RCTSurfaceSizeMeasureModeWidthExact | RCTSurfaceSizeMeasureModeHeightExact];
return surfaceHostingProxyRootView;
}
[self createBridgeIfNeeded:launchOptions];
[self createBridgeAdapterIfNeeded];
if (self->_configuration.createRootViewWithBridge != nil) {
return self->_configuration.createRootViewWithBridge(self.bridge, moduleName, initProps);
}
return [self createRootViewWithBridge:self.bridge moduleName:moduleName initProps:initProps];
}
- (RCTBridge *)createBridgeWithDelegate:(id<RCTBridgeDelegate>)delegate launchOptions:(NSDictionary *)launchOptions
{
return [[RCTBridge alloc] initWithDelegate:delegate launchOptions:launchOptions];
}
- (UIView *)createRootViewWithBridge:(RCTBridge *)bridge
moduleName:(NSString *)moduleName
initProps:(NSDictionary *)initProps
{
BOOL enableFabric = self->_configuration.fabricEnabled;
UIView *rootView = RCTAppSetupDefaultRootView(bridge, moduleName, initProps, enableFabric);
rootView.backgroundColor = [UIColor systemBackgroundColor];
return rootView;
}
#pragma mark - RCTCxxBridgeDelegate
- (std::unique_ptr<facebook::react::JSExecutorFactory>)jsExecutorFactoryForBridge:(RCTBridge *)bridge
{
_runtimeScheduler = std::make_shared<facebook::react::RuntimeScheduler>(RCTRuntimeExecutorFromBridge(bridge));
if (RCTIsNewArchEnabled()) {
std::shared_ptr<facebook::react::CallInvoker> callInvoker =
std::make_shared<facebook::react::RuntimeSchedulerCallInvoker>(_runtimeScheduler);
RCTTurboModuleManager *turboModuleManager =
[[RCTTurboModuleManager alloc] initWithBridge:bridge
delegate:_turboModuleManagerDelegate
jsInvoker:callInvoker];
_contextContainer->erase("RuntimeScheduler");
_contextContainer->insert("RuntimeScheduler", _runtimeScheduler);
return RCTAppSetupDefaultJsExecutorFactory(bridge, turboModuleManager, _runtimeScheduler);
} else {
return RCTAppSetupJsExecutorFactoryForOldArch(bridge, _runtimeScheduler);
}
}
- (void)createBridgeIfNeeded:(NSDictionary *)launchOptions
{
if (self.bridge != nil) {
return;
}
if (self->_configuration.createBridgeWithDelegate != nil) {
self.bridge = self->_configuration.createBridgeWithDelegate(self, launchOptions);
} else {
self.bridge = [self createBridgeWithDelegate:self launchOptions:launchOptions];
}
}
- (void)createBridgeAdapterIfNeeded
{
if (!self->_configuration.fabricEnabled || self.bridgeAdapter) {
return;
}
self.bridgeAdapter = [[RCTSurfacePresenterBridgeAdapter alloc] initWithBridge:self.bridge
contextContainer:_contextContainer];
self.bridge.surfacePresenter = self.bridgeAdapter.surfacePresenter;
}
#pragma mark - New Arch Utilities
- (void)createReactHostIfNeeded:(NSDictionary *)launchOptions
{
if (_reactHost) {
return;
}
__weak __typeof(self) weakSelf = self;
_reactHost = [[RCTHost alloc] initWithBundleURLProvider:self->_configuration.bundleURLBlock
hostDelegate:nil
turboModuleManagerDelegate:_turboModuleManagerDelegate
jsEngineProvider:^std::shared_ptr<facebook::react::JSRuntimeFactory>() {
return [weakSelf createJSRuntimeFactory];
}
launchOptions:launchOptions];
[_reactHost setBundleURLProvider:^NSURL *() {
return [weakSelf bundleURL];
}];
[_reactHost setContextContainerHandler:self];
[_reactHost start];
}
- (std::shared_ptr<facebook::react::JSRuntimeFactory>)createJSRuntimeFactory
{
#if USE_HERMES
return std::make_shared<facebook::react::RCTHermesInstance>(_reactNativeConfig, nullptr);
#else
return std::make_shared<facebook::react::RCTJscInstance>();
#endif
}
- (void)didCreateContextContainer:(std::shared_ptr<facebook::react::ContextContainer>)contextContainer
{
contextContainer->insert("ReactNativeConfig", _reactNativeConfig);
}
- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge
{
return [self bundleURL];
}
- (NSURL *)bundleURL
{
return self->_configuration.bundleURLBlock();
}
@end

View File

@@ -0,0 +1,99 @@
# Copyright (c) Meta Platforms, Inc. and affiliates.
#
# This source code is licensed under the MIT license found in the
# LICENSE file in the root directory of this source tree.
require "json"
package = JSON.parse(File.read(File.join(__dir__, "..", "..", "package.json")))
version = package['version']
source = { :git => 'https://github.com/facebook/react-native.git' }
if version == '1000.0.0'
# This is an unpublished version, use the latest commit hash of the react-native repo, which were presumably in.
source[:commit] = `git rev-parse HEAD`.strip if system("git rev-parse --git-dir > /dev/null 2>&1")
else
source[:tag] = "v#{version}"
end
folly_config = get_folly_config()
folly_compiler_flags = folly_config[:compiler_flags]
folly_version = folly_config[:version]
is_new_arch_enabled = ENV["RCT_NEW_ARCH_ENABLED"] == "1"
use_hermes = ENV['USE_HERMES'] == nil || ENV['USE_HERMES'] == '1'
new_arch_enabled_flag = (is_new_arch_enabled ? " -DRCT_NEW_ARCH_ENABLED" : "")
is_fabric_enabled = true #is_new_arch_enabled || ENV["RCT_FABRIC_ENABLED"]
hermes_flag = (use_hermes ? " -DUSE_HERMES" : "")
other_cflags = "$(inherited)" + folly_compiler_flags + new_arch_enabled_flag + hermes_flag
header_search_paths = [
"$(PODS_TARGET_SRCROOT)/../../ReactCommon",
"$(PODS_ROOT)/Headers/Private/React-Core",
"$(PODS_ROOT)/boost",
"$(PODS_ROOT)/DoubleConversion",
"$(PODS_ROOT)/fmt/include",
"$(PODS_ROOT)/RCT-Folly",
"${PODS_ROOT}/Headers/Public/FlipperKit",
"$(PODS_ROOT)/Headers/Public/ReactCommon",
"$(PODS_ROOT)/Headers/Public/React-RCTFabric",
"$(PODS_ROOT)/Headers/Private/Yoga",
].concat(use_hermes ? [
"$(PODS_ROOT)/Headers/Public/React-hermes",
"$(PODS_ROOT)/Headers/Public/hermes-engine"
] : [])
Pod::Spec.new do |s|
s.name = "React-RCTAppDelegate"
s.version = version
s.summary = "An utility library to simplify common operations for the New Architecture"
s.homepage = "https://reactnative.dev/"
s.documentation_url = "https://reactnative.dev/"
s.license = package["license"]
s.author = "Meta Platforms, Inc. and its affiliates"
s.platforms = min_supported_versions
s.source = source
s.source_files = "**/*.{c,h,m,mm,S,cpp}"
# This guard prevent to install the dependencies when we run `pod install` in the old architecture.
s.compiler_flags = other_cflags
s.pod_target_xcconfig = {
"HEADER_SEARCH_PATHS" => header_search_paths,
"OTHER_CPLUSPLUSFLAGS" => other_cflags,
"CLANG_CXX_LANGUAGE_STANDARD" => "c++20",
"DEFINES_MODULE" => "YES"
}
s.user_target_xcconfig = { "HEADER_SEARCH_PATHS" => "\"$(PODS_ROOT)/Headers/Private/React-Core\""}
use_hermes = ENV['USE_HERMES'] == nil || ENV['USE_HERMES'] == "1"
s.dependency "React-Core"
s.dependency "RCT-Folly", folly_version
s.dependency "RCTRequired"
s.dependency "RCTTypeSafety"
s.dependency "React-RCTNetwork"
s.dependency "React-RCTImage"
s.dependency "React-CoreModules"
s.dependency "React-nativeconfig"
s.dependency "React-Codegen"
add_dependency(s, "ReactCommon", :subspec => "turbomodule/core", :additional_framework_paths => ["react/nativemodule/core"])
add_dependency(s, "React-NativeModulesApple")
add_dependency(s, "React-runtimescheduler")
add_dependency(s, "React-RCTFabric", :framework_name => "RCTFabric")
add_dependency(s, "React-RuntimeCore")
add_dependency(s, "React-RuntimeApple")
add_dependency(s, "React-Fabric", :additional_framework_paths => ["react/renderer/components/view/platform/cxx"])
add_dependency(s, "React-graphics", :additional_framework_paths => ["react/renderer/graphics/platform/ios"])
add_dependency(s, "React-utils")
add_dependency(s, "React-debug")
add_dependency(s, "React-rendererdebug")
if use_hermes
s.dependency "React-hermes"
s.dependency "React-RuntimeHermes"
else
s.dependency "React-jsc"
end
end