Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
69 commits
Select commit Hold shift + click to select a range
917f539
feat: migrate to SceneDelegate, update RNTester code
artus9033 Sep 10, 2025
8b4adc0
feat: provide two configurations for launching RNTester based on Scen…
artus9033 Sep 10, 2025
2863c4c
feat: migrate RNTester NativeExampleViews to support SceneDelegate
artus9033 Sep 10, 2025
d27e491
chore: remove obsolete code
artus9033 Sep 10, 2025
0ac5467
chore: updated Podfile.lock
artus9033 Sep 10, 2025
0232d98
chore: revert unnecessary migration in RCTDeviceInfo
artus9033 Sep 10, 2025
a81e935
fix: migrate usages of application.delegate.window to use RCTKeyWindo…
artus9033 Sep 10, 2025
6a0dce2
feat: add NativeDeviceInfo.getInfo, deprecate NativeDeviceInfo.getCon…
artus9033 Sep 11, 2025
641a29c
test: test if getInfo works and has Dimensions property
artus9033 Sep 11, 2025
d961af6
feat: added imperative non-subscription demos to DimensionsExample in…
artus9033 Sep 11, 2025
dc7763c
feat: stub for DeviceInfoModule.getInfo CXX implementation
artus9033 Sep 11, 2025
c0bc778
fix: RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD RCTDeviceInfo.getInfo
artus9033 Sep 11, 2025
c77f68a
fix(test): fix integration tests js app problems due to ES exports
artus9033 Sep 11, 2025
1e7a30e
fix(test): fix unit tests compilation errors
artus9033 Sep 11, 2025
5448f10
fix: ensure that RCTDeviceInfo::invalidateCachedInfo logic is run on …
artus9033 Sep 11, 2025
7eebb2f
fix(test): add jest mock for JS DeviceInfo.getInfo
artus9033 Sep 11, 2025
1f25576
fix(test): fix AccessibilityManagerTest failing because of handling l…
artus9033 Sep 11, 2025
d436cd8
refactor: explicitly depend on retained self in RCTExecuteOnMainQueue…
artus9033 Sep 12, 2025
75d2c66
refactor: typo in TODO comment in RCTDeviceInfo
artus9033 Sep 12, 2025
5045ad8
test: disable AccessibilityManagerTest due to T225745315
artus9033 Sep 12, 2025
cb9a5b4
docs: update unit and integration tests instructions
artus9033 Sep 13, 2025
697758b
Merge branch 'main' into artur/feat/scene-delegate
artus9033 Sep 13, 2025
b37bcd9
chore: update Podfile.lock
artus9033 Sep 13, 2025
de29fca
Revert "fix: RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD RCTDeviceInfo.get…
artus9033 Sep 18, 2025
2ed5739
Revert "feat: stub for DeviceInfoModule.getInfo CXX implementation"
artus9033 Sep 18, 2025
4ede7e8
Revert "fix(test): add jest mock for JS DeviceInfo.getInfo"
artus9033 Sep 18, 2025
7bc2b30
Revert "feat: add NativeDeviceInfo.getInfo, deprecate NativeDeviceInf…
artus9033 Sep 18, 2025
d3c2cd4
feat: invalidate cached value of dimensions for internal state consis…
artus9033 Sep 18, 2025
7db2384
chore: updated RNTester Podfile, integration tests xcscheme and pbxproj
artus9033 Sep 18, 2025
a4503ab
feat: deprecate getConstants in NativeDeviceInfo, introduce getInfo a…
artus9033 Sep 18, 2025
8771ff1
chore: update Podfile
artus9033 Sep 18, 2025
4268e4c
Merge branch 'main' into artur/feat/scene-delegate
artus9033 Sep 21, 2025
785f869
refactor: sort imports in DimensionsExample
artus9033 Sep 21, 2025
e332eb7
feat: added NativeDeviceInfo.getInfo API to RN API snapshot
artus9033 Sep 21, 2025
c69f974
fix: typechecking in IntegrationTestsApp.js
artus9033 Sep 21, 2025
3b0416b
feat: warn at runtime from RCTReactNativeFactory if unsupported capab…
artus9033 Sep 21, 2025
543c296
chore: update Podfile.lock
artus9033 Sep 21, 2025
6f5935a
Merge branch 'main' into artur/feat/scene-delegate
artus9033 Sep 21, 2025
3f96863
Merge branch 'main' into artur/feat/scene-delegate
artus9033 Sep 29, 2025
a72e1e3
wip: PoC fixing delayed application of ShadowTree commits after inten…
artus9033 Nov 5, 2025
f661e41
Merge remote-tracking branch 'facebook/main' into artur/feat/scene-de…
artus9033 Nov 6, 2025
5aac7cd
chore: retract the workarounds
artus9033 Nov 19, 2025
1c0c5ad
Merge branch 'main' into feat/scene-delegate
artus9033 Nov 20, 2025
2d64c04
chore: update ReactNativeApi.d.ts SignedSource
artus9033 Nov 20, 2025
ea3c55e
chore: use RCTLogWarn in RCTReactNativeFactory if running with multiw…
artus9033 Nov 20, 2025
693b31d
feat: support RCTDevLoadingView resizing
artus9033 Dec 1, 2025
b822bec
fix: print warning of unsupported configuration from hostDidStart to …
artus9033 Dec 18, 2025
d751f4c
Merge branch 'main' into feat/scene-delegate
artus9033 Dec 18, 2025
041c9bc
chore: remove new NativeDeviceInfo API
artus9033 Dec 18, 2025
a75ed5b
chore: update project.pbxproj
artus9033 Dec 18, 2025
37cfa12
feat: support resizing in RCTDevLoadingView using automatic constrain…
artus9033 Dec 18, 2025
dbad6af
Merge branch 'main' into feat/scene-delegate
artus9033 Jun 25, 2026
d874dda
feat: add RCTSceneDelegate for UIScene-based iOS app bootstrap
artus9033 Jul 9, 2026
a0b8944
feat: migrate RNTester and HelloWorld to RCTSceneDelegate
artus9033 Jul 9, 2026
0820933
Merge branch 'main' into feat/scene-delegate
artus9033 Jul 12, 2026
d5a5a6d
fix: helloworld text to be visible in dark mode, missing Gems in hell…
artus9033 Jul 13, 2026
0979697
fix: RCTAppDelegate to depend on RCTLinking
artus9033 Jul 13, 2026
78f298c
fix(types): comply with Flow linter
artus9033 Jul 13, 2026
49816a3
chore: commit cxx API files
artus9033 Jul 13, 2026
bdf5a0a
feat: assert that the users do not enable multiple scenes
artus9033 Jul 14, 2026
48d6172
chore: deintegrate RCTSceneDelegate after CR
artus9033 Jul 15, 2026
46e9ee9
chore: remove RCT_REMOVE_LEGACY_ARCH conditionals as it is not possib…
artus9033 Jul 22, 2026
5241090
refactor: do not use inverted logic in RCTLinkingManager
artus9033 Jul 22, 2026
6fa4f4b
Revert "fix(test): fix integration tests js app problems due to ES ex…
artus9033 Jul 22, 2026
d4cab37
chore: drop AppDelegate support in RNTester
artus9033 Jul 22, 2026
d09a548
chore: deintegrate legacy AppDelegate from helloworld
artus9033 Jul 22, 2026
5453a82
Merge branch 'main' into feat/scene-delegate
cipolleschi Jul 23, 2026
6409517
Merge branch 'main' into feat/scene-delegate
cipolleschi Jul 23, 2026
6380d24
chore: regenerate CXX API definitions
artus9033 Jul 23, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 7 additions & 10 deletions packages/react-native/Libraries/AppDelegate/RCTAppDelegate.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,12 @@
NS_ASSUME_NONNULL_BEGIN

/**
* @deprecated RCTAppDelegate is deprecated and will be removed in a future version of React Native. Use
`RCTReactNativeFactory` instead.
* @deprecated RCTAppDelegate is deprecated and will be removed in a future version of React Native. For new apps
* using the UIScene lifecycle, implement your own `SceneDelegate` with `RCTReactNativeFactory` (see integration
* docs). For AppDelegate-only apps, use `RCTReactNativeFactory` directly.
*
* Scene-based apps must keep `UIApplicationSupportsMultipleScenes` set to `false` in Info.plist. Define
* `RN_ALLOW_MULTIPLE_SCENES` on the app target to downgrade the unsupported-configuration crash to a warning.
*
* 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.
Expand Down Expand Up @@ -55,19 +59,12 @@ NS_ASSUME_NONNULL_BEGIN
* - (id<RCTTurboModule>)getModuleInstanceFromClass:(Class)moduleClass
*/
__attribute__((deprecated(
"RCTAppDelegate is deprecated and will be removed in a future version of React Native. Use `RCTReactNativeFactory` instead.")))
"RCTAppDelegate is deprecated and will be removed in a future version of React Native. For UIScene apps implement your own SceneDelegate with RCTReactNativeFactory; otherwise use RCTReactNativeFactory.")))
@interface RCTAppDelegate : RCTDefaultReactNativeFactoryDelegate<UIApplicationDelegate>

/// The window object, used to render the UViewControllers
@property (nonatomic, strong, nonnull) UIWindow *window;

#if !defined(RCT_REMOVE_LEGACY_ARCH)
@property (nonatomic, nullable) RCTBridge *bridge
__attribute__((deprecated("The bridge is deprecated and will be removed when removing the legacy architecture.")));
@property (nonatomic, nullable) RCTSurfacePresenterBridgeAdapter *bridgeAdapter __attribute__((
deprecated("The bridge adapter is deprecated and will be removed when removing the legacy architecture.")));
#endif

@property (nonatomic, strong, nullable) NSString *moduleName;
@property (nonatomic, strong, nullable) NSDictionary *initialProps;
@property (nonatomic, strong) RCTReactNativeFactory *reactNativeFactory;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ - (RCTColorSpace)defaultColorSpace

- (NSURL *_Nullable)bundleURL
{
[NSException raise:@"RCTAppDelegate::bundleURL not implemented"
[NSException raise:@"RCTReactNativeFactoryDelegate::bundleURL not implemented"
format:@"Subclasses must implement a valid getBundleURL method"];
return nullptr;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,21 @@ typedef NS_ENUM(NSInteger, RCTReleaseLevel) { Canary, Experimental, Stable };

@interface RCTReactNativeFactory : NSObject

/**
* Bootstrap entrypoints:
* - **AppDelegate path**: `startReactNativeWithModuleName:inWindow:launchOptions:` — call from
* `application:didFinishLaunchingWithOptions:` or `RCTAppDelegate`.
* - **SceneDelegate path**: `startReactNativeWithModuleName:inWindow:connectionOptions:` — call from
* `scene:willConnectToSession:options:` in your app-owned `SceneDelegate` (subclass
* `RCTDefaultReactNativeFactoryDelegate` and conform to `UIWindowSceneDelegate`).
*
* **Multi-scene / multi-window (unsupported):** When using the SceneDelegate path, React Native
* checks that Info.plist does not set `UIApplicationSupportsMultipleScenes` to `true`, since
* running multiple React Native instances in one process is unsupported. The app crashes by default;
* define `RN_ALLOW_MULTIPLE_SCENES` on the app target (e.g. `GCC_PREPROCESSOR_DEFINITIONS` or
* `OTHER_CFLAGS`: `-DRN_ALLOW_MULTIPLE_SCENES=1`) to downgrade the check to a warning.
*/

- (instancetype)initWithDelegate:(id<RCTReactNativeFactoryDelegate>)delegate;

- (instancetype)initWithDelegate:(id<RCTReactNativeFactoryDelegate>)delegate releaseLevel:(RCTReleaseLevel)releaseLevel;
Expand All @@ -73,10 +88,31 @@ typedef NS_ENUM(NSInteger, RCTReleaseLevel) { Canary, Experimental, Stable };
initialProperties:(NSDictionary *_Nullable)initialProperties
launchOptions:(NSDictionary *_Nullable)launchOptions;

#if !defined(RCT_REMOVE_LEGACY_ARCH)
@property (nonatomic, nullable) RCTSurfacePresenterBridgeAdapter *bridgeAdapter __attribute__((
deprecated("The bridgeAdapter is deprecated and will be removed when removing the legacy architecture.")));
#endif
/// This is a SceneDelegate entrypoint method to start a React Native instance with the specified module name, window
/// and connection options for linking & user activity information. As it's usual for the typical deep-linking use case,
/// only the first item in URLContexts from connectionOptions will be checked; the same applies to userActivities.
/// @param moduleName name of the JS module to load
/// @param window the window to launch in
/// @param connectionOptions the scene's connection options
- (void)startReactNativeWithModuleName:(NSString *)moduleName
inWindow:(UIWindow *_Nullable)window
connectionOptions:(UISceneConnectionOptions *_Nullable)connectionOptions;

/// This is a SceneDelegate entrypoint method to start a React Native instance with the specified module name, window
/// and connection options for linking, initial properties & user activity information. As it's usual for the typical
/// deep-linking use case, only the first item in URLContexts from connectionOptions will be checked; the same applies
/// to userActivities.
/// @param moduleName name of the JS module to load
/// @param window the window to launch in
/// @param initialProperties the initial root properties
/// @param connectionOptions the scene's connection options
- (void)startReactNativeWithModuleName:(NSString *)moduleName
inWindow:(UIWindow *_Nullable)window
initialProperties:(NSDictionary *_Nullable)initialProperties
connectionOptions:(UISceneConnectionOptions *_Nullable)connectionOptions;

@property (nonatomic, nullable) RCTBridge *bridge
__attribute__((deprecated("The bridge is deprecated and will be removed when removing the legacy architecture.")));

@property (nonatomic, strong, nonnull) RCTRootViewFactory *rootViewFactory;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,13 @@ @interface RCTReactNativeFactory () <
RCTHostDelegate,
RCTJSRuntimeConfiguratorProtocol,
RCTTurboModuleManagerDelegate>

/// Adapter for SceneDelegate entrypoint's UISceneConnectionOptions that converts it to the AppDelegate-style
/// NSDictionary for internal RN needs
/// @param connectionOptions the scene's connection options
/// @return an NSDictionary with proper UIApplicationLaunchOptions- keys set to values from connectionOptions
- (NSDictionary *)convertConnectionOptionsToLaunchOptions:(UISceneConnectionOptions *)connectionOptions;

@end

@implementation RCTReactNativeFactory
Expand Down Expand Up @@ -95,6 +102,58 @@ - (void)startReactNativeWithModuleName:(NSString *)moduleName
[window makeKeyAndVisible];
}

#pragma mark - UIScene.ConnectionOptions

- (void)startReactNativeWithModuleName:(NSString *)moduleName
inWindow:(UIWindow *_Nullable)window
connectionOptions:(UISceneConnectionOptions *_Nullable)connectionOptions
{
[self startReactNativeWithModuleName:moduleName
inWindow:window
initialProperties:nil
launchOptions:[self convertConnectionOptionsToLaunchOptions:connectionOptions]];
}

- (void)startReactNativeWithModuleName:(NSString *)moduleName
inWindow:(UIWindow *_Nullable)window
initialProperties:(NSDictionary *_Nullable)initialProperties
connectionOptions:(UISceneConnectionOptions *_Nullable)connectionOptions
{
[self startReactNativeWithModuleName:moduleName
inWindow:window
initialProperties:initialProperties
launchOptions:[self convertConnectionOptionsToLaunchOptions:connectionOptions]];
}

- (NSDictionary *)convertConnectionOptionsToLaunchOptions:(UISceneConnectionOptions *)connectionOptions
{
NSMutableDictionary *launchOptions = [NSMutableDictionary dictionary];

// handle launch URL
if (connectionOptions.URLContexts.count > 0) {
UIOpenURLContext *urlContext = connectionOptions.URLContexts.allObjects.firstObject;

if (urlContext.URL) {
launchOptions[UIApplicationLaunchOptionsURLKey] = urlContext.URL;
}
}

// handle user activities
if (connectionOptions.userActivities.count > 0) {
NSUserActivity *activity = connectionOptions.userActivities.allObjects.firstObject;

if (activity) {
NSMutableDictionary *userActivityDict = [NSMutableDictionary dictionary];
userActivityDict[UIApplicationLaunchOptionsUserActivityTypeKey] = activity.activityType;
userActivityDict[@"UIApplicationLaunchOptionsUserActivityKey"] = activity;

launchOptions[UIApplicationLaunchOptionsUserActivityDictionaryKey] = userActivityDict;
}
}

return launchOptions;
}

#pragma mark - RCTUIConfiguratorProtocol

- (RCTColorSpace)defaultColorSpace
Expand Down Expand Up @@ -209,6 +268,25 @@ - (void)hostDidStart:(RCTHost *)host
{
if ([_delegate respondsToSelector:@selector(hostDidStart:)]) {
[_delegate hostDidStart:host];

// check if the application is running with multiple scenes capability enabled in scene manifest (Info.plist),
// which is unsupported by RN at the moment, and crash in such case (unless RN_ALLOW_MULTIPLE_SCENES is defined).
// To opt out, add RN_ALLOW_MULTIPLE_SCENES=1 to the app target's GCC_PREPROCESSOR_DEFINITIONS or
// -DRN_ALLOW_MULTIPLE_SCENES=1 to OTHER_CFLAGS.
NSDictionary *infoDict = [[NSBundle mainBundle] infoDictionary];
NSDictionary *sceneManifest = infoDict ? infoDict[@"UIApplicationSceneManifest"] : nil;
BOOL supportsMultipleScenes =
sceneManifest ? [sceneManifest[@"UIApplicationSupportsMultipleScenes"] boolValue] : false;

if (supportsMultipleScenes) {
NSString *const message =
@"RCTReactNativeFactory: (FATAL - UNSUPPORTED RN APP CONFIGURATION) Your application is running with the Info.plist UIApplicationSceneManifest.UIApplicationSupportsMultipleScenes key set to true, which is NOT supported by React Native at the moment. Allowing the user to run multiple windows of a RN application means allowing to run multiple instances of React Native and libraries in the same process, which may cause ALL SORTS OF PROBLEMS in implementations which use singletons or static storage lifetime variables. Define RN_ALLOW_MULTIPLE_SCENES to downgrade this to a warning if you know what you are doing.";
#if defined(RN_ALLOW_MULTIPLE_SCENES)
RCTLogWarn(message);
#else
[NSException raise:@"RCTReactNativeFactory::unsupportedMultipleScenesConfiguration" format:@"%@", message];
#endif
}
Comment thread
artus9033 marked this conversation as resolved.
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -184,11 +184,6 @@ typedef void (^RCTLoadSourceForBridgeBlock)(RCTBridge *bridge, RCTSourceLoadBloc
*/
@interface RCTRootViewFactory : NSObject

#if !defined(RCT_REMOVE_LEGACY_ARCH)
@property (nonatomic, strong, nullable) RCTBridge *bridge;
@property (nonatomic, strong, nullable) RCTSurfacePresenterBridgeAdapter *bridgeAdapter;
#endif

@property (nonatomic, strong, nullable) RCTHost *reactHost;

- (instancetype)initWithConfiguration:(RCTRootViewFactoryConfiguration *)configuration
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
#import <React/RCTRootView.h>
#import <React/RCTUtils.h>
#import <react/renderer/runtimescheduler/RuntimeScheduler.h>
#import "RCTAppDelegate.h"
#import "RCTAppSetupUtils.h"

#if RN_DISABLE_OSS_PLUGIN_HEADER
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ NS_ASSUME_NONNULL_BEGIN

/**
* 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`:
* Override on your `RCTReactNativeFactoryDelegate` (e.g. in AppDelegate, SceneDelegate, or
* `RCTAppDelegate` subclass). Example:
* ```
* - (void)customizeRootView:(RCTRootView *)rootView
* {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ Pod::Spec.new do |s|
s.dependency "RCTTypeSafety"
s.dependency "React-RCTNetwork"
s.dependency "React-RCTImage"
s.dependency "React-RCTLinking"
s.dependency "React-CoreModules"
s.dependency "React-RCTFBReactNativeSpec"
s.dependency "React-defaultsnativemodule"
Expand Down
25 changes: 25 additions & 0 deletions packages/react-native/Libraries/LinkingIOS/RCTLinkingManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,42 @@

@interface RCTLinkingManager : RCTEventEmitter

/**
* Deep linking integration supports two iOS lifecycle paths:
* - **AppDelegate methods** (below): use when the app does not declare `UIApplicationSceneManifest` in Info.plist.
* - **SceneDelegate methods** (below): use when the app uses the UIScene lifecycle. Forward these from your
* app-owned `SceneDelegate`.
*/

#pragma mark - AppDelegate methods

/// Lifecycle method informing of a URL being opened with the app.
/// Invoke from AppDelegate for non-scene apps (no `UIApplicationSceneManifest` in Info.plist).
/// Note: this is an implementation using the iOS 9.0-26.0 API
+ (BOOL)application:(nonnull UIApplication *)app
openURL:(nonnull NSURL *)URL
options:(nonnull NSDictionary<UIApplicationOpenURLOptionsKey, id> *)options;

/// Lifecycle method handling a URL being opened with the app.
/// Invoke from AppDelegate for non-scene apps.
/// Note: this is an implementation using the iOS 4.2-9.0 API
+ (BOOL)application:(nonnull UIApplication *)application
openURL:(nonnull NSURL *)URL
sourceApplication:(nullable NSString *)sourceApplication
annotation:(nonnull id)annotation;

/// Lifecycle method handling user activity being performed.
/// Invoke from AppDelegate for non-scene apps.
+ (BOOL)application:(nonnull UIApplication *)application
continueUserActivity:(nonnull NSUserActivity *)userActivity
restorationHandler:(nonnull void (^)(NSArray<id<UIUserActivityRestoring>> *_Nullable))restorationHandler;

#pragma mark - SceneDelegate methods

/// Handles user activity for scene-based apps. Invoke from your SceneDelegate.
+ (void)scene:(nonnull UIScene *)scene continueUserActivity:(nonnull NSUserActivity *)userActivity;

/// Handles URLs opened while the app is running for scene-based apps. Invoke from your SceneDelegate.
+ (void)scene:(nonnull UIScene *)scene openURLContexts:(nonnull NSSet<UIOpenURLContext *> *)URLContexts;

@end
Loading
Loading