Skip to content

Commit 85ab8c2

Browse files
Saadnajmiclaude
andauthored
fix(spm): fix pre-existing macOS porting bugs (#2869)
## Summary Fixes compilation errors that block macOS SPM builds, helping unblock #2815. - **RCTLinkingManager**: combined iOS and macOS implementations into a single file using `#if TARGET_OS_OSX` guards. Added missing `NativeLinkingManagerSpec` conformance (`openSettings`, `sendIntent`, `getTurboModule`), removed unused import, deleted the `macos/` overlay directory, and cleaned up the podspec - **RCTCursor.m**: replaced `Foundation.h` + conditional `AppKit.h` with `RCTUIKit` umbrella header - **RCTViewComponentView.mm**: removed duplicate `cursor` property check introduced during merge ## Test plan - [x] macOS SPM build passes (verified on `feature/spm-macos-support` — zero errors from these files) - [ ] Verify iOS build is not regressed 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
1 parent e7767ac commit 85ab8c2

File tree

5 files changed

+120
-133
lines changed

5 files changed

+120
-133
lines changed

packages/react-native/Libraries/LinkingIOS/RCTLinkingManager.mm

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414

1515
#import "RCTLinkingPlugins.h"
1616

17+
#if !TARGET_OS_OSX // [macOS]
18+
1719
static NSString *const kOpenURLNotification = @"RCTOpenURLNotification";
1820

1921
static void postNotificationWithURL(NSURL *URL, id sender)
@@ -22,6 +24,24 @@ static void postNotificationWithURL(NSURL *URL, id sender)
2224
[[NSNotificationCenter defaultCenter] postNotificationName:kOpenURLNotification object:sender userInfo:payload];
2325
}
2426

27+
#else // [macOS
28+
29+
NSString *const RCTOpenURLNotification = @"RCTOpenURLNotification";
30+
31+
static NSString *initialURL = nil;
32+
static BOOL moduleInitalized = NO;
33+
static BOOL alwaysForegroundLastWindow = YES;
34+
35+
static void postNotificationWithURL(NSString *url, id sender)
36+
{
37+
NSDictionary<NSString *, id> *payload = @{@"url": url};
38+
[[NSNotificationCenter defaultCenter] postNotificationName:RCTOpenURLNotification
39+
object:sender
40+
userInfo:payload];
41+
}
42+
43+
#endif // macOS]
44+
2545
@interface RCTLinkingManager () <NativeLinkingManagerSpec>
2646
@end
2747

@@ -34,6 +54,8 @@ - (dispatch_queue_t)methodQueue
3454
return dispatch_get_main_queue();
3555
}
3656

57+
#if !TARGET_OS_OSX // [macOS]
58+
3759
- (void)startObserving
3860
{
3961
[[NSNotificationCenter defaultCenter] addObserver:self
@@ -47,11 +69,33 @@ - (void)stopObserving
4769
[[NSNotificationCenter defaultCenter] removeObserver:self];
4870
}
4971

72+
#else // [macOS
73+
74+
- (void)startObserving
75+
{
76+
moduleInitalized = YES;
77+
78+
[[NSNotificationCenter defaultCenter] addObserver:self
79+
selector:@selector(handleOpenURLNotification:)
80+
name:RCTOpenURLNotification
81+
object:nil];
82+
}
83+
84+
- (void)stopObserving
85+
{
86+
moduleInitalized = NO;
87+
[[NSNotificationCenter defaultCenter] removeObserver:self];
88+
}
89+
90+
#endif // macOS]
91+
5092
- (NSArray<NSString *> *)supportedEvents
5193
{
5294
return @[ @"url" ];
5395
}
5496

97+
#if !TARGET_OS_OSX // [macOS]
98+
5599
+ (BOOL)application:(UIApplication *)app
56100
openURL:(NSURL *)URL
57101
options:(NSDictionary<UIApplicationOpenURLOptionsKey, id> *)options
@@ -87,6 +131,43 @@ - (void)handleOpenURLNotification:(NSNotification *)notification
87131
[self sendEventWithName:@"url" body:notification.userInfo];
88132
}
89133

134+
#else // [macOS
135+
136+
+ (void)setAlwaysForegroundLastWindow:(BOOL)alwaysForeground
137+
{
138+
alwaysForegroundLastWindow = alwaysForeground;
139+
}
140+
141+
+ (void)getUrlEventHandler:(NSAppleEventDescriptor *)event withReplyEvent:(NSAppleEventDescriptor *)replyEvent
142+
{
143+
// extract url value from the event
144+
NSString *url = [[event paramDescriptorForKeyword:keyDirectObject] stringValue];
145+
146+
// If the application was launched via URL, this handler will be called before
147+
// the module is initialized by the bridge. Store the initial URL, because we are not listening to the notification yet.
148+
if (!moduleInitalized && initialURL == nil) {
149+
initialURL = url;
150+
}
151+
152+
postNotificationWithURL(url, self);
153+
}
154+
155+
- (void)handleOpenURLNotification:(NSNotification *)notification
156+
{
157+
// Activate app, because [NSApp mainWindow] returns nil when the app is hidden and another app is maximized
158+
[NSApp activateIgnoringOtherApps:YES];
159+
// foreground top level window
160+
if (alwaysForegroundLastWindow) {
161+
NSWindow *lastWindow = [[NSApp windows] lastObject];
162+
[lastWindow makeKeyAndOrderFront:nil];
163+
}
164+
[self sendEventWithName:@"url" body:notification.userInfo];
165+
}
166+
167+
#endif // macOS]
168+
169+
#if !TARGET_OS_OSX // [macOS]
170+
90171
RCT_EXPORT_METHOD(openURL
91172
: (NSURL *)URL resolve
92173
: (RCTPromiseResolveBlock)resolve reject
@@ -184,6 +265,44 @@ - (void)handleOpenURLNotification:(NSNotification *)notification
184265
}];
185266
}
186267

268+
#else // [macOS
269+
270+
RCT_EXPORT_METHOD(openURL:(NSURL *)URL
271+
resolve:(RCTPromiseResolveBlock)resolve
272+
reject:(RCTPromiseRejectBlock)reject)
273+
{
274+
BOOL result = [[NSWorkspace sharedWorkspace] openURL:URL];
275+
if (result) {
276+
resolve(@YES);
277+
} else {
278+
reject(RCTErrorUnspecified, [NSString stringWithFormat:@"Unable to open URL: %@", URL], nil);
279+
}
280+
}
281+
282+
RCT_EXPORT_METHOD(canOpenURL:(NSURL *)URL
283+
resolve:(RCTPromiseResolveBlock)resolve
284+
reject:(__unused RCTPromiseRejectBlock)reject)
285+
{
286+
resolve(@YES);
287+
}
288+
289+
RCT_EXPORT_METHOD(getInitialURL:(RCTPromiseResolveBlock)resolve
290+
reject:(__unused RCTPromiseRejectBlock)reject)
291+
{
292+
resolve(RCTNullIfNil(initialURL));
293+
}
294+
295+
RCT_EXPORT_METHOD(openSettings:(RCTPromiseResolveBlock)resolve
296+
reject:(__unused RCTPromiseRejectBlock)reject)
297+
{
298+
// macOS doesn't have a direct equivalent of UIApplicationOpenSettingsURLString
299+
// Open System Preferences instead
300+
[[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:@"x-apple.systempreferences:"]];
301+
resolve(nil);
302+
}
303+
304+
#endif // macOS]
305+
187306
RCT_EXPORT_METHOD(sendIntent
188307
: (NSString *)action extras
189308
: (NSArray *_Nullable)extras resolve

packages/react-native/Libraries/LinkingIOS/React-RCTLinking.podspec

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,6 @@ Pod::Spec.new do |s|
3232
s.compiler_flags = '-Wno-nullability-completeness'
3333
s.source = source
3434
s.source_files = podspec_sources("*.{m,mm}", "")
35-
# [macOS
36-
s.osx.exclude_files = "RCTLinkingManager.mm"
37-
s.osx.source_files = "macos/RCTLinkingManager.mm"
38-
# macOS]
3935
s.preserve_paths = "package.json", "LICENSE", "LICENSE-docs"
4036
s.header_dir = "RCTLinking"
4137
s.pod_target_xcconfig = {

packages/react-native/Libraries/LinkingIOS/macos/RCTLinkingManager.mm

Lines changed: 0 additions & 123 deletions
This file was deleted.

packages/react-native/React/Fabric/Mounting/ComponentViews/View/RCTViewComponentView.mm

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -341,11 +341,6 @@ - (void)updateProps:(const Props::Shared &)props oldProps:(const Props::Shared &
341341
needsInvalidateLayer = YES;
342342
}
343343

344-
// `cursor`
345-
if (oldViewProps.cursor != newViewProps.cursor) {
346-
needsInvalidateLayer = YES;
347-
}
348-
349344
// `shouldRasterize`
350345
if (oldViewProps.shouldRasterize != newViewProps.shouldRasterize) {
351346
self.layer.shouldRasterize = newViewProps.shouldRasterize;

packages/react-native/React/Views/RCTCursor.m

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

88
// [macOS]
99

10-
#import <Foundation/Foundation.h>
10+
#import <React/RCTUIKit.h>
1111
#import "RCTCursor.h"
1212

1313
#if defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && __MAC_OS_X_VERSION_MAX_ALLOWED >= 150000 /* __MAC_15_0 */

0 commit comments

Comments
 (0)