Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/*
* 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>

void RCTInitializeUIKitProxies(void);
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/*
* 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 "RCTInitializeUIKitProxies.h"
#import "RCTTraitCollectionProxy.h"
#import "RCTWindowSafeAreaProxy.h"

void RCTInitializeUIKitProxies(void)
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
[[RCTWindowSafeAreaProxy sharedInstance] startObservingSafeArea];
[[RCTTraitCollectionProxy sharedInstance] startObservingTraitCollection];
});
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/*
* 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 <UIKit/UIKit.h>

NS_ASSUME_NONNULL_BEGIN

@interface RCTTraitCollectionProxy : NSObject

+ (instancetype)sharedInstance;

/*
* Property to access the current trait collection.
* Thread safe.
*/
@property (nonatomic, readonly) UITraitCollection *currentTraitCollection;

- (void)startObservingTraitCollection;

@end

NS_ASSUME_NONNULL_END
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
/*
* 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 "RCTTraitCollectionProxy.h"
#import <React/RCTUtils.h>
#import <mutex>

#import <React/RCTConstants.h>

@implementation RCTTraitCollectionProxy {
BOOL _isObserving;
std::mutex _mutex;
UITraitCollection *_currentTraitCollection;
}

+ (instancetype)sharedInstance
{
static RCTTraitCollectionProxy *sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [RCTTraitCollectionProxy new];
});
return sharedInstance;
}

- (instancetype)init
{
self = [super init];
if (self) {
_isObserving = NO;
_currentTraitCollection = [RCTKeyWindow().traitCollection copy];
}
return self;
}

- (void)startObservingTraitCollection
{
RCTAssertMainQueue();
std::lock_guard<std::mutex> lock(_mutex);
if (!_isObserving) {
_isObserving = YES;
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(_appearanceDidChange:)
name:RCTUserInterfaceStyleDidChangeNotification
object:nil];
}
}

- (UITraitCollection *)currentTraitCollection
{
{
std::lock_guard<std::mutex> lock(_mutex);
if (_isObserving) {
return _currentTraitCollection;
}
}

// Fallback in case [RCTTraitCollectionProxy startObservingTraitCollection] was not called.
__block UITraitCollection *traitCollection = nil;
RCTUnsafeExecuteOnMainQueueSync(^{
traitCollection = [RCTKeyWindow().traitCollection copy];
});
return traitCollection;
}

- (void)_appearanceDidChange:(NSNotification *)notification
{
std::lock_guard<std::mutex> lock(_mutex);

NSDictionary *userInfo = [notification userInfo];
if (userInfo) {
_currentTraitCollection = userInfo[RCTUserInterfaceStyleDidChangeNotificationTraitCollectionKey];
}
}

@end
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/*
* 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 <UIKit/UIKit.h>

NS_ASSUME_NONNULL_BEGIN

@interface RCTWindowSafeAreaProxy : NSObject

+ (instancetype)sharedInstance;

/*
* Property to access the current safe area insets of the window, read-only.
* Thread safe.
*/
@property (nonatomic, readonly) UIEdgeInsets currentSafeAreaInsets;

- (void)startObservingSafeArea;

@end

NS_ASSUME_NONNULL_END
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/*
* 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 "RCTWindowSafeAreaProxy.h"
#import <React/RCTAssert.h>
#import <React/RCTUtils.h>
#import <mutex>

#import <React/RCTConstants.h>

@implementation RCTWindowSafeAreaProxy {
BOOL _isObserving;
std::mutex _currentSafeAreaInsetsMutex;
UIEdgeInsets _currentSafeAreaInsets;
}

+ (instancetype)sharedInstance
{
static RCTWindowSafeAreaProxy *sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [RCTWindowSafeAreaProxy new];
});
return sharedInstance;
}

- (instancetype)init
{
self = [super init];
if (self) {
_isObserving = NO;
_currentSafeAreaInsets = [UIApplication sharedApplication].delegate.window.safeAreaInsets;
}
return self;
}

- (void)startObservingSafeArea
{
RCTAssertMainQueue();
std::lock_guard<std::mutex> lock(_currentSafeAreaInsetsMutex);
if (!_isObserving) {
_isObserving = YES;
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(_interfaceFrameDidChange)
name:RCTUserInterfaceStyleDidChangeNotification
object:nil];
}
}

- (UIEdgeInsets)currentSafeAreaInsets
{
std::lock_guard<std::mutex> lock(_currentSafeAreaInsetsMutex);

if (!_isObserving) {
// Fallback in case [startObservingSafeArea startObservingSafeArea] was not called.
__block UIEdgeInsets insets;
RCTUnsafeExecuteOnMainQueueSync(^{
insets = [UIApplication sharedApplication].delegate.window.safeAreaInsets;
});
return insets;
}

return _currentSafeAreaInsets;
}

- (void)_interfaceFrameDidChange
{
std::lock_guard<std::mutex> lock(_currentSafeAreaInsetsMutex);
_currentSafeAreaInsets = [UIApplication sharedApplication].delegate.window.safeAreaInsets;
}

@end
11 changes: 4 additions & 7 deletions packages/react-native/React/CoreModules/RCTAppearance.mm
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
#import <FBReactNativeSpec/FBReactNativeSpec.h>
#import <React/RCTConstants.h>
#import <React/RCTEventEmitter.h>
#import <React/RCTUtils.h>
#import <React/RCTTraitCollectionProxy.h>

#import "CoreModulesPlugins.h"

Expand Down Expand Up @@ -90,7 +90,7 @@ @implementation RCTAppearance {
- (instancetype)init
{
if ((self = [super init])) {
UITraitCollection *traitCollection = RCTKeyWindow().traitCollection;
UITraitCollection *traitCollection = [RCTTraitCollectionProxy sharedInstance].currentTraitCollection;
_currentColorScheme = RCTColorSchemePreference(traitCollection);
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(appearanceChanged:)
Expand All @@ -104,7 +104,7 @@ - (instancetype)init

+ (BOOL)requiresMainQueueSetup
{
return YES;
return NO;
}

- (dispatch_queue_t)methodQueue
Expand Down Expand Up @@ -133,10 +133,7 @@ - (dispatch_queue_t)methodQueue
RCT_EXPORT_SYNCHRONOUS_TYPED_METHOD(NSString *, getColorScheme)
{
if (!sIsAppearancePreferenceSet) {
__block UITraitCollection *traitCollection = nil;
RCTUnsafeExecuteOnMainQueueSync(^{
traitCollection = RCTKeyWindow().traitCollection;
});
UITraitCollection *traitCollection = [RCTTraitCollectionProxy sharedInstance].currentTraitCollection;
_currentColorScheme = RCTColorSchemePreference(traitCollection);
}
return _currentColorScheme;
Expand Down
40 changes: 19 additions & 21 deletions packages/react-native/React/CoreModules/RCTPlatform.mm
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#import <UIKit/UIKit.h>

#import <FBReactNativeSpec/FBReactNativeSpec.h>
#import <React/RCTTraitCollectionProxy.h>
#import <React/RCTUtils.h>
#import <React/RCTVersion.h>

Expand Down Expand Up @@ -48,7 +49,7 @@ @implementation RCTPlatform

+ (BOOL)requiresMainQueueSetup
{
return YES;
return NO;
}

- (dispatch_queue_t)methodQueue
Expand All @@ -64,30 +65,27 @@ - (dispatch_queue_t)methodQueue

- (ModuleConstants<JS::NativePlatformConstantsIOS::Constants>)getConstants
{
__block ModuleConstants<JS::NativePlatformConstantsIOS::Constants> constants;
RCTUnsafeExecuteOnMainQueueSync(^{
UIDevice *device = [UIDevice currentDevice];
auto versions = RCTGetReactNativeVersion();
constants = typedConstants<JS::NativePlatformConstantsIOS::Constants>({
.forceTouchAvailable = RCTForceTouchAvailable() ? true : false,
.osVersion = [device systemVersion],
.systemName = [device systemName],
.interfaceIdiom = interfaceIdiom([device userInterfaceIdiom]),
.isTesting = RCTRunningInTestEnvironment() ? true : false,
.reactNativeVersion = JS::NativePlatformConstantsIOS::ConstantsReactNativeVersion::Builder(
{.minor = [versions[@"minor"] doubleValue],
.major = [versions[@"major"] doubleValue],
.patch = [versions[@"patch"] doubleValue],
.prerelease = [versions[@"prerelease"] isKindOfClass:[NSNull class]] ? nullptr : versions[@"prerelease"]}),
UIDevice *device = [UIDevice currentDevice];
bool isForceTouchAvailable = [RCTTraitCollectionProxy sharedInstance].currentTraitCollection.forceTouchCapability ==
UIForceTouchCapabilityAvailable;
auto versions = RCTGetReactNativeVersion();
return typedConstants<JS::NativePlatformConstantsIOS::Constants>({
.forceTouchAvailable = isForceTouchAvailable,
.osVersion = [device systemVersion],
.systemName = [device systemName],
.interfaceIdiom = interfaceIdiom([device userInterfaceIdiom]),
.isTesting = RCTRunningInTestEnvironment() ? true : false,
.reactNativeVersion = JS::NativePlatformConstantsIOS::ConstantsReactNativeVersion::Builder(
{.minor = [versions[@"minor"] doubleValue],
.major = [versions[@"major"] doubleValue],
.patch = [versions[@"patch"] doubleValue],
.prerelease = [versions[@"prerelease"] isKindOfClass:[NSNull class]] ? nullptr : versions[@"prerelease"]}),
#if TARGET_OS_MACCATALYST
.isMacCatalyst = true,
.isMacCatalyst = true,
#else
.isMacCatalyst = false,
.isMacCatalyst = false,
#endif
});
});

return constants;
}

- (std::shared_ptr<TurboModule>)getTurboModule:(const ObjCTurboModule::InitParams &)params
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#import <React/RCTBridgeModule.h>
#import <React/RCTConvert.h>
#import <React/RCTFabricSurface.h>
#import <React/RCTInitializeUIKitProxies.h>
#import <React/RCTInspectorDevServerHelper.h>
#import <React/RCTInspectorNetworkHelper.h>
#import <React/RCTInspectorUtils.h>
Expand Down Expand Up @@ -248,6 +249,8 @@ - (RCTFabricSurface *)createSurfaceWithModuleName:(NSString *)moduleName
mode:(DisplayMode)displayMode
initialProperties:(NSDictionary *)properties
{
RCTInitializeUIKitProxies();

RCTFabricSurface *surface = [[RCTFabricSurface alloc] initWithSurfacePresenter:self.surfacePresenter
moduleName:moduleName
initialProperties:properties];
Expand Down
Loading