From f21fa4ecb73551bdc4c3d70db9fc13e93b19b3a6 Mon Sep 17 00:00:00 2001 From: Andy Matuschak Date: Tue, 17 Dec 2019 16:50:24 -0800 Subject: [PATCH] Enabling RCTWebSocket on UIKitForMac (macOS Catalyst) (#27469) Summary: In https://github.com/facebook/react-native/issues/25427, radex added initial support for running React Native projects on macOS via Catalyst. However, `RCTWebSocket` was disabled for that target because of some compilation issues. This meant that running projects via a connection to the packager wasn't possible: no live reload, and projects must be run in "Release" mode. It also meant making manual changes to Xcode projects deploying to macOS and scattering a number of conditional checks throughout the codebase. In this change, I've implemented support for `RCTWebSocket` on the macOS target and re-enabled the affected features. Live reload and the inspector now work for macOS targets. Manual modifications of Xcode build settings are no longer necessary for react-native projects running on macOS. ![Screen Shot 2019-12-10 at 8 36 38 AM](https://user-images.githubusercontent.com/2771/70549905-ce7b0800-1b29-11ea-85c6-07bf09811ae2.png) ### Limitations There's no binding which displays the developer menu (since there's no shake event on macOS). We'll probably want to add one, perhaps to the menu bar. I've chosen not to commit the modifications to RNTester which enable macOS support, since that would imply more "official" support for this target than I suspect you all would like to convey. I'm happy to add those chunks if it would be helpful. ## Changelog [iOS] [Added] - Added web socket support for macOS (Catalyst), enabling debug builds and live reload Pull Request resolved: https://github.com/facebook/react-native/pull/27469 Test Plan: * Open RNTester/RNTester.xcodeproj with Xcode 11.2.1, run it like a normal iOS app -- make sure it compiles and runs correctly (no regression) * Select "My Mac" as device target, and run. You may need to configure a valid development team to make signing work. * RNTester should run fine with no additional configuration. Modify a file in RNTester, note that live reload is now working. * Test the developer inspector. To display the developer menu, you'll need to manually show it; here's an example diff which does that: ``` diff --git a/RNTester/js/RNTesterApp.ios.js b/RNTester/js/RNTesterApp.ios.js index 8245a68d12..a447ad3b1b 100644 --- a/RNTester/js/RNTesterApp.ios.js +++ b/RNTester/js/RNTesterApp.ios.js @@ -19,6 +19,8 @@ const React = require('react'); const SnapshotViewIOS = require('./examples/Snapshot/SnapshotViewIOS.ios'); const URIActionMap = require('./utils/URIActionMap'); +import NativeDevMenu from '../../Libraries/NativeModules/specs/NativeDevMenu'; + const { AppRegistry, AsyncStorage, @@ -143,6 +145,7 @@ class RNTesterApp extends React.Component { UNSAFE_componentWillMount() { BackHandler.addEventListener('hardwareBackPress', this._handleBack); + NativeDevMenu.show(); } componentDidMount() { ``` Reviewed By: sammy-SC Differential Revision: D18945861 Pulled By: hramos fbshipit-source-id: edcf02c5803742c89a845a3e5d72bc7dacae839f --- .../RCTPushNotificationManager.mm | 2 +- Libraries/WebSocket/RCTSRWebSocket.m | 17 ++++++----------- React/Base/RCTBridge.m | 2 +- React/Base/RCTDefines.h | 2 +- React/CoreModules/RCTDevMenu.mm | 2 +- React/CoreModules/RCTDevSettings.mm | 2 +- React/DevSupport/RCTInspectorDevServerHelper.h | 2 +- React/DevSupport/RCTInspectorDevServerHelper.mm | 2 +- React/DevSupport/RCTPackagerConnection.h | 2 +- React/DevSupport/RCTPackagerConnection.mm | 2 +- React/Inspector/RCTInspector.mm | 2 +- .../Inspector/RCTInspectorPackagerConnection.h | 2 +- .../Inspector/RCTInspectorPackagerConnection.m | 2 +- 13 files changed, 18 insertions(+), 23 deletions(-) diff --git a/Libraries/PushNotificationIOS/RCTPushNotificationManager.mm b/Libraries/PushNotificationIOS/RCTPushNotificationManager.mm index 09d2c42a40ffbd..c6465bd7189f64 100644 --- a/Libraries/PushNotificationIOS/RCTPushNotificationManager.mm +++ b/Libraries/PushNotificationIOS/RCTPushNotificationManager.mm @@ -26,7 +26,7 @@ static NSString *const kErrorUnableToRequestPermissions = @"E_UNABLE_TO_REQUEST_PERMISSIONS"; -#if !TARGET_OS_TV && !TARGET_OS_UIKITFORMAC +#if !TARGET_OS_TV @implementation RCTConvert (NSCalendarUnit) RCT_ENUM_CONVERTER(NSCalendarUnit, diff --git a/Libraries/WebSocket/RCTSRWebSocket.m b/Libraries/WebSocket/RCTSRWebSocket.m index fc88b283c8bc48..b967c14173d625 100644 --- a/Libraries/WebSocket/RCTSRWebSocket.m +++ b/Libraries/WebSocket/RCTSRWebSocket.m @@ -14,12 +14,9 @@ // limitations under the License. // -#if !TARGET_OS_UIKITFORMAC - #import #import -#import #import @@ -580,7 +577,7 @@ - (void)closeWithCode:(NSInteger)code reason:(NSString *)reason NSMutableData *mutablePayload = [[NSMutableData alloc] initWithLength:sizeof(uint16_t) + maxMsgSize]; NSData *payload = mutablePayload; - ((uint16_t *)mutablePayload.mutableBytes)[0] = EndianU16_BtoN(code); + ((uint16_t *)mutablePayload.mutableBytes)[0] = NSSwapBigShortToHost(code); if (reason) { NSRange remainingRange = {0}; @@ -749,7 +746,7 @@ - (void)handleCloseWithData:(NSData *)data return; } else if (dataSize >= 2) { [data getBytes:&closeCode length:sizeof(closeCode)]; - _closeCode = EndianU16_BtoN(closeCode); + _closeCode = NSSwapBigShortToHost(closeCode); if (!closeCodeIsValid(_closeCode)) { [self _closeWithProtocolError:[NSString stringWithFormat:@"Cannot have close code of %d", _closeCode]]; return; @@ -972,12 +969,12 @@ - (void)_readFrameContinue if (header.payload_length == 126) { assert(mapped_size >= sizeof(uint16_t)); - uint16_t newLen = EndianU16_BtoN(*(uint16_t *)(mapped_buffer)); + uint16_t newLen = NSSwapBigShortToHost(*(uint16_t *)(mapped_buffer)); header.payload_length = newLen; offset += sizeof(uint16_t); } else if (header.payload_length == 127) { assert(mapped_size >= sizeof(uint64_t)); - header.payload_length = EndianU64_BtoN(*(uint64_t *)(mapped_buffer)); + header.payload_length = NSSwapBigLongLongToHost(*(uint64_t *)(mapped_buffer)); offset += sizeof(uint64_t); } else { assert(header.payload_length < 126 && header.payload_length >= 0); @@ -1264,11 +1261,11 @@ - (void)_sendFrameWithOpcode:(RCTSROpCode)opcode data:(NSData *)data frame_buffer[1] |= payloadLength; } else if (payloadLength <= UINT16_MAX) { frame_buffer[1] |= 126; - *((uint16_t *)(frame_buffer + frame_buffer_size)) = EndianU16_BtoN((uint16_t)payloadLength); + *((uint16_t *)(frame_buffer + frame_buffer_size)) = NSSwapBigShortToHost((uint16_t)payloadLength); frame_buffer_size += sizeof(uint16_t); } else { frame_buffer[1] |= 127; - *((uint64_t *)(frame_buffer + frame_buffer_size)) = EndianU64_BtoN((uint64_t)payloadLength); + *((uint64_t *)(frame_buffer + frame_buffer_size)) = NSSwapBigLongLongToHost((uint64_t)payloadLength); frame_buffer_size += sizeof(uint64_t); } @@ -1637,5 +1634,3 @@ - (NSRunLoop *)runLoop } @end - -#endif diff --git a/React/Base/RCTBridge.m b/React/Base/RCTBridge.m index 706b3b10245c07..b47f212a30cf71 100644 --- a/React/Base/RCTBridge.m +++ b/React/Base/RCTBridge.m @@ -305,7 +305,7 @@ - (void)reload */ - (void)reloadWithReason:(NSString *)reason { - #if RCT_ENABLE_INSPECTOR && !TARGET_OS_UIKITFORMAC + #if RCT_ENABLE_INSPECTOR // Disable debugger to resume the JsVM & avoid thread locks while reloading [RCTInspectorDevServerHelper disableDebugger]; #endif diff --git a/React/Base/RCTDefines.h b/React/Base/RCTDefines.h index f9cd58fd32beaf..d1bbf9df01bb70 100644 --- a/React/Base/RCTDefines.h +++ b/React/Base/RCTDefines.h @@ -63,7 +63,7 @@ #endif #ifndef ENABLE_PACKAGER_CONNECTION -#if RCT_DEV && (__has_include("RCTPackagerConnection.h") || __has_include()) && !TARGET_OS_UIKITFORMAC +#if RCT_DEV && (__has_include("RCTPackagerConnection.h") || __has_include()) #define ENABLE_PACKAGER_CONNECTION 1 #else #define ENABLE_PACKAGER_CONNECTION 0 diff --git a/React/CoreModules/RCTDevMenu.mm b/React/CoreModules/RCTDevMenu.mm index 3e1b869f27b7fc..9e857fce32bda1 100644 --- a/React/CoreModules/RCTDevMenu.mm +++ b/React/CoreModules/RCTDevMenu.mm @@ -262,7 +262,7 @@ - (void)setDefaultJSBundle if (devSettings.isNuclideDebuggingAvailable && !devSettings.isDebuggingRemotely) { [items addObject:[RCTDevMenuItem buttonItemWithTitle:@"Debug with Nuclide" handler:^{ -#if RCT_ENABLE_INSPECTOR && !TARGET_OS_UIKITFORMAC +#if RCT_ENABLE_INSPECTOR [RCTInspectorDevServerHelper attachDebugger:@"ReactNative" withBundleURL:bridge.bundleURL diff --git a/React/CoreModules/RCTDevSettings.mm b/React/CoreModules/RCTDevSettings.mm index fd6bbcd8ed2e7e..08615d6131add8 100644 --- a/React/CoreModules/RCTDevSettings.mm +++ b/React/CoreModules/RCTDevSettings.mm @@ -176,7 +176,7 @@ - (void)setBridge:(RCTBridge *)bridge forMethod:@"reload"]; #endif -#if RCT_ENABLE_INSPECTOR && !TARGET_OS_UIKITFORMAC +#if RCT_ENABLE_INSPECTOR // 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 diff --git a/React/DevSupport/RCTInspectorDevServerHelper.h b/React/DevSupport/RCTInspectorDevServerHelper.h index d1fc838eea9e10..0315d6c98089a0 100644 --- a/React/DevSupport/RCTInspectorDevServerHelper.h +++ b/React/DevSupport/RCTInspectorDevServerHelper.h @@ -11,7 +11,7 @@ #import #import -#if RCT_DEV && !TARGET_OS_UIKITFORMAC +#if RCT_DEV @interface RCTInspectorDevServerHelper : NSObject diff --git a/React/DevSupport/RCTInspectorDevServerHelper.mm b/React/DevSupport/RCTInspectorDevServerHelper.mm index 13098d16a59513..b6c2ac621f9000 100644 --- a/React/DevSupport/RCTInspectorDevServerHelper.mm +++ b/React/DevSupport/RCTInspectorDevServerHelper.mm @@ -7,7 +7,7 @@ #import -#if RCT_DEV && !TARGET_OS_UIKITFORMAC +#if RCT_DEV #import #import diff --git a/React/DevSupport/RCTPackagerConnection.h b/React/DevSupport/RCTPackagerConnection.h index 497fb10b783c5a..e774572ec44ed4 100644 --- a/React/DevSupport/RCTPackagerConnection.h +++ b/React/DevSupport/RCTPackagerConnection.h @@ -9,7 +9,7 @@ #import -#if RCT_DEV && !TARGET_OS_UIKITFORMAC +#if RCT_DEV NS_ASSUME_NONNULL_BEGIN diff --git a/React/DevSupport/RCTPackagerConnection.mm b/React/DevSupport/RCTPackagerConnection.mm index 253c2b486d3d5e..7d0966dca63dca 100644 --- a/React/DevSupport/RCTPackagerConnection.mm +++ b/React/DevSupport/RCTPackagerConnection.mm @@ -21,7 +21,7 @@ #import #import -#if RCT_DEV && !TARGET_OS_UIKITFORMAC +#if RCT_DEV #import diff --git a/React/Inspector/RCTInspector.mm b/React/Inspector/RCTInspector.mm index eb3ef7e0f0f116..571f7f94256e9e 100644 --- a/React/Inspector/RCTInspector.mm +++ b/React/Inspector/RCTInspector.mm @@ -7,7 +7,7 @@ #import -#if RCT_DEV && !TARGET_OS_UIKITFORMAC +#if RCT_DEV #include diff --git a/React/Inspector/RCTInspectorPackagerConnection.h b/React/Inspector/RCTInspectorPackagerConnection.h index 6fe57a441d2992..e30858b1c53937 100644 --- a/React/Inspector/RCTInspectorPackagerConnection.h +++ b/React/Inspector/RCTInspectorPackagerConnection.h @@ -8,7 +8,7 @@ #import #import -#if RCT_DEV && !TARGET_OS_UIKITFORMAC +#if RCT_DEV @interface RCTBundleStatus : NSObject @property (atomic, assign) BOOL isLastBundleDownloadSuccess; diff --git a/React/Inspector/RCTInspectorPackagerConnection.m b/React/Inspector/RCTInspectorPackagerConnection.m index 5da2e858f102d0..001e25a13e26b9 100644 --- a/React/Inspector/RCTInspectorPackagerConnection.m +++ b/React/Inspector/RCTInspectorPackagerConnection.m @@ -7,7 +7,7 @@ #import -#if RCT_DEV && !TARGET_OS_UIKITFORMAC +#if RCT_DEV #import #import