Skip to content

Commit ec19b16

Browse files
coadofacebook-github-bot
authored andcommitted
iOS: Add new configuration for RCTDevMenu (#53505)
Summary: Following the [RFC](react-native-community/discussions-and-proposals#925), this PR adds new `RCTDevMenu` configuration and extends `RCTReactNativeFactory` API for passing it to the particular `RCTHost`. The `RCTDevMenuConfiguration` includes: - isDevMenuEnabled, - isShakeGestureEnabled, - areKeyboardShortcutsEnabled ## Changelog: [IOS][ADDED] - Add new configuration for `RCTDevMenu` <!-- Help reviewers and the release process by writing your own changelog entry. Pick one each for the category and type tags: [ANDROID|GENERAL|IOS|INTERNAL] [BREAKING|ADDED|CHANGED|DEPRECATED|REMOVED|FIXED|SECURITY] - Message For more details, see: https://reactnative.dev/contributing/changelogs-in-pull-requests Test Plan: Tested with different configurations on `RCTDevMenuConfiguration`: <details> <summary>Click to view code</summary> ```objc - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { self.reactNativeFactory = [[RCTReactNativeFactory alloc] initWithDelegate:self]; #if USE_OSS_CODEGEN self.dependencyProvider = [RCTAppDependencyProvider new]; #endif RCTDevMenuConfiguration *devMenuConfiguration = [[RCTDevMenuConfiguration alloc] initWithDevMenuEnabled:true shakeGestureEnabled:false keyboardShortcutsEnabled:false]; [self.reactNativeFactory setDevMenuConfiguration:devMenuConfiguration]; self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; [self.reactNativeFactory startReactNativeWithModuleName:@"RNTesterApp" inWindow:self.window initialProperties:[self prepareInitialProps] launchOptions:launchOptions]; [[UNUserNotificationCenter currentNotificationCenter] setDelegate:self]; return YES; } ``` </details> Run helloworld: <img src="https://github.com/user-attachments/assets/16c35176-6fbe-498c-96fd-a0fe988a5e3c" alt="hello-world-screenshot" width="300"> Differential Revision: D81684275 Pulled By: coado
1 parent f599e2a commit ec19b16

File tree

19 files changed

+387
-35
lines changed

19 files changed

+387
-35
lines changed

packages/react-native/Libraries/AppDelegate/RCTReactNativeFactory.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
@class RCTBridge;
2525
@protocol RCTComponentViewProtocol;
2626
@class RCTSurfacePresenterBridgeAdapter;
27+
@class RCTDevMenuConfiguration;
2728

2829
NS_ASSUME_NONNULL_BEGIN
2930

@@ -116,6 +117,8 @@ typedef NS_ENUM(NSInteger, RCTReleaseLevel) { Canary, Experimental, Stable };
116117

117118
@property (nonatomic, weak) id<RCTReactNativeFactoryDelegate> delegate;
118119

120+
@property (nonatomic, nullable) RCTDevMenuConfiguration *devMenuConfiguration;
121+
119122
@end
120123

121124
NS_ASSUME_NONNULL_END

packages/react-native/Libraries/AppDelegate/RCTReactNativeFactory.mm

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
#import "RCTReactNativeFactory.h"
99
#import <React/RCTColorSpaceUtils.h>
10+
#import <React/RCTDevMenu.h>
1011
#import <React/RCTLog.h>
1112
#import <React/RCTRootView.h>
1213
#import <React/RCTSurfacePresenterBridgeAdapter.h>
@@ -82,7 +83,8 @@ - (void)startReactNativeWithModuleName:(NSString *)moduleName
8283
{
8384
UIView *rootView = [self.rootViewFactory viewWithModuleName:moduleName
8485
initialProperties:initialProperties
85-
launchOptions:launchOptions];
86+
launchOptions:launchOptions
87+
devMenuConfiguration:self.devMenuConfiguration];
8688
UIViewController *rootViewController = [_delegate createRootViewController];
8789
[_delegate setRootView:rootView toRootViewController:rootViewController];
8890
window.rootViewController = rootViewController;

packages/react-native/Libraries/AppDelegate/RCTRootViewFactory.h

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
@class RCTHost;
1919
@class RCTRootView;
2020
@class RCTSurfacePresenterBridgeAdapter;
21+
@class RCTDevMenuConfiguration;
2122

2223
NS_ASSUME_NONNULL_BEGIN
2324

@@ -201,7 +202,13 @@ typedef void (^RCTLoadSourceForBridgeBlock)(RCTBridge *bridge, RCTSourceLoadBloc
201202
* @parameter: moduleName - the name of the app, used by Metro to resolve the module.
202203
* @parameter: initialProperties - a set of initial properties.
203204
* @parameter: launchOptions - a dictionary with a set of options.
205+
* @parameter: devMenuConfiguration - a configuration for enabling/disabling dev menu.
204206
*/
207+
- (UIView *_Nonnull)viewWithModuleName:(NSString *)moduleName
208+
initialProperties:(NSDictionary *__nullable)initialProperties
209+
launchOptions:(NSDictionary *__nullable)launchOptions
210+
devMenuConfiguration:(RCTDevMenuConfiguration *__nullable)devMenuConfiguration;
211+
205212
- (UIView *_Nonnull)viewWithModuleName:(NSString *)moduleName
206213
initialProperties:(NSDictionary *__nullable)initialProperties
207214
launchOptions:(NSDictionary *__nullable)launchOptions;
@@ -219,11 +226,16 @@ typedef void (^RCTLoadSourceForBridgeBlock)(RCTBridge *bridge, RCTSourceLoadBloc
219226
* Use it to speed up later viewWithModuleName: calls.
220227
*
221228
* @parameter: launchOptions - a dictionary with a set of options.
229+
* @parameter: devMenuConfiguration - a configuration for enabling/disabling dev menu.
222230
*/
223-
- (void)initializeReactHostWithLaunchOptions:(NSDictionary *__nullable)launchOptions;
231+
- (void)initializeReactHostWithLaunchOptions:(NSDictionary *__nullable)launchOptions
232+
devMenuConfiguration:(RCTDevMenuConfiguration *)devMenuConfiguration;
224233

225234
- (RCTHost *)createReactHost:(NSDictionary *__nullable)launchOptions;
226235

236+
- (RCTHost *)createReactHost:(NSDictionary *__nullable)launchOptions
237+
devMenuConfiguration:(RCTDevMenuConfiguration *__nullable)devMenuConfiguration;
238+
227239
@end
228240

229241
NS_ASSUME_NONNULL_END

packages/react-native/Libraries/AppDelegate/RCTRootViewFactory.mm

Lines changed: 33 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
#import "RCTRootViewFactory.h"
99
#import <React/RCTCxxBridgeDelegate.h>
10+
#import <React/RCTDevMenu.h>
1011
#import <React/RCTLog.h>
1112
#import <React/RCTRootView.h>
1213
#import <React/RCTSurfacePresenterBridgeAdapter.h>
@@ -133,29 +134,47 @@ - (instancetype)initWithConfiguration:(RCTRootViewFactoryConfiguration *)configu
133134

134135
- (UIView *)viewWithModuleName:(NSString *)moduleName initialProperties:(NSDictionary *)initialProperties
135136
{
136-
return [self viewWithModuleName:moduleName initialProperties:initialProperties launchOptions:nil];
137+
return [self viewWithModuleName:moduleName
138+
initialProperties:initialProperties
139+
launchOptions:nil
140+
devMenuConfiguration:[RCTDevMenuConfiguration defaultConfiguration]];
137141
}
138142

139143
- (UIView *)viewWithModuleName:(NSString *)moduleName
140144
{
141-
return [self viewWithModuleName:moduleName initialProperties:nil launchOptions:nil];
145+
return [self viewWithModuleName:moduleName
146+
initialProperties:nil
147+
launchOptions:nil
148+
devMenuConfiguration:[RCTDevMenuConfiguration defaultConfiguration]];
142149
}
143150

144151
- (void)initializeReactHostWithLaunchOptions:(NSDictionary *)launchOptions
152+
devMenuConfiguration:(RCTDevMenuConfiguration *)devMenuConfiguration
145153
{
146154
// Enable TurboModule interop by default in Bridgeless mode
147155
RCTEnableTurboModuleInterop(YES);
148156
RCTEnableTurboModuleInteropBridgeProxy(YES);
149157

150-
[self createReactHostIfNeeded:launchOptions];
158+
[self createReactHostIfNeeded:launchOptions devMenuConfiguration:devMenuConfiguration];
151159
return;
152160
}
153161

162+
- (UIView *)viewWithModuleName:(NSString *)moduleName
163+
initialProperties:(NSDictionary *)initialProperties
164+
launchOptions:(NSDictionary *)launchOptions
165+
{
166+
return [self viewWithModuleName:moduleName
167+
initialProperties:initialProperties
168+
launchOptions:launchOptions
169+
devMenuConfiguration:[RCTDevMenuConfiguration defaultConfiguration]];
170+
}
171+
154172
- (UIView *)viewWithModuleName:(NSString *)moduleName
155173
initialProperties:(NSDictionary *)initProps
156174
launchOptions:(NSDictionary *)launchOptions
175+
devMenuConfiguration:(RCTDevMenuConfiguration *)devMenuConfiguration
157176
{
158-
[self initializeReactHostWithLaunchOptions:launchOptions];
177+
[self initializeReactHostWithLaunchOptions:launchOptions devMenuConfiguration:devMenuConfiguration];
159178

160179
RCTFabricSurface *surface = [self.reactHost createSurfaceWithModuleName:moduleName
161180
initialProperties:initProps ? initProps : @{}];
@@ -226,14 +245,21 @@ - (void)createBridgeAdapterIfNeeded
226245
#pragma mark - New Arch Utilities
227246

228247
- (void)createReactHostIfNeeded:(NSDictionary *)launchOptions
248+
devMenuConfiguration:(RCTDevMenuConfiguration *)devMenuConfiguration
229249
{
230250
if (self.reactHost) {
231251
return;
232252
}
233-
self.reactHost = [self createReactHost:launchOptions];
253+
self.reactHost = [self createReactHost:launchOptions devMenuConfiguration:devMenuConfiguration];
254+
}
255+
256+
- (RCTHost *)createReactHost:(NSDictionary *)launchOptions
257+
{
258+
return [self createReactHost:launchOptions devMenuConfiguration:[RCTDevMenuConfiguration defaultConfiguration]];
234259
}
235260

236261
- (RCTHost *)createReactHost:(NSDictionary *)launchOptions
262+
devMenuConfiguration:(RCTDevMenuConfiguration *)devMenuConfiguration
237263
{
238264
__weak __typeof(self) weakSelf = self;
239265
RCTHost *reactHost =
@@ -243,7 +269,8 @@ - (RCTHost *)createReactHost:(NSDictionary *)launchOptions
243269
jsEngineProvider:^std::shared_ptr<facebook::react::JSRuntimeFactory>() {
244270
return [weakSelf createJSRuntimeFactory];
245271
}
246-
launchOptions:launchOptions];
272+
launchOptions:launchOptions
273+
devMenuConfiguration:devMenuConfiguration];
247274
[reactHost setBundleURLProvider:^NSURL *() {
248275
return [weakSelf bundleURL];
249276
}];

packages/react-native/React/Base/RCTBundleURLProvider.mm

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818

1919
const NSUInteger kRCTBundleURLProviderDefaultPort = RCT_METRO_PORT;
2020

21-
#if RCT_DEV_MENU | RCT_PACKAGER_LOADING_FUNCTIONALITY
21+
#if RCT_DEV | RCT_PACKAGER_LOADING_FUNCTIONALITY
2222
static BOOL kRCTAllowPackagerAccess = YES;
2323
void RCTBundleURLProviderAllowPackagerServerAccess(BOOL allowed)
2424
{
@@ -78,7 +78,7 @@ - (void)resetToDefaults
7878
(unsigned long)kRCTBundleURLProviderDefaultPort]];
7979
}
8080

81-
#if RCT_DEV_MENU | RCT_PACKAGER_LOADING_FUNCTIONALITY
81+
#if RCT_DEV | RCT_PACKAGER_LOADING_FUNCTIONALITY
8282
+ (BOOL)isPackagerRunning:(NSString *)hostPort
8383
{
8484
return [RCTBundleURLProvider isPackagerRunning:hostPort scheme:nil];
@@ -155,14 +155,14 @@ - (NSString *)packagerServerHost
155155

156156
- (NSString *)packagerServerHostPort
157157
{
158-
#if RCT_DEV_MENU | RCT_PACKAGER_LOADING_FUNCTIONALITY
158+
#if RCT_DEV | RCT_PACKAGER_LOADING_FUNCTIONALITY
159159
if (!kRCTAllowPackagerAccess) {
160160
RCTLogInfo(@"Packager server access is disabled in this environment");
161161
return nil;
162162
}
163163
#endif
164164
NSString *location = [self jsLocation];
165-
#if RCT_DEV_MENU
165+
#if RCT_DEV
166166
NSString *scheme = [self packagerScheme];
167167
if ([location length] && ![RCTBundleURLProvider isPackagerRunning:location scheme:scheme]) {
168168
location = nil;

packages/react-native/React/CoreModules/RCTDevMenu.h

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,26 @@
1212
#import <React/RCTBridgeProxy.h>
1313
#import <React/RCTDefines.h>
1414

15+
RCT_EXTERN NSString *const RCTShowDevMenuNotification;
16+
17+
@interface RCTDevMenuConfiguration : NSObject
18+
1519
#if RCT_DEV_MENU
1620

17-
RCT_EXTERN NSString *const RCTShowDevMenuNotification;
21+
@property (nonatomic, readonly) BOOL isDevMenuEnabled;
22+
@property (nonatomic, readonly) BOOL isShakeGestureEnabled;
23+
@property (nonatomic, readonly) BOOL areKeyboardShortcutsEnabled;
24+
25+
- (instancetype)initWithDevMenuEnabled:(BOOL)isDevMenuEnabled
26+
shakeGestureEnabled:(BOOL)isShakeGestureEnabled
27+
keyboardShortcutsEnabled:(BOOL)areKeyboardShortcutsEnabled;
1828

1929
#endif
2030

31+
+ (instancetype)defaultConfiguration;
32+
33+
@end
34+
2135
@class RCTDevMenuItem;
2236

2337
/**
@@ -45,6 +59,16 @@ RCT_EXTERN NSString *const RCTShowDevMenuNotification;
4559
*/
4660
@property (nonatomic, assign) BOOL hotkeysEnabled;
4761

62+
/**
63+
* Whether the developer menu is enabled.
64+
*/
65+
@property (nonatomic, assign) BOOL isDevMenuEnabled;
66+
67+
/**
68+
* Whether keyboard shortcuts are enabled.
69+
*/
70+
@property (nonatomic, assign) BOOL areKeyboardShortcutsEnabled;
71+
4872
/**
4973
* Presented items in development menu
5074
*/
@@ -76,6 +100,11 @@ RCT_EXTERN NSString *const RCTShowDevMenuNotification;
76100
*/
77101
- (void)addItem:(RCTDevMenuItem *)item;
78102

103+
/**
104+
* Disable the reload command (Cmd+R) in the simulator.
105+
*/
106+
- (void)disableReloadCommand;
107+
79108
@end
80109

81110
typedef NSString * (^RCTDevMenuItemTitleBlock)(void);

0 commit comments

Comments
 (0)