Add RCTDevSettings module
Summary:
This decouples non-UI logic from RCTDevMenu into a new module RCTDevSettings.
**Motivation**: This allows developers to change dev settings without depending on the built-in dev menu, e.g. if they want to introduce their own UI, or have other devtools logic that doesn't depend on an action sheet.
It also introduces the RCTDevSettingsDataSource protocol for storing dev tools preferences. This could allow a developer to implement alternative behaviors, e.g. loading the settings from some other config, changing settings based on the user, deciding not to persist some settings, or something else.
The included data source implementation, RCTDevSettingsUserDefaultsDataSource, uses NSUserDefaults and is backwards compatible with the older implementation, so **no workflows or dependent code will break, and old saved settings will persist.**
The RCTDevMenu interface has not changed and is therefore also backwards-compatible, though
some methods are now deprecated.
In order to ensure that RCTDevSettings
Closes https://github.com/facebook/react-native/pull/11613
Reviewed By: mmmulani
Differential Revision: D4571773
Pulled By: javache
fbshipit-source-id: 25555d0a6eaa81f694343e079ed02439e5845fbc
2017-02-24 14:50:29 +00:00
|
|
|
/**
|
|
|
|
* Copyright (c) 2015-present, Facebook, Inc.
|
|
|
|
* All rights reserved.
|
|
|
|
*
|
|
|
|
* This source code is licensed under the BSD-style license found in the
|
|
|
|
* LICENSE file in the root directory of this source tree. An additional grant
|
|
|
|
* of patent rights can be found in the PATENTS file in the same directory.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#import "RCTDevSettings.h"
|
|
|
|
|
|
|
|
#import <objc/runtime.h>
|
|
|
|
|
|
|
|
#import <JavaScriptCore/JavaScriptCore.h>
|
|
|
|
|
|
|
|
#import <jschelpers/JavaScriptCore.h>
|
|
|
|
|
|
|
|
#import "RCTBridge+Private.h"
|
|
|
|
#import "RCTBridgeModule.h"
|
|
|
|
#import "RCTEventDispatcher.h"
|
2017-06-08 14:34:45 +00:00
|
|
|
#import "RCTInspectorDevServerHelper.h"
|
2017-04-18 20:15:25 +00:00
|
|
|
#import "RCTJSCSamplingProfiler.h"
|
2017-06-15 18:52:08 +00:00
|
|
|
#import "RCTJSEnvironment.h"
|
Add RCTDevSettings module
Summary:
This decouples non-UI logic from RCTDevMenu into a new module RCTDevSettings.
**Motivation**: This allows developers to change dev settings without depending on the built-in dev menu, e.g. if they want to introduce their own UI, or have other devtools logic that doesn't depend on an action sheet.
It also introduces the RCTDevSettingsDataSource protocol for storing dev tools preferences. This could allow a developer to implement alternative behaviors, e.g. loading the settings from some other config, changing settings based on the user, deciding not to persist some settings, or something else.
The included data source implementation, RCTDevSettingsUserDefaultsDataSource, uses NSUserDefaults and is backwards compatible with the older implementation, so **no workflows or dependent code will break, and old saved settings will persist.**
The RCTDevMenu interface has not changed and is therefore also backwards-compatible, though
some methods are now deprecated.
In order to ensure that RCTDevSettings
Closes https://github.com/facebook/react-native/pull/11613
Reviewed By: mmmulani
Differential Revision: D4571773
Pulled By: javache
fbshipit-source-id: 25555d0a6eaa81f694343e079ed02439e5845fbc
2017-02-24 14:50:29 +00:00
|
|
|
#import "RCTLog.h"
|
|
|
|
#import "RCTProfile.h"
|
|
|
|
#import "RCTUtils.h"
|
|
|
|
|
|
|
|
NSString *const kRCTDevSettingProfilingEnabled = @"profilingEnabled";
|
|
|
|
NSString *const kRCTDevSettingHotLoadingEnabled = @"hotLoadingEnabled";
|
|
|
|
NSString *const kRCTDevSettingLiveReloadEnabled = @"liveReloadEnabled";
|
|
|
|
NSString *const kRCTDevSettingIsInspectorShown = @"showInspector";
|
|
|
|
NSString *const kRCTDevSettingIsDebuggingRemotely = @"isDebuggingRemotely";
|
|
|
|
NSString *const kRCTDevSettingExecutorOverrideClass = @"executor-override";
|
|
|
|
NSString *const kRCTDevSettingShakeToShowDevMenu = @"shakeToShow";
|
|
|
|
NSString *const kRCTDevSettingIsPerfMonitorShown = @"RCTPerfMonitorKey";
|
|
|
|
NSString *const kRCTDevSettingIsJSCProfilingEnabled = @"RCTJSCProfilerEnabled";
|
|
|
|
NSString *const kRCTDevSettingStartSamplingProfilerOnLaunch = @"startSamplingProfilerOnLaunch";
|
|
|
|
|
|
|
|
NSString *const kRCTDevSettingsUserDefaultsKey = @"RCTDevMenu";
|
|
|
|
|
2017-04-20 15:20:03 +00:00
|
|
|
#define ENABLE_PACKAGER_CONNECTION RCT_DEV && __has_include("RCTPackagerConnection.h")
|
|
|
|
|
|
|
|
#if ENABLE_PACKAGER_CONNECTION
|
|
|
|
#import "RCTPackagerConnection.h"
|
2017-02-27 21:25:47 +00:00
|
|
|
#endif
|
Add RCTDevSettings module
Summary:
This decouples non-UI logic from RCTDevMenu into a new module RCTDevSettings.
**Motivation**: This allows developers to change dev settings without depending on the built-in dev menu, e.g. if they want to introduce their own UI, or have other devtools logic that doesn't depend on an action sheet.
It also introduces the RCTDevSettingsDataSource protocol for storing dev tools preferences. This could allow a developer to implement alternative behaviors, e.g. loading the settings from some other config, changing settings based on the user, deciding not to persist some settings, or something else.
The included data source implementation, RCTDevSettingsUserDefaultsDataSource, uses NSUserDefaults and is backwards compatible with the older implementation, so **no workflows or dependent code will break, and old saved settings will persist.**
The RCTDevMenu interface has not changed and is therefore also backwards-compatible, though
some methods are now deprecated.
In order to ensure that RCTDevSettings
Closes https://github.com/facebook/react-native/pull/11613
Reviewed By: mmmulani
Differential Revision: D4571773
Pulled By: javache
fbshipit-source-id: 25555d0a6eaa81f694343e079ed02439e5845fbc
2017-02-24 14:50:29 +00:00
|
|
|
|
2017-04-20 15:20:03 +00:00
|
|
|
#if RCT_DEV
|
|
|
|
|
Add RCTDevSettings module
Summary:
This decouples non-UI logic from RCTDevMenu into a new module RCTDevSettings.
**Motivation**: This allows developers to change dev settings without depending on the built-in dev menu, e.g. if they want to introduce their own UI, or have other devtools logic that doesn't depend on an action sheet.
It also introduces the RCTDevSettingsDataSource protocol for storing dev tools preferences. This could allow a developer to implement alternative behaviors, e.g. loading the settings from some other config, changing settings based on the user, deciding not to persist some settings, or something else.
The included data source implementation, RCTDevSettingsUserDefaultsDataSource, uses NSUserDefaults and is backwards compatible with the older implementation, so **no workflows or dependent code will break, and old saved settings will persist.**
The RCTDevMenu interface has not changed and is therefore also backwards-compatible, though
some methods are now deprecated.
In order to ensure that RCTDevSettings
Closes https://github.com/facebook/react-native/pull/11613
Reviewed By: mmmulani
Differential Revision: D4571773
Pulled By: javache
fbshipit-source-id: 25555d0a6eaa81f694343e079ed02439e5845fbc
2017-02-24 14:50:29 +00:00
|
|
|
@interface RCTDevSettingsUserDefaultsDataSource : NSObject <RCTDevSettingsDataSource>
|
|
|
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
@implementation RCTDevSettingsUserDefaultsDataSource {
|
|
|
|
NSMutableDictionary *_settings;
|
|
|
|
NSUserDefaults *_userDefaults;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (instancetype)init
|
|
|
|
{
|
|
|
|
return [self initWithDefaultValues:nil];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (instancetype)initWithDefaultValues:(NSDictionary *)defaultValues
|
|
|
|
{
|
|
|
|
if (self = [super init]) {
|
|
|
|
_userDefaults = [NSUserDefaults standardUserDefaults];
|
|
|
|
if (defaultValues) {
|
|
|
|
[self _reloadWithDefaults:defaultValues];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)updateSettingWithValue:(id)value forKey:(NSString *)key
|
|
|
|
{
|
|
|
|
RCTAssert((key != nil), @"%@", [NSString stringWithFormat:@"%@: Tried to update nil key", [self class]]);
|
|
|
|
|
|
|
|
id currentValue = [self settingForKey:key];
|
|
|
|
if (currentValue == value || [currentValue isEqual:value]) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (value) {
|
|
|
|
_settings[key] = value;
|
|
|
|
} else {
|
|
|
|
[_settings removeObjectForKey:key];
|
|
|
|
}
|
|
|
|
[_userDefaults setObject:_settings forKey:kRCTDevSettingsUserDefaultsKey];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (id)settingForKey:(NSString *)key
|
|
|
|
{
|
|
|
|
return _settings[key];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)_reloadWithDefaults:(NSDictionary *)defaultValues
|
|
|
|
{
|
|
|
|
NSDictionary *existingSettings = [_userDefaults objectForKey:kRCTDevSettingsUserDefaultsKey];
|
|
|
|
_settings = existingSettings ? [existingSettings mutableCopy] : [NSMutableDictionary dictionary];
|
|
|
|
for (NSString *key in [defaultValues keyEnumerator]) {
|
|
|
|
if (!_settings[key]) {
|
|
|
|
_settings[key] = defaultValues[key];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
[_userDefaults setObject:_settings forKey:kRCTDevSettingsUserDefaultsKey];
|
|
|
|
}
|
|
|
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
@interface RCTDevSettings () <RCTBridgeModule, RCTInvalidating>
|
|
|
|
{
|
|
|
|
NSURLSessionDataTask *_liveReloadUpdateTask;
|
|
|
|
NSURL *_liveReloadURL;
|
|
|
|
BOOL _isJSLoaded;
|
2017-04-20 15:20:03 +00:00
|
|
|
|
|
|
|
#if ENABLE_PACKAGER_CONNECTION
|
|
|
|
RCTPackagerConnection *_packagerConnection;
|
|
|
|
#endif
|
Add RCTDevSettings module
Summary:
This decouples non-UI logic from RCTDevMenu into a new module RCTDevSettings.
**Motivation**: This allows developers to change dev settings without depending on the built-in dev menu, e.g. if they want to introduce their own UI, or have other devtools logic that doesn't depend on an action sheet.
It also introduces the RCTDevSettingsDataSource protocol for storing dev tools preferences. This could allow a developer to implement alternative behaviors, e.g. loading the settings from some other config, changing settings based on the user, deciding not to persist some settings, or something else.
The included data source implementation, RCTDevSettingsUserDefaultsDataSource, uses NSUserDefaults and is backwards compatible with the older implementation, so **no workflows or dependent code will break, and old saved settings will persist.**
The RCTDevMenu interface has not changed and is therefore also backwards-compatible, though
some methods are now deprecated.
In order to ensure that RCTDevSettings
Closes https://github.com/facebook/react-native/pull/11613
Reviewed By: mmmulani
Differential Revision: D4571773
Pulled By: javache
fbshipit-source-id: 25555d0a6eaa81f694343e079ed02439e5845fbc
2017-02-24 14:50:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
@property (nonatomic, strong) Class executorClass;
|
|
|
|
@property (nonatomic, readwrite, strong) id<RCTDevSettingsDataSource> dataSource;
|
|
|
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
@implementation RCTDevSettings
|
|
|
|
|
|
|
|
@synthesize bridge = _bridge;
|
|
|
|
|
|
|
|
RCT_EXPORT_MODULE()
|
|
|
|
|
|
|
|
- (instancetype)init
|
|
|
|
{
|
|
|
|
// default behavior is to use NSUserDefaults
|
|
|
|
NSDictionary *defaultValues = @{
|
|
|
|
kRCTDevSettingShakeToShowDevMenu: @YES,
|
|
|
|
};
|
|
|
|
RCTDevSettingsUserDefaultsDataSource *dataSource = [[RCTDevSettingsUserDefaultsDataSource alloc] initWithDefaultValues:defaultValues];
|
|
|
|
return [self initWithDataSource:dataSource];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (instancetype)initWithDataSource:(id<RCTDevSettingsDataSource>)dataSource
|
|
|
|
{
|
|
|
|
if (self = [super init]) {
|
|
|
|
_dataSource = dataSource;
|
2017-05-05 15:32:15 +00:00
|
|
|
|
Add RCTDevSettings module
Summary:
This decouples non-UI logic from RCTDevMenu into a new module RCTDevSettings.
**Motivation**: This allows developers to change dev settings without depending on the built-in dev menu, e.g. if they want to introduce their own UI, or have other devtools logic that doesn't depend on an action sheet.
It also introduces the RCTDevSettingsDataSource protocol for storing dev tools preferences. This could allow a developer to implement alternative behaviors, e.g. loading the settings from some other config, changing settings based on the user, deciding not to persist some settings, or something else.
The included data source implementation, RCTDevSettingsUserDefaultsDataSource, uses NSUserDefaults and is backwards compatible with the older implementation, so **no workflows or dependent code will break, and old saved settings will persist.**
The RCTDevMenu interface has not changed and is therefore also backwards-compatible, though
some methods are now deprecated.
In order to ensure that RCTDevSettings
Closes https://github.com/facebook/react-native/pull/11613
Reviewed By: mmmulani
Differential Revision: D4571773
Pulled By: javache
fbshipit-source-id: 25555d0a6eaa81f694343e079ed02439e5845fbc
2017-02-24 14:50:29 +00:00
|
|
|
[[NSNotificationCenter defaultCenter] addObserver:self
|
|
|
|
selector:@selector(jsLoaded:)
|
|
|
|
name:RCTJavaScriptDidLoadNotification
|
|
|
|
object:nil];
|
|
|
|
|
|
|
|
// Delay setup until after Bridge init
|
|
|
|
dispatch_async(dispatch_get_main_queue(), ^{
|
|
|
|
[self _synchronizeAllSettings];
|
|
|
|
});
|
|
|
|
}
|
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
2017-05-15 17:16:39 +00:00
|
|
|
- (void)setBridge:(RCTBridge *)bridge
|
|
|
|
{
|
|
|
|
RCTAssert(_bridge == nil, @"RCTDevSettings module should not be reused");
|
|
|
|
_bridge = bridge;
|
|
|
|
[self _configurePackagerConnection];
|
2017-06-08 14:34:45 +00:00
|
|
|
|
|
|
|
#if RCT_DEV
|
|
|
|
// we need this dispatch back to the main thread because even though this
|
|
|
|
// is executed on the main thread, at this point the bridge is not yet
|
|
|
|
// finished with its initialisation. But it does finish by the time it
|
|
|
|
// relinquishes control of the main thread, so only queue on the JS thread
|
|
|
|
// after the current main thread operation is done.
|
|
|
|
dispatch_async(dispatch_get_main_queue(), ^{
|
|
|
|
[bridge dispatchBlock:^{
|
|
|
|
[RCTInspectorDevServerHelper connectForContext:bridge.jsContextRef
|
|
|
|
withBundleURL:bridge.bundleURL];
|
|
|
|
} queue:RCTJSThread];
|
|
|
|
});
|
|
|
|
#endif
|
2017-05-15 17:16:39 +00:00
|
|
|
}
|
|
|
|
|
Add RCTDevSettings module
Summary:
This decouples non-UI logic from RCTDevMenu into a new module RCTDevSettings.
**Motivation**: This allows developers to change dev settings without depending on the built-in dev menu, e.g. if they want to introduce their own UI, or have other devtools logic that doesn't depend on an action sheet.
It also introduces the RCTDevSettingsDataSource protocol for storing dev tools preferences. This could allow a developer to implement alternative behaviors, e.g. loading the settings from some other config, changing settings based on the user, deciding not to persist some settings, or something else.
The included data source implementation, RCTDevSettingsUserDefaultsDataSource, uses NSUserDefaults and is backwards compatible with the older implementation, so **no workflows or dependent code will break, and old saved settings will persist.**
The RCTDevMenu interface has not changed and is therefore also backwards-compatible, though
some methods are now deprecated.
In order to ensure that RCTDevSettings
Closes https://github.com/facebook/react-native/pull/11613
Reviewed By: mmmulani
Differential Revision: D4571773
Pulled By: javache
fbshipit-source-id: 25555d0a6eaa81f694343e079ed02439e5845fbc
2017-02-24 14:50:29 +00:00
|
|
|
- (dispatch_queue_t)methodQueue
|
|
|
|
{
|
|
|
|
return dispatch_get_main_queue();
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)invalidate
|
|
|
|
{
|
|
|
|
[_liveReloadUpdateTask cancel];
|
|
|
|
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)_updateSettingWithValue:(id)value forKey:(NSString *)key
|
|
|
|
{
|
|
|
|
[_dataSource updateSettingWithValue:value forKey:key];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (id)settingForKey:(NSString *)key
|
|
|
|
{
|
|
|
|
return [_dataSource settingForKey:key];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (BOOL)isRemoteDebuggingAvailable
|
|
|
|
{
|
|
|
|
Class jsDebuggingExecutorClass = objc_lookUpClass("RCTWebSocketExecutor");
|
|
|
|
return (jsDebuggingExecutorClass != nil);
|
|
|
|
}
|
|
|
|
|
|
|
|
- (BOOL)isHotLoadingAvailable
|
|
|
|
{
|
|
|
|
return _bridge.bundleURL && !_bridge.bundleURL.fileURL; // Only works when running from server
|
|
|
|
}
|
|
|
|
|
|
|
|
- (BOOL)isLiveReloadAvailable
|
|
|
|
{
|
|
|
|
return (_liveReloadURL != nil);
|
|
|
|
}
|
|
|
|
|
|
|
|
- (BOOL)isJSCSamplingProfilerAvailable
|
|
|
|
{
|
2017-04-07 18:11:04 +00:00
|
|
|
return JSC_JSSamplingProfilerEnabled(_bridge.jsContextRef);
|
Add RCTDevSettings module
Summary:
This decouples non-UI logic from RCTDevMenu into a new module RCTDevSettings.
**Motivation**: This allows developers to change dev settings without depending on the built-in dev menu, e.g. if they want to introduce their own UI, or have other devtools logic that doesn't depend on an action sheet.
It also introduces the RCTDevSettingsDataSource protocol for storing dev tools preferences. This could allow a developer to implement alternative behaviors, e.g. loading the settings from some other config, changing settings based on the user, deciding not to persist some settings, or something else.
The included data source implementation, RCTDevSettingsUserDefaultsDataSource, uses NSUserDefaults and is backwards compatible with the older implementation, so **no workflows or dependent code will break, and old saved settings will persist.**
The RCTDevMenu interface has not changed and is therefore also backwards-compatible, though
some methods are now deprecated.
In order to ensure that RCTDevSettings
Closes https://github.com/facebook/react-native/pull/11613
Reviewed By: mmmulani
Differential Revision: D4571773
Pulled By: javache
fbshipit-source-id: 25555d0a6eaa81f694343e079ed02439e5845fbc
2017-02-24 14:50:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
RCT_EXPORT_METHOD(reload)
|
|
|
|
{
|
|
|
|
[_bridge reload];
|
|
|
|
}
|
|
|
|
|
2017-04-21 09:54:09 +00:00
|
|
|
RCT_EXPORT_METHOD(setIsShakeToShowDevMenuEnabled:(BOOL)enabled)
|
Add RCTDevSettings module
Summary:
This decouples non-UI logic from RCTDevMenu into a new module RCTDevSettings.
**Motivation**: This allows developers to change dev settings without depending on the built-in dev menu, e.g. if they want to introduce their own UI, or have other devtools logic that doesn't depend on an action sheet.
It also introduces the RCTDevSettingsDataSource protocol for storing dev tools preferences. This could allow a developer to implement alternative behaviors, e.g. loading the settings from some other config, changing settings based on the user, deciding not to persist some settings, or something else.
The included data source implementation, RCTDevSettingsUserDefaultsDataSource, uses NSUserDefaults and is backwards compatible with the older implementation, so **no workflows or dependent code will break, and old saved settings will persist.**
The RCTDevMenu interface has not changed and is therefore also backwards-compatible, though
some methods are now deprecated.
In order to ensure that RCTDevSettings
Closes https://github.com/facebook/react-native/pull/11613
Reviewed By: mmmulani
Differential Revision: D4571773
Pulled By: javache
fbshipit-source-id: 25555d0a6eaa81f694343e079ed02439e5845fbc
2017-02-24 14:50:29 +00:00
|
|
|
{
|
2017-04-21 09:54:09 +00:00
|
|
|
[self _updateSettingWithValue:@(enabled) forKey:kRCTDevSettingShakeToShowDevMenu];
|
Add RCTDevSettings module
Summary:
This decouples non-UI logic from RCTDevMenu into a new module RCTDevSettings.
**Motivation**: This allows developers to change dev settings without depending on the built-in dev menu, e.g. if they want to introduce their own UI, or have other devtools logic that doesn't depend on an action sheet.
It also introduces the RCTDevSettingsDataSource protocol for storing dev tools preferences. This could allow a developer to implement alternative behaviors, e.g. loading the settings from some other config, changing settings based on the user, deciding not to persist some settings, or something else.
The included data source implementation, RCTDevSettingsUserDefaultsDataSource, uses NSUserDefaults and is backwards compatible with the older implementation, so **no workflows or dependent code will break, and old saved settings will persist.**
The RCTDevMenu interface has not changed and is therefore also backwards-compatible, though
some methods are now deprecated.
In order to ensure that RCTDevSettings
Closes https://github.com/facebook/react-native/pull/11613
Reviewed By: mmmulani
Differential Revision: D4571773
Pulled By: javache
fbshipit-source-id: 25555d0a6eaa81f694343e079ed02439e5845fbc
2017-02-24 14:50:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (BOOL)isShakeToShowDevMenuEnabled
|
|
|
|
{
|
|
|
|
return [[self settingForKey:kRCTDevSettingShakeToShowDevMenu] boolValue];
|
|
|
|
}
|
|
|
|
|
|
|
|
RCT_EXPORT_METHOD(setIsDebuggingRemotely:(BOOL)enabled)
|
|
|
|
{
|
|
|
|
[self _updateSettingWithValue:@(enabled) forKey:kRCTDevSettingIsDebuggingRemotely];
|
|
|
|
[self _remoteDebugSettingDidChange];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (BOOL)isDebuggingRemotely
|
|
|
|
{
|
|
|
|
return [[self settingForKey:kRCTDevSettingIsDebuggingRemotely] boolValue];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)_remoteDebugSettingDidChange
|
|
|
|
{
|
|
|
|
// This value is passed as a command-line argument, so fall back to reading from NSUserDefaults directly
|
|
|
|
NSString *executorOverride = [[NSUserDefaults standardUserDefaults] stringForKey:kRCTDevSettingExecutorOverrideClass];
|
2017-03-05 00:42:55 +00:00
|
|
|
Class executorOverrideClass = executorOverride ? NSClassFromString(executorOverride) : nil;
|
|
|
|
if (executorOverrideClass) {
|
|
|
|
self.executorClass = executorOverrideClass;
|
Add RCTDevSettings module
Summary:
This decouples non-UI logic from RCTDevMenu into a new module RCTDevSettings.
**Motivation**: This allows developers to change dev settings without depending on the built-in dev menu, e.g. if they want to introduce their own UI, or have other devtools logic that doesn't depend on an action sheet.
It also introduces the RCTDevSettingsDataSource protocol for storing dev tools preferences. This could allow a developer to implement alternative behaviors, e.g. loading the settings from some other config, changing settings based on the user, deciding not to persist some settings, or something else.
The included data source implementation, RCTDevSettingsUserDefaultsDataSource, uses NSUserDefaults and is backwards compatible with the older implementation, so **no workflows or dependent code will break, and old saved settings will persist.**
The RCTDevMenu interface has not changed and is therefore also backwards-compatible, though
some methods are now deprecated.
In order to ensure that RCTDevSettings
Closes https://github.com/facebook/react-native/pull/11613
Reviewed By: mmmulani
Differential Revision: D4571773
Pulled By: javache
fbshipit-source-id: 25555d0a6eaa81f694343e079ed02439e5845fbc
2017-02-24 14:50:29 +00:00
|
|
|
} else {
|
|
|
|
BOOL enabled = self.isRemoteDebuggingAvailable && self.isDebuggingRemotely;
|
|
|
|
self.executorClass = enabled ? objc_getClass("RCTWebSocketExecutor") : nil;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
RCT_EXPORT_METHOD(setProfilingEnabled:(BOOL)enabled)
|
|
|
|
{
|
|
|
|
[self _updateSettingWithValue:@(enabled) forKey:kRCTDevSettingProfilingEnabled];
|
|
|
|
[self _profilingSettingDidChange];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (BOOL)isProfilingEnabled
|
|
|
|
{
|
|
|
|
return [[self settingForKey:kRCTDevSettingProfilingEnabled] boolValue];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)_profilingSettingDidChange
|
|
|
|
{
|
|
|
|
BOOL enabled = self.isProfilingEnabled;
|
|
|
|
if (_liveReloadURL && enabled != RCTProfileIsProfiling()) {
|
|
|
|
if (enabled) {
|
|
|
|
[_bridge startProfiling];
|
|
|
|
} else {
|
|
|
|
[_bridge stopProfiling:^(NSData *logData) {
|
|
|
|
RCTProfileSendResult(self->_bridge, @"systrace", logData);
|
|
|
|
}];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
RCT_EXPORT_METHOD(setLiveReloadEnabled:(BOOL)enabled)
|
|
|
|
{
|
|
|
|
[self _updateSettingWithValue:@(enabled) forKey:kRCTDevSettingLiveReloadEnabled];
|
|
|
|
[self _liveReloadSettingDidChange];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (BOOL)isLiveReloadEnabled
|
|
|
|
{
|
|
|
|
return [[self settingForKey:kRCTDevSettingLiveReloadEnabled] boolValue];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)_liveReloadSettingDidChange
|
|
|
|
{
|
|
|
|
BOOL liveReloadEnabled = (self.isLiveReloadAvailable && self.isLiveReloadEnabled);
|
|
|
|
if (liveReloadEnabled) {
|
|
|
|
[self _pollForLiveReload];
|
|
|
|
} else {
|
|
|
|
[_liveReloadUpdateTask cancel];
|
|
|
|
_liveReloadUpdateTask = nil;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
RCT_EXPORT_METHOD(setHotLoadingEnabled:(BOOL)enabled)
|
|
|
|
{
|
|
|
|
[self _updateSettingWithValue:@(enabled) forKey:kRCTDevSettingHotLoadingEnabled];
|
|
|
|
[self _hotLoadingSettingDidChange];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (BOOL)isHotLoadingEnabled
|
|
|
|
{
|
|
|
|
return [[self settingForKey:kRCTDevSettingHotLoadingEnabled] boolValue];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)_hotLoadingSettingDidChange
|
|
|
|
{
|
|
|
|
BOOL hotLoadingEnabled = self.isHotLoadingAvailable && self.isHotLoadingEnabled;
|
|
|
|
if (RCTGetURLQueryParam(_bridge.bundleURL, @"hot").boolValue != hotLoadingEnabled) {
|
|
|
|
_bridge.bundleURL = RCTURLByReplacingQueryParam(_bridge.bundleURL, @"hot",
|
|
|
|
hotLoadingEnabled ? @"true" : nil);
|
|
|
|
[_bridge reload];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
RCT_EXPORT_METHOD(toggleElementInspector)
|
|
|
|
{
|
|
|
|
BOOL value = [[self settingForKey:kRCTDevSettingIsInspectorShown] boolValue];
|
|
|
|
[self _updateSettingWithValue:@(!value) forKey:kRCTDevSettingIsInspectorShown];
|
|
|
|
|
|
|
|
if (_isJSLoaded) {
|
|
|
|
#pragma clang diagnostic push
|
|
|
|
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
|
|
|
[self.bridge.eventDispatcher sendDeviceEventWithName:@"toggleElementInspector" body:nil];
|
|
|
|
#pragma clang diagnostic pop
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)toggleJSCSamplingProfiler
|
|
|
|
{
|
|
|
|
JSContext *context = _bridge.jsContext;
|
|
|
|
JSGlobalContextRef globalContext = context.JSGlobalContextRef;
|
|
|
|
// JSPokeSamplingProfiler() toggles the profiling process
|
|
|
|
JSValueRef jsResult = JSC_JSPokeSamplingProfiler(globalContext);
|
|
|
|
|
|
|
|
if (JSC_JSValueGetType(globalContext, jsResult) != kJSTypeNull) {
|
|
|
|
NSString *results = [[JSC_JSValue(globalContext) valueWithJSValueRef:jsResult inContext:context] toObject];
|
2017-04-18 20:15:25 +00:00
|
|
|
RCTJSCSamplingProfiler *profilerModule = [_bridge moduleForClass:[RCTJSCSamplingProfiler class]];
|
Add RCTDevSettings module
Summary:
This decouples non-UI logic from RCTDevMenu into a new module RCTDevSettings.
**Motivation**: This allows developers to change dev settings without depending on the built-in dev menu, e.g. if they want to introduce their own UI, or have other devtools logic that doesn't depend on an action sheet.
It also introduces the RCTDevSettingsDataSource protocol for storing dev tools preferences. This could allow a developer to implement alternative behaviors, e.g. loading the settings from some other config, changing settings based on the user, deciding not to persist some settings, or something else.
The included data source implementation, RCTDevSettingsUserDefaultsDataSource, uses NSUserDefaults and is backwards compatible with the older implementation, so **no workflows or dependent code will break, and old saved settings will persist.**
The RCTDevMenu interface has not changed and is therefore also backwards-compatible, though
some methods are now deprecated.
In order to ensure that RCTDevSettings
Closes https://github.com/facebook/react-native/pull/11613
Reviewed By: mmmulani
Differential Revision: D4571773
Pulled By: javache
fbshipit-source-id: 25555d0a6eaa81f694343e079ed02439e5845fbc
2017-02-24 14:50:29 +00:00
|
|
|
[profilerModule operationCompletedWithResults:results];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
- (BOOL)isElementInspectorShown
|
|
|
|
{
|
|
|
|
return [[self settingForKey:kRCTDevSettingIsInspectorShown] boolValue];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)setIsPerfMonitorShown:(BOOL)isPerfMonitorShown
|
|
|
|
{
|
|
|
|
[self _updateSettingWithValue:@(isPerfMonitorShown) forKey:kRCTDevSettingIsPerfMonitorShown];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (BOOL)isPerfMonitorShown
|
|
|
|
{
|
|
|
|
return [[self settingForKey:kRCTDevSettingIsPerfMonitorShown] boolValue];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)setIsJSCProfilingEnabled:(BOOL)isJSCProfilingEnabled
|
|
|
|
{
|
|
|
|
[self _updateSettingWithValue:@(isJSCProfilingEnabled) forKey:kRCTDevSettingIsJSCProfilingEnabled];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (BOOL)isJSCProfilingEnabled
|
|
|
|
{
|
|
|
|
return [[self settingForKey:kRCTDevSettingIsJSCProfilingEnabled] boolValue];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)setStartSamplingProfilerOnLaunch:(BOOL)startSamplingProfilerOnLaunch
|
|
|
|
{
|
|
|
|
[self _updateSettingWithValue:@(startSamplingProfilerOnLaunch) forKey:kRCTDevSettingStartSamplingProfilerOnLaunch];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (BOOL)startSamplingProfilerOnLaunch
|
|
|
|
{
|
|
|
|
return [[self settingForKey:kRCTDevSettingStartSamplingProfilerOnLaunch] boolValue];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)setExecutorClass:(Class)executorClass
|
|
|
|
{
|
|
|
|
_executorClass = executorClass;
|
|
|
|
if (_bridge.executorClass != executorClass) {
|
|
|
|
|
|
|
|
// TODO (6929129): we can remove this special case test once we have better
|
|
|
|
// support for custom executors in the dev menu. But right now this is
|
|
|
|
// needed to prevent overriding a custom executor with the default if a
|
|
|
|
// custom executor has been set directly on the bridge
|
|
|
|
if (executorClass == Nil &&
|
|
|
|
_bridge.executorClass != objc_lookUpClass("RCTWebSocketExecutor")) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
_bridge.executorClass = executorClass;
|
|
|
|
[_bridge reload];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-05-05 15:32:15 +00:00
|
|
|
#if ENABLE_PACKAGER_CONNECTION
|
|
|
|
|
|
|
|
- (void)addHandler:(id<RCTPackagerClientMethod>)handler forPackagerMethod:(NSString *)name
|
|
|
|
{
|
|
|
|
RCTAssert(_packagerConnection, @"Expected packager connection");
|
|
|
|
[_packagerConnection addHandler:handler forMethod:name];
|
|
|
|
}
|
|
|
|
|
|
|
|
#elif RCT_DEV
|
|
|
|
|
|
|
|
- (void)addHandler:(id<RCTPackagerClientMethod>)handler forPackagerMethod:(NSString *)name {}
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
2017-04-20 15:20:03 +00:00
|
|
|
#pragma mark - Internal
|
|
|
|
|
|
|
|
- (void)_configurePackagerConnection
|
|
|
|
{
|
|
|
|
#if ENABLE_PACKAGER_CONNECTION
|
|
|
|
if (_packagerConnection) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-06-15 18:52:05 +00:00
|
|
|
_packagerConnection = [RCTPackagerConnection connectionForBridge:_bridge];
|
2017-04-20 15:20:03 +00:00
|
|
|
#endif
|
|
|
|
}
|
Add RCTDevSettings module
Summary:
This decouples non-UI logic from RCTDevMenu into a new module RCTDevSettings.
**Motivation**: This allows developers to change dev settings without depending on the built-in dev menu, e.g. if they want to introduce their own UI, or have other devtools logic that doesn't depend on an action sheet.
It also introduces the RCTDevSettingsDataSource protocol for storing dev tools preferences. This could allow a developer to implement alternative behaviors, e.g. loading the settings from some other config, changing settings based on the user, deciding not to persist some settings, or something else.
The included data source implementation, RCTDevSettingsUserDefaultsDataSource, uses NSUserDefaults and is backwards compatible with the older implementation, so **no workflows or dependent code will break, and old saved settings will persist.**
The RCTDevMenu interface has not changed and is therefore also backwards-compatible, though
some methods are now deprecated.
In order to ensure that RCTDevSettings
Closes https://github.com/facebook/react-native/pull/11613
Reviewed By: mmmulani
Differential Revision: D4571773
Pulled By: javache
fbshipit-source-id: 25555d0a6eaa81f694343e079ed02439e5845fbc
2017-02-24 14:50:29 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Query the data source for all possible settings and make sure we're doing the right
|
|
|
|
* thing for the state of each setting.
|
|
|
|
*/
|
|
|
|
- (void)_synchronizeAllSettings
|
|
|
|
{
|
|
|
|
[self _hotLoadingSettingDidChange];
|
|
|
|
[self _liveReloadSettingDidChange];
|
|
|
|
[self _remoteDebugSettingDidChange];
|
|
|
|
[self _profilingSettingDidChange];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)_pollForLiveReload
|
|
|
|
{
|
|
|
|
if (!_isJSLoaded || ![[self settingForKey:kRCTDevSettingLiveReloadEnabled] boolValue] || !_liveReloadURL) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (_liveReloadUpdateTask) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
__weak RCTDevSettings *weakSelf = self;
|
|
|
|
_liveReloadUpdateTask = [[NSURLSession sharedSession] dataTaskWithURL:_liveReloadURL completionHandler:
|
|
|
|
^(__unused NSData *data, NSURLResponse *response, NSError *error) {
|
|
|
|
|
|
|
|
dispatch_async(dispatch_get_main_queue(), ^{
|
|
|
|
__strong RCTDevSettings *strongSelf = weakSelf;
|
|
|
|
if (strongSelf && [[strongSelf settingForKey:kRCTDevSettingLiveReloadEnabled] boolValue]) {
|
|
|
|
NSHTTPURLResponse *HTTPResponse = (NSHTTPURLResponse *)response;
|
|
|
|
if (!error && HTTPResponse.statusCode == 205) {
|
|
|
|
[strongSelf reload];
|
|
|
|
} else {
|
|
|
|
if (error.code != NSURLErrorCancelled) {
|
|
|
|
strongSelf->_liveReloadUpdateTask = nil;
|
|
|
|
[strongSelf _pollForLiveReload];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
}];
|
|
|
|
|
|
|
|
[_liveReloadUpdateTask resume];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)jsLoaded:(NSNotification *)notification
|
|
|
|
{
|
|
|
|
if (notification.userInfo[@"bridge"] != _bridge) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
_isJSLoaded = YES;
|
|
|
|
|
|
|
|
// Check if live reloading is available
|
|
|
|
NSURL *scriptURL = _bridge.bundleURL;
|
|
|
|
if (![scriptURL isFileURL]) {
|
|
|
|
// Live reloading is disabled when running from bundled JS file
|
|
|
|
_liveReloadURL = [[NSURL alloc] initWithString:@"/onchange" relativeToURL:scriptURL];
|
|
|
|
} else {
|
|
|
|
_liveReloadURL = nil;
|
|
|
|
}
|
|
|
|
|
|
|
|
dispatch_async(dispatch_get_main_queue(), ^{
|
|
|
|
// update state again after the bridge has finished loading
|
|
|
|
[self _synchronizeAllSettings];
|
2017-03-20 19:40:16 +00:00
|
|
|
|
|
|
|
// Inspector can only be shown after JS has loaded
|
|
|
|
if ([self isElementInspectorShown]) {
|
|
|
|
#pragma clang diagnostic push
|
|
|
|
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
|
|
|
[self.bridge.eventDispatcher sendDeviceEventWithName:@"toggleElementInspector" body:nil];
|
|
|
|
#pragma clang diagnostic pop
|
|
|
|
}
|
Add RCTDevSettings module
Summary:
This decouples non-UI logic from RCTDevMenu into a new module RCTDevSettings.
**Motivation**: This allows developers to change dev settings without depending on the built-in dev menu, e.g. if they want to introduce their own UI, or have other devtools logic that doesn't depend on an action sheet.
It also introduces the RCTDevSettingsDataSource protocol for storing dev tools preferences. This could allow a developer to implement alternative behaviors, e.g. loading the settings from some other config, changing settings based on the user, deciding not to persist some settings, or something else.
The included data source implementation, RCTDevSettingsUserDefaultsDataSource, uses NSUserDefaults and is backwards compatible with the older implementation, so **no workflows or dependent code will break, and old saved settings will persist.**
The RCTDevMenu interface has not changed and is therefore also backwards-compatible, though
some methods are now deprecated.
In order to ensure that RCTDevSettings
Closes https://github.com/facebook/react-native/pull/11613
Reviewed By: mmmulani
Differential Revision: D4571773
Pulled By: javache
fbshipit-source-id: 25555d0a6eaa81f694343e079ed02439e5845fbc
2017-02-24 14:50:29 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
#else // #if RCT_DEV
|
|
|
|
|
|
|
|
@implementation RCTDevSettings
|
|
|
|
|
|
|
|
- (instancetype)initWithDataSource:(id<RCTDevSettingsDataSource>)dataSource { return [super init]; }
|
|
|
|
- (BOOL)isHotLoadingAvailable { return NO; }
|
|
|
|
- (BOOL)isLiveReloadAvailable { return NO; }
|
|
|
|
- (BOOL)isRemoteDebuggingAvailable { return NO; }
|
|
|
|
- (id)settingForKey:(NSString *)key { return nil; }
|
|
|
|
- (void)reload {}
|
|
|
|
- (void)toggleElementInspector {}
|
|
|
|
- (void)toggleJSCSamplingProfiler {}
|
|
|
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
@implementation RCTBridge (RCTDevSettings)
|
|
|
|
|
|
|
|
- (RCTDevSettings *)devSettings
|
|
|
|
{
|
|
|
|
#if RCT_DEV
|
|
|
|
return [self moduleForClass:[RCTDevSettings class]];
|
|
|
|
#else
|
|
|
|
return nil;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
@end
|