Repository navigation
Conversation
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
The macOS-enabled Assist widget intent still references an accessory-only widget family that is unavailable on native macOS.
Review effort: Balanced
Findings: 1
Open (1)
What changed in this PR
Adds native AppKit/SwiftUI macOS builds while preserving iOS and Mac Catalyst variants.
Changes:
- Adds cross-platform aliases, lifecycle abstractions, availability declarations, and AppKit imports.
- Enables native macOS widgets, intents, networking, sensors, settings, and web frontend support.
- Excludes unsupported iOS, Watch, CarPlay, NFC, and accessory-widget functionality.
| File | Description |
|---|---|
Tests/App/WebView/Mocks/MockWebViewController.swift |
Adds appearance-state mock support. |
Sources/Shared/Watch/* |
Enables shared watch APIs to compile for non-watch platforms. |
Sources/Shared/Toast/* |
Adds macOS toast availability. |
Sources/Shared/Shared.h |
Selects AppKit or UIKit by platform. |
Sources/Shared/Panels/PanelsUpdater.swift |
Uses cross-platform lifecycle notifications. |
Sources/Shared/Notifications/* |
Adds native macOS notification compatibility. |
Sources/Shared/MaterialDesignIcons+CarPlay.swift |
Guards CarPlay-only code. |
Sources/Shared/Location/* |
Adapts location handling for macOS. |
Sources/Shared/LiveActivity/* |
Adds explicit platform availability. |
Sources/Shared/Extensions/* |
Removes or guards UIKit-only dependencies. |
Sources/Shared/Environment/* |
Adds AppKit, battery, connectivity, haptic, and theme support. |
Sources/Shared/Domain/Domain.swift |
Adds AppKit import support. |
Sources/Shared/DesignSystem/* |
Adds macOS availability to shared UI. |
Sources/Shared/Common/* |
Adds platform colors, images, lifecycle, and application state. |
Sources/Shared/API/* |
Extends models, sensors, updates, and authentication to macOS. |
Sources/MacBridge/* |
Makes bridge implementations platform-conditional. |
Sources/HAWatchComplications/* |
Excludes watch rendering components from macOS. |
Sources/HAWatchCommunicationMessages/Package.swift |
Declares macOS package support. |
Sources/HAUtilities/Package.swift |
Declares macOS package support. |
Sources/HANetworking/Package.swift |
Declares macOS package support. |
Sources/HAModels/Package.swift |
Declares macOS package support. |
Sources/HAIconic/* |
Adds macOS package support and guards UIKit views. |
Sources/HADesignSystem/* |
Adds macOS availability, exports, and platform UI behavior. |
Sources/Extensions/Widgets/* |
Enables native macOS widgets and guards unsupported families. |
Sources/Extensions/AppIntents/* |
Adds macOS availability to intents and entities. |
Sources/CarPlay/* |
Guards CarPlay-only implementation files. |
Sources/App/WhatsNew/* |
Removes direct UIKit dependencies and recognizes native Mac. |
Sources/App/VoiceToolsServer/* |
Uses cross-platform grouped settings forms. |
Sources/App/Utilities/* |
Adds platform abstractions for state, settings, themes, and intents. |
Sources/App/TestFlightCommunication/* |
Removes unnecessary UIKit dependency. |
Sources/App/Templating/* |
Uses platform-compatible colors and imports. |
Sources/App/Settings/* |
Adapts settings UI and platform-specific features for native macOS. |
Sources/App/Servers/ServerSelectionListView.swift |
Adds macOS list-spacing availability. |
Sources/App/Scenes/* |
Guards UIKit scenes and adds platform window support. |
Sources/App/PermissionScreen/* |
Removes unnecessary UIKit dependency. |
Sources/App/Onboarding/* |
Adds macOS availability, naming, and toolbar behavior. |
Sources/App/Notifications/KioskPushCommand.swift |
Adds macOS toast availability. |
Sources/App/MainWindowGroupCommands.swift |
Enables menu commands on native macOS. |
Sources/App/Frontend/WebView/* |
Adds AppKit hosting, platform windows, and native Mac frontend behavior. |
Sources/App/Frontend/TagApprovalBottomSheet.swift |
Removes unnecessary UIKit dependency. |
Sources/App/Frontend/OnscreenPage/* |
Adds macOS entity-identifier availability. |
Sources/App/Frontend/OnscreenEntity/* |
Adds macOS entity-identifier availability. |
Sources/App/Frontend/ExternalMessageBus/* |
Adds macOS symbol availability. |
Sources/App/Frontend/Extensions/* |
Adds platform presentation and notification registration. |
Sources/App/Frontend/EntityDeeplink/* |
Removes unnecessary UIKit dependency. |
Sources/App/FlightGreetings/* |
Uses cross-platform grouped settings forms. |
Sources/App/Container/LaunchSplash/* |
Disables the fake splash on native Mac. |
Sources/App/ClientEvents/* |
Adds platform hosting and native detail navigation. |
Sources/App/Cameras/* |
Adds AppKit image handling and skips iOS audio sessions. |
Sources/App/Assist/* |
Adds macOS API availability. |
Configuration/HomeAssistant.xcconfig |
Raises the macOS deployment target to 13.3. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
The notification prompt no longer comes back once answered, the log files open selected in Finder, buttons in a grouped form are drawn as rows, and the widgets screen uses the same grouped form as the other screens.
On a loaded CI machine the network refresh an intent does first can outlast the second the tests polled for, after which they awaited a perform nobody would answer and the whole run hung until its timeout.
…e drawn on the Mac
Adding macosx to the supported platforms made gym's generic macOS destination resolve the app to the native variant, which the committed Catalyst profiles cannot sign. The lane now names the Catalyst destination. CI builds the app for Catalyst and for native macOS and runs HADesignSystem's package tests on macOS, which cover the AppKit stand-ins.
…own string The notification prompt is remembered once the system has answered it, not before, so an app killed under the system alert asks again. The welcome screen's background is a Mac-only addition. The Preferences string keeps its value for Lokalise and the Mac menu item reads a new Settings key.
…he audio output Quitting now waits for the in-flight background activities, with a cap, so the inactive state reaches the server. The audio output sensor reads CoreAudio's default output device on the Mac instead of vanishing. The app asks for the Bluetooth entitlement it tells the frontend it can use. The empty Format menu no longer appears, so the code that stripped it is gone, along with two dead lint directives and a redundant environment assignment.
…n none is left The View menu's frontend commands resolve against the key window synchronously and are disabled when there is no frontend there. A closed window unregisters its coordinator and web view, and the next request without a window opens one. The Settings and About scenes no longer add their own Window menu entries.
…right window Return presses the action marked preferred, else cancel, never a destructive one. Deep link alerts go through the coordinator so they sit on an open sheet rather than behind it. A sheet's record is dropped as it closes, so what its completion presents gets a window of its own, and the tag approval and camera sheets are sized to their content. Deleting a server from the Settings window resets the sidebar instead of dismissing the pane, and the Servers entry is left out of the Mac's settings search.
… view Find Next, Find Previous and Use Selection for Find reach NSTextFinder and are validated by it, and the bar follows the window's layout. The user activity becomes current again when the window comes back. Reconnects treat a visible window as active. The web view's background is made transparent through a guarded key-value call.
…plication source The system background colours follow the iOS values so cards stand out from the page, components are read in extended sRGB, and bitmaps are rendered at the densest screen's scale. The AppKit and SwiftUI stand-ins each live in their own file. The foreground state is read on the main thread, on-device transcription refuses an input with no sample rate, the gauge widget no longer offers a complication source on the Mac, and the labs info sheet is a NavigationStack.
…they found it The render smoke tests fail when a body lays out to nothing and say they are iOS smoke tests. The badge test drives an injected badge instead of the host app's. The alert tests put the coordinator back, dismiss what they presented and point the web view at a loopback address. The deep link alert tests await the main queue instead of spinning the run loop under the main actor, which is why they never saw their alert on CI. The tautological tests are gone.
One type per file, previews for every view, bodies kept inline, the banner's numbers named, and the share buttons as ShareLinks on every platform instead of a label shared across platform branches. The symbol lint rule names the AppKit initializer that exists.
…ighlighting The stand-by view takes the notification center it listens to, so its test posts to one of its own and checks the network type is read again. A remote notification carrying an unknown command is handed to the command manager and reported as not handled. The reconnect manager's default activity check, the server invitation share sheet and the template highlighter's entity pills get tests of their own.
Shown in a window, the controller loaded the frontend and refreshed its server, and that work was still running when the next suite swapped in its own network gate, which then counted callers it did not expect and waited forever. The controller is logged out before it appears and the updaters are idle for the suite, so nothing outlives the test.
# Conflicts: # Sources/Shared/API/WatchHelpers.swift
Codecov Report❌ Patch coverage is ❌ Your patch check has failed because the patch coverage (83.03%) is below the target coverage (90.00%). You can increase the patch coverage or adjust the target coverage. Additional details and impacted files@@ Coverage Diff @@
## main #5935 +/- ##
==========================================
+ Coverage 54.14% 57.56% +3.42%
==========================================
Files 1244 1257 +13
Lines 82591 82725 +134
==========================================
+ Hits 44720 47624 +2904
+ Misses 37871 35101 -2770
☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
# Conflicts: # Sources/App/Cameras/CameraPlayer/CameraOverlayPresenter.swift
# Conflicts: # Sources/App/Cameras/CameraPlayer/CameraPlayerView.swift
# Conflicts: # Sources/Watch/WatchCommunicatorService.swift
# Conflicts: # Sources/App/BarcodeScanner/Camera/BarcodeScannerCamera.swift # Sources/App/BarcodeScanner/Camera/BarcodeScannerView.swift # Sources/App/Frontend/Extensions/WebViewController+PostOnboarding.swift # Sources/App/Frontend/WebView/MacSidebar/MacNativeSidebarState.swift # Sources/App/Frontend/WebView/MacWebViewTitleBar.swift # Sources/App/Frontend/WebView/WebViewController/WebViewController+Alerts.swift # Sources/App/Frontend/WebView/WebViewController/WebViewController.swift # Sources/App/Onboarding/Steps/Servers/OnboardingServersListView.swift # Sources/App/Onboarding/Steps/Welcome/OnboardingWelcomeView.swift # Sources/App/Utilities/Extensions/SwiftUI+SafeArea.swift # Sources/App/Utilities/SoftwareKeyboardObserver.swift # Sources/HADesignSystem/Sources/Components/AppleLikeBottomSheet.swift # Sources/Shared/API/Webhook/Sensors/InputOutputDeviceSensor.swift # Sources/Shared/Extensions/View+ScreenCaptureProtection.swift
# Conflicts: # Sources/App/Settings/Sensors/List/SensorForegroundOnlyBadge.swift
# Conflicts: # Sources/App/Frontend/WebView/Views/HomeAssistantStandByView.swift
# Conflicts: # Sources/App/Settings/AppIconShortcuts/AppIconShortcutItemsUpdater.swift

AI Policy
Select exactly one option that describes AI usage in this contribution:
Summary
Builds the Mac app natively with AppKit and SwiftUI instead of Mac Catalyst. The same targets keep building for iOS and Catalyst; native macOS is a third variant of them.
UIColor,UIImage, ...) alias AppKit on macOS and iOS-only SwiftUI modifiers get Mac stand-ins, so screens are written once. Windows, menus, sheets, the frontend controller and the settings sidebar are written per platform.fastlane/lanes/macos.rbnow passes the Catalyst destination explicitly, so the Mac lane still archives the Catalyst app now that the targets build for both Mac variants. There is no signing or provisioning for the native app yet.build-macjob that builds the app for Catalyst and for native macOS, and runsHADesignSystem's package tests on macOS, which cover the AppKit stand-ins (renderer orientation and scale, colour components, dynamic colours in both appearances).Changes that also apply to iOS
GroupedList, which is a plainListon iOS.AppAlertcan mark a preferred action, which setsUIAlertController.preferredActionfor the deep link confirmation ("Open").ShareLinks, as the log export already was, instead of a button and aUIActivityViewControllerwrapper of their own.SpeechTranscriberrefuses an audio format with no sample rate or channels instead of trapping inAVAudioConverter.Still to do before a native release
aps-environment, app groups, keychain access groups). An unsigned build has no entitlements, which hides keychain and extension problems.SecItemwrapper that setskSecUseDataProtectionKeychainon macOS behindServerManagerKeychain,ClientCertificate,AppConstantsandKeychainWatchDeviceRegistrationStore, so a Catalyst install's servers are found by the native app.Screenshots
Link to pull request in Documentation repository
Documentation: home-assistant/companion.home-assistant#
Any other notes
Native macOS signing and provisioning are still needed before push notifications and the extensions can be tried at runtime. The Debug builds keep the "Simulator" placeholder device name during onboarding on every platform, as before.