Skip to content

Commit

Permalink
feat: add visionos support
Browse files Browse the repository at this point in the history
  • Loading branch information
okwasniewski committed Oct 6, 2023
1 parent 5be6f49 commit 8c46acf
Show file tree
Hide file tree
Showing 51 changed files with 1,090 additions and 512 deletions.
26 changes: 26 additions & 0 deletions packages/react-native/Libraries/AppDelegate/RCTAppDelegate.mm
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#import <react/renderer/runtimescheduler/RuntimeScheduler.h>
#import "RCTAppSetupUtils.h"
#import "RCTLegacyInteropComponents.h"
#import <React/RCTUtils.h>

#if RCT_NEW_ARCH_ENABLED
#import <React/CoreModulesPlugins.h>
Expand Down Expand Up @@ -49,6 +50,21 @@ @interface RCTAppDelegate () <

#endif


#if TARGET_OS_VISION
@interface GlassViewController : UIViewController

@end

@implementation GlassViewController

- (UIContainerBackgroundStyle)preferredContainerBackgroundStyle {
return UIContainerBackgroundStyleGlass;
}

@end
#endif

@interface RCTAppDelegate () <RCTCxxBridgeDelegate> {
std::shared_ptr<facebook::react::RuntimeScheduler> _runtimeScheduler;
}
Expand Down Expand Up @@ -121,7 +137,13 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(
NSDictionary *initProps = [self prepareInitialProps];
rootView = [self createRootViewWithBridge:self.bridge moduleName:self.moduleName initProps:initProps];
}

#if TARGET_OS_VISION
self.window = [[UIWindow alloc] initWithFrame:RCTForegroundWindow().bounds];
#else
self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
#endif

UIViewController *rootViewController = [self createRootViewController];
[self setRootView:rootView toRootViewController:rootViewController];
self.window.rootViewController = rootViewController;
Expand Down Expand Up @@ -173,7 +195,11 @@ - (UIView *)createRootViewWithBridge:(RCTBridge *)bridge

- (UIViewController *)createRootViewController
{
#if TARGET_OS_VISION
return [GlassViewController new];
#else
return [UIViewController new];
#endif
}

- (void)setRootView:(UIView *)rootView toRootViewController:(UIViewController *)rootViewController
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

#import <CoreGraphics/CoreGraphics.h>
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>

#import <React/RCTDefines.h>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ extern NSString *const RCTRemoteNotificationReceived;

typedef void (^RCTRemoteNotificationCallback)(UIBackgroundFetchResult result);

#if !TARGET_OS_UIKITFORMAC
#if !TARGET_OS_UIKITFORMAC && !TARGET_OS_VISION
+ (void)didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings;
+ (void)didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken;
+ (void)didReceiveRemoteNotification:(NSDictionary *)notification;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@

static NSString *const kErrorUnableToRequestPermissions = @"E_UNABLE_TO_REQUEST_PERMISSIONS";

#if !TARGET_OS_UIKITFORMAC
#if !TARGET_OS_UIKITFORMAC && !TARGET_OS_VISION
@implementation RCTConvert (NSCalendarUnit)

RCT_ENUM_CONVERTER(
Expand Down Expand Up @@ -81,13 +81,13 @@ + (UILocalNotification *)UILocalNotification:(id)json

@end
#else
@interface RCTPushNotificationManager () <NativePushNotificationManagerIOSSpec>
@interface RCTPushNotificationManager ()
@end
#endif // TARGET_OS_UIKITFORMAC

@implementation RCTPushNotificationManager

#if !TARGET_OS_UIKITFORMAC
#if !TARGET_OS_UIKITFORMAC && !TARGET_OS_VISION

static NSDictionary *RCTFormatLocalNotification(UILocalNotification *notification)
{
Expand Down Expand Up @@ -140,7 +140,7 @@ - (dispatch_queue_t)methodQueue
return dispatch_get_main_queue();
}

#if !TARGET_OS_UIKITFORMAC
#if !TARGET_OS_UIKITFORMAC && !TARGET_OS_VISION
- (void)startObserving
{
[[NSNotificationCenter defaultCenter] addObserver:self
Expand Down
2 changes: 1 addition & 1 deletion packages/react-native/Libraries/Text/Text/RCTTextView.mm
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,7 @@ - (void)disableContextMenu
- (void)handleLongPress:(UILongPressGestureRecognizer *)gesture
{
// TODO: Adopt showMenuFromRect (necessary for UIKitForMac)
#if !TARGET_OS_UIKITFORMAC
#if !TARGET_OS_UIKITFORMAC && !TARGET_OS_VISION
UIMenuController *menuController = [UIMenuController sharedMenuController];

if (menuController.isMenuVisible) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -642,6 +642,7 @@ - (void)didSetProps:(NSArray<NSString *> *)changedProps

- (void)setCustomInputAccessoryViewWithNativeID:(NSString *)nativeID
{
#if !TARGET_OS_VISION
__weak RCTBaseTextInputView *weakSelf = self;
[_bridge.uiManager rootViewForReactTag:self.reactTag
withCompletion:^(UIView *rootView) {
Expand All @@ -656,10 +657,12 @@ - (void)setCustomInputAccessoryViewWithNativeID:(NSString *)nativeID
}
}
}];
#endif
}

- (void)setDefaultInputAccessoryView
{
#if !TARGET_OS_VISION
UIView<RCTBackedTextInputViewProtocol> *textInputView = self.backedTextInputView;
UIKeyboardType keyboardType = textInputView.keyboardType;

Expand Down Expand Up @@ -691,6 +694,7 @@ - (void)setDefaultInputAccessoryView
textInputView.inputAccessoryView = nil;
}
[self reloadInputViewsIfNecessary];
#endif
}

- (void)reloadInputViewsIfNecessary
Expand Down
2 changes: 1 addition & 1 deletion packages/react-native/React-Core.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ end

folly_compiler_flags = '-DFOLLY_NO_CONFIG -DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1 -DFOLLY_CFG_NO_COROUTINES=1 -Wno-comma -Wno-shorten-64-to-32'
folly_version = '2022.05.16.00'
socket_rocket_version = '0.6.0'
socket_rocket_version = '0.6.0.2'
boost_compiler_flags = '-Wno-documentation'

use_hermes = ENV['USE_HERMES'] == nil || ENV['USE_HERMES'] == '1'
Expand Down
4 changes: 2 additions & 2 deletions packages/react-native/React/Base/RCTConvert.m
Original file line number Diff line number Diff line change
Expand Up @@ -551,8 +551,8 @@ + (UIKeyboardType)UIKeyboardType:(id)json RCT_DYNAMIC
(@{
@"default" : @(UIBarStyleDefault),
@"black" : @(UIBarStyleBlack),
@"blackOpaque" : @(UIBarStyleBlackOpaque),
@"blackTranslucent" : @(UIBarStyleBlackTranslucent),
@"blackOpaque" : @(UIBarStyleBlack),
@"blackTranslucent" : @(UIBarStyleBlack),
}),
UIBarStyleDefault,
integerValue)
Expand Down
5 changes: 4 additions & 1 deletion packages/react-native/React/Base/RCTKeyCommands.m
Original file line number Diff line number Diff line change
Expand Up @@ -127,8 +127,11 @@ - (void)handleKeyUIEventSwizzle:(UIEvent *)event
if ([event respondsToSelector:@selector(_isKeyDown)]) {
isKeyDown = [event _isKeyDown];
}

#if !TARGET_OS_VISION
BOOL interactionEnabled = !RCTSharedApplication().isIgnoringInteractionEvents;
#else
BOOL interactionEnabled = true;
#endif
BOOL hasFirstResponder = NO;
if (isKeyDown && modifiedInput.length > 0 && interactionEnabled) {
UIResponder *firstResponder = nil;
Expand Down
5 changes: 5 additions & 0 deletions packages/react-native/React/Base/RCTUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,11 @@ RCT_EXTERN UIApplication *__nullable RCTSharedApplication(void);
// or view controller
RCT_EXTERN UIWindow *__nullable RCTKeyWindow(void);

#if TARGET_OS_VISION
// Returns the current active UIWindow based on UIWindowScene
RCT_EXTERN UIWindow *__nullable RCTForegroundWindow(void);
#endif

// Returns the presented view controller, useful if you need
// e.g. to present a modal view controller or alert over it
RCT_EXTERN UIViewController *__nullable RCTPresentedViewController(void);
Expand Down
25 changes: 24 additions & 1 deletion packages/react-native/React/Base/RCTUtils.m
Original file line number Diff line number Diff line change
Expand Up @@ -301,18 +301,23 @@ static void RCTUnsafeExecuteOnMainQueueOnceSync(dispatch_once_t *onceToken, disp

void RCTComputeScreenScale(void)
{
#if !TARGET_OS_VISION
dispatch_once(&onceTokenScreenScale, ^{
screenScale = [UIScreen mainScreen].scale;
});
#endif
}

CGFloat RCTScreenScale(void)
{
#if !TARGET_OS_VISION
RCTUnsafeExecuteOnMainQueueOnceSync(&onceTokenScreenScale, ^{
screenScale = [UIScreen mainScreen].scale;
});

return screenScale;
#endif

return 1;
}

CGFloat RCTFontSizeMultiplier(void)
Expand Down Expand Up @@ -347,9 +352,14 @@ CGSize RCTScreenSize(void)

static CGSize size;
static dispatch_once_t onceToken;

dispatch_once(&onceToken, ^{
RCTUnsafeExecuteOnMainQueueSync(^{
#if TARGET_OS_VISION
size = RCTKeyWindow().bounds.size;
#else
size = [UIScreen mainScreen].bounds.size;
#endif
});
});

Expand Down Expand Up @@ -557,6 +567,19 @@ BOOL RCTRunningInAppExtension(void)
return nil;
}

#if TARGET_OS_VISION
UIWindow *__nullable RCTForegroundWindow(void)
{
for (UIScene *scene in RCTSharedApplication().connectedScenes) {
if (scene.activationState == UISceneActivationStateForegroundActive &&
[scene isKindOfClass:[UIWindowScene class]]) {
return [[UIWindow alloc] initWithWindowScene:(UIWindowScene *)scene];
}
}
return nil;
}
#endif

UIViewController *__nullable RCTPresentedViewController(void)
{
if ([RCTUtilsUIOverride hasPresentedViewController]) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ - (UIWindow *)alertWindow
{
if (_alertWindow == nil) {
_alertWindow = [self getUIWindowFromScene];


#if !TARGET_OS_VISION
if (_alertWindow == nil) {
UIWindow *keyWindow = RCTSharedApplication().keyWindow;
if (keyWindow) {
Expand All @@ -31,6 +32,7 @@ - (UIWindow *)alertWindow
NSLog(@"Unable to create alert window: keyWindow is nil");
}
}
#endif

if (_alertWindow) {
_alertWindow.rootViewController = [UIViewController new];
Expand Down
20 changes: 19 additions & 1 deletion packages/react-native/React/CoreModules/RCTDevLoadingView.mm
Original file line number Diff line number Diff line change
Expand Up @@ -114,13 +114,30 @@ - (void)showMessage:(NSString *)message color:(UIColor *)color backgroundColor:(
dispatch_async(dispatch_get_main_queue(), ^{
self->_showDate = [NSDate date];
if (!self->_window && !RCTRunningInTestEnvironment()) {

#if TARGET_OS_VISION
UIWindow *window = RCTKeyWindow();
CGSize screenSize = window.bounds.size;

self->_window =
[[UIWindow alloc] initWithFrame:CGRectMake(0, 0, screenSize.width, window.safeAreaInsets.top + 30)];
self->_label =
[[UILabel alloc] initWithFrame:CGRectMake(0, window.safeAreaInsets.top + 5, screenSize.width, 20)];
#else
CGSize screenSize = [UIScreen mainScreen].bounds.size;

UIWindow *window = RCTSharedApplication().keyWindow;

self->_window =
[[UIWindow alloc] initWithFrame:CGRectMake(0, 0, screenSize.width, window.safeAreaInsets.top + 10)];
self->_label =
[[UILabel alloc] initWithFrame:CGRectMake(0, window.safeAreaInsets.top - 10, screenSize.width, 20)];
#endif


self->_window =
[[UIWindow alloc] initWithFrame:CGRectMake(0, 0, screenSize.width, window.safeAreaInsets.top + 30)];
self->_label =
[[UILabel alloc] initWithFrame:CGRectMake(0, window.safeAreaInsets.top + 5, screenSize.width, 20)];
[self->_window addSubview:self->_label];

self->_window.windowLevel = UIWindowLevelStatusBar + 1;
Expand All @@ -142,6 +159,7 @@ - (void)showMessage:(NSString *)message color:(UIColor *)color backgroundColor:(
});

[self hideBannerAfter:15.0];

}

RCT_EXPORT_METHOD(showMessage
Expand Down
20 changes: 13 additions & 7 deletions packages/react-native/React/CoreModules/RCTDeviceInfo.mm
Original file line number Diff line number Diff line change
Expand Up @@ -51,13 +51,16 @@ - (void)initialize
selector:@selector(didReceiveNewContentSizeMultiplier)
name:RCTAccessibilityManagerDidUpdateMultiplierNotification
object:[_moduleRegistry moduleForName:"AccessibilityManager"]];

#if !TARGET_OS_VISION

_currentInterfaceOrientation = [RCTSharedApplication() statusBarOrientation];

[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(interfaceOrientationDidChange)
name:UIApplicationDidChangeStatusBarOrientationNotification
object:nil];
#endif

_currentInterfaceDimensions = [self _exportedDimensions];

Expand Down Expand Up @@ -85,15 +88,16 @@ - (void)invalidate
static BOOL RCTIsIPhoneNotched()
{
static BOOL isIPhoneNotched = NO;
static dispatch_once_t onceToken;
#if !TARGET_OS_VISION
static dispatch_once_t onceToken;

dispatch_once(&onceToken, ^{
RCTAssertMainQueue();

// 20pt is the top safeArea value in non-notched devices
isIPhoneNotched = RCTSharedApplication().keyWindow.safeAreaInsets.top > 20;
});
dispatch_once(&onceToken, ^{
RCTAssertMainQueue();

// 20pt is the top safeArea value in non-notched devices
isIPhoneNotched = RCTSharedApplication().keyWindow.safeAreaInsets.top > 20;
});
#endif
return isIPhoneNotched;
}

Expand Down Expand Up @@ -176,6 +180,7 @@ - (void)interfaceOrientationDidChange

- (void)_interfaceOrientationDidChange
{
#if !TARGET_OS_VISION
UIApplication *application = RCTSharedApplication();
UIInterfaceOrientation nextOrientation = [application statusBarOrientation];

Expand Down Expand Up @@ -205,6 +210,7 @@ - (void)_interfaceOrientationDidChange
_isFullscreen = isRunningInFullScreen;
#pragma clang diagnostic pop
}
#endif
}

- (void)interfaceFrameDidChange
Expand Down
2 changes: 1 addition & 1 deletion packages/react-native/React/CoreModules/RCTPerfMonitor.mm
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ - (UIPanGestureRecognizer *)gestureRecognizer
- (UIView *)container
{
if (!_container) {
CGSize statusBarSize = RCTSharedApplication().statusBarFrame.size;
CGSize statusBarSize = CGSizeMake(1000, 1000);
CGFloat statusBarHeight = statusBarSize.height;
_container = [[UIView alloc] initWithFrame:CGRectMake(10, statusBarHeight, 180, RCTPerfMonitorBarHeight)];
_container.layer.borderWidth = 2;
Expand Down
7 changes: 6 additions & 1 deletion packages/react-native/React/CoreModules/RCTRedBox.mm
Original file line number Diff line number Diff line change
Expand Up @@ -594,7 +594,12 @@ - (void)showErrorMessage:(NSString *)message
#pragma clang diagnostic pop

if (!self->_window) {
self->_window = [[RCTRedBoxWindow alloc] initWithFrame:[UIScreen mainScreen].bounds
#if TARGET_OS_VISION
CGRect frame = RCTForegroundWindow().bounds;
#else
CGRect frame = [UIScreen mainScreen].bounds;
#endif
self->_window = [[RCTRedBoxWindow alloc] initWithFrame:frame
customButtonTitles:self->_customButtonTitles
customButtonHandlers:self->_customButtonHandlers];
self->_window.actionDelegate = self;
Expand Down
Loading

0 comments on commit 8c46acf

Please sign in to comment.