feat(macos): migrate init template from Objective-C to Swift#2948
Draft
Saadnajmi wants to merge 5 commits intomicrosoft:mainfrom
Draft
feat(macos): migrate init template from Objective-C to Swift#2948Saadnajmi wants to merge 5 commits intomicrosoft:mainfrom
Saadnajmi wants to merge 5 commits intomicrosoft:mainfrom
Conversation
Replace the Objective-C/Storyboard-based macOS init template with a modern Swift implementation that aligns with the upstream React Native community template (https://github.com/react-native-community/template). Changes: - Replace AppDelegate.h/AppDelegate.mm with AppDelegate.swift using the new RCTReactNativeFactory pattern (matching upstream iOS template) - Replace main.m with main.swift for the app entry point - Remove Main.storyboard (684 lines of XML) in favor of a programmatic menu bar built in Swift - Update project.pbxproj to reference Swift source files - Remove NSMainStoryboardFile from Info.plist The new template uses: - RCTReactNativeFactory + ReactNativeDelegate (non-deprecated API) - NSObject + NSApplicationDelegate (instead of deprecated RCTAppDelegate) - Programmatic NSWindow creation (1280x720 default) - Programmatic menu bar: App, Edit, View, Window, Help menus - Same bundleURL/sourceURL pattern as upstream community template
Replace imperative NSMenu/NSMenuItem creation with a small @resultBuilder DSL that reads almost like SwiftUI: NSApp.mainMenu = NSMenu { NSMenuItem { NSMenu("Edit") { NSMenuItem("Undo", action: Selector(("undo:")), key: "z") NSMenuItem.separator() NSMenuItem("Cut", action: #selector(NSText.cut(_:)), key: "x") } } } The builder infrastructure is ~30 lines: - MenuBuilder: collects NSMenuItem instances into an array - SubMenuBuilder: wraps a single NSMenu as a submenu - NSMenu convenience init with builder closure - NSMenuItem convenience inits and .keyModifiers() chainable helper
AppKit doesn't provide default menus programmatically (that was the
storyboard's job), but keyboard shortcuts like ⌘C, ⌘V, ⌘Q, ⌘W only
work when a corresponding NSMenuItem exists. So we need the menus, but
they don't belong inline in AppDelegate.
Move all standard menu construction into a single factory method:
NSApp.mainMenu = .standardMenu(appName: "HelloWorld")
This keeps AppDelegate focused on React Native setup while the menu
boilerplate lives in a self-contained NSMenu extension that's easy to
customize or replace.
Replace the AppKit-based AppDelegate template with a SwiftUI App that hosts the React Native root view via NSViewRepresentable. - Use @main on a SwiftUI App struct; remove main.swift - Use Window scene with .defaultSize(1280x720) instead of manual NSWindow - Wrap factory.rootViewFactory.view(withModuleName:) in NSViewRepresentable - Drop the ~130 line NSMenu.standardMenu extension; SwiftUI provides the standard App, Edit, View, Window, and Help menus by default - Initialize RCTReactNativeFactory in AppDelegate.init() instead of applicationDidFinishLaunching, so it's ready when the scene body evaluates Reduces the template AppDelegate from 181 to 59 lines.
mischreiber
approved these changes
Apr 27, 2026
mischreiber
left a comment
There was a problem hiding this comment.
Approved assuming you take the suggestion in that one comment on AppDelegate.swift
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Replaces the Objective-C/Storyboard-based macOS init template with a modern SwiftUI implementation. The app delegate hosts the React Native root view inside a SwiftUI
Windowscene viaNSViewRepresentable, so the template gets standard macOS menus, window management, and lifecycle handling for free from SwiftUI.Net diff vs main: ~219 insertions, ~770 deletions — most of the reduction comes from removing the 684-line
Main.storyboardXML and the ~130-line programmaticNSMenubuilder.Why SwiftUI?
When replacing the Storyboard, both pure AppKit and SwiftUI were on the table:
NSMenuItemboilerplate) and manually creating anNSWindow.WindowGroup/Window, plus declarative window sizing via.defaultSize(...).Because React Native's view is an
NSView, embedding it in SwiftUI is a one-liner withNSViewRepresentable— no awkward bridging.Changes
Files removed
AppDelegate.h/AppDelegate.mm— replaced byAppDelegate.swiftmain.m— replaced by@mainon the SwiftUIAppstruct (nomain.swiftneeded)Base.lproj/Main.storyboard(684 lines of XML) — replaced by SwiftUIFiles added
AppDelegate.swift(59 lines) — contains:@main struct HelloWorldApp: Appwith aWindowscene,.defaultSize(width: 1280, height: 720)AppDelegate: NSObject, NSApplicationDelegatewired via@NSApplicationDelegateAdaptor, initializingRCTReactNativeFactoryininit()ReactNativeDelegate: RCTDefaultReactNativeFactoryDelegateforbundleURL()/sourceURL(for:)ReactNativeView: NSViewRepresentablewrappingfactory.rootViewFactory.view(withModuleName:)Files modified
Info.plist— removedNSMainStoryboardFilekeyproject.pbxproj— updated file references from ObjC/storyboard to Swift; removedmain.swiftreferences in favor of@mainArchitecture alignment with upstream
UIApplicationDelegateApp+NSApplicationDelegateadaptorUIResponder, UIApplicationDelegateNSObject, NSApplicationDelegate✅RCTReactNativeFactory+ReactNativeDelegateRCTAppDelegate(deprecated)RCTAppDependencyProvider()bundleURL()/sourceURL(for:)@main)@main) ✅UIWindow(frame:)WindowsceneRCTRootViewdirectlyNSViewRepresentable→RCTRootView@main@main✅Menu bar
SwiftUI provides the standard macOS menu bar automatically with no code:
Using
Window(instead ofWindowGroup) intentionally omits the "New Window" command, which is appropriate for a single-window React Native app.Testing
pod installsucceedsAppDelegate.swiftcompiles cleanlyRCT_NEW_ARCH_ENABLED=1)NewAppScreen) renders inside the SwiftUIWindowWhy this is better than pure AppKit
AppDelegate.swiftvs the AppKit versionNSMenuboilerplate — SwiftUI provides standard menus automaticallyNSWindowsetup —Windowscene handles size, title bar, lifecyclemain.swiftneeded —@maingenerates the entry point.defaultSize(width:height:)