7.11 — HomeKit & Matter
Opening scenario
A client makes smart bulbs and wants iOS users to control them from a native app — not the generic Home app, their branded app. They also want to support Matter so the same bulbs work with Google Home and Alexa. You open Xcode, find HomeKit and Matter frameworks, and have to figure out which is for which. The answer: HomeKit (the framework) is your read/write API into the user’s HomeKit database — the user-managed set of accessories. Matter is the cross-vendor protocol over Thread / Wi-Fi that newer accessories speak. Apple’s MatterSupport framework bridges them: a Matter accessory commissioned through your app shows up in HomeKit and in any other Matter ecosystem the user invites.
| Context | What it usually means |
|---|---|
| Reads “HMHomeManager” | Has read/written HomeKit data |
| Reads “HMService / HMCharacteristic” | Knows the device model |
| Reads “Matter / Thread border router” | Understands the cross-ecosystem protocol |
| Reads “MatterSupport extension” | Has commissioned a Matter accessory |
| Reads “HMHomeManagerAuthorizationStatus” | Has shipped a HomeKit-enabled app |
Concept → Why → How → Code
Concept
- HomeKit — Apple’s user-controlled smart-home database. Users add accessories via the Home app (or third-party apps with the HomeKit entitlement); your app, with permission, can read and control them.
- Matter — the cross-vendor IP-based protocol. Built on top of Thread (low-power mesh) or Wi-Fi. Accessories speaking Matter are vendor-agnostic.
- HomePod / Apple TV as border routers — extend Thread mesh.
- MatterSupport.framework — lets your app run commissioning UI (the “scan QR / pair this device” flow) for a Matter accessory, after which the accessory is shared across HomeKit, Google Home, Alexa, SmartThings.
Why
- Native control — your branded experience without web pages or vendor-specific cloud round-trips.
- Cross-platform device sales — Matter means the same hardware works in every ecosystem; the app you ship for setup is your differentiator.
- Local-first — most HomeKit/Matter operations are LAN-local; works without cloud.
How — capability & authorization
- Apple Developer account → request HomeKit entitlement (Apple-approved; not auto-granted).
- Xcode → Signing & Capabilities → + Capability → HomeKit.
Info.plist:NSHomeKitUsageDescription= “We need access to your home to control your bulbs.”
import HomeKit
@MainActor
final class HomeService: NSObject, HMHomeManagerDelegate, ObservableObject {
private let manager = HMHomeManager()
@Published var primaryHome: HMHome?
@Published var bulbs: [HMAccessory] = []
override init() {
super.init()
manager.delegate = self
}
func homeManagerDidUpdateHomes(_ manager: HMHomeManager) {
primaryHome = manager.primaryHome
bulbs = manager.primaryHome?.accessories.filter {
$0.services.contains { $0.serviceType == HMServiceTypeLightbulb }
} ?? []
}
func homeManager(_ manager: HMHomeManager, didUpdateAuthorizationStatus status: HMHomeManagerAuthorizationStatus) {
// .authorized, .restricted, .determined ...
}
}
Reading / writing a characteristic
func togglePower(_ accessory: HMAccessory) async throws {
guard let bulbService = accessory.services.first(where: { $0.serviceType == HMServiceTypeLightbulb }),
let power = bulbService.characteristics.first(where: { $0.characteristicType == HMCharacteristicTypePowerState })
else { return }
let current = (power.value as? Bool) ?? false
try await power.writeValue(!current)
}
func setBrightness(_ accessory: HMAccessory, percent: Int) async throws {
guard let bulbService = accessory.services.first(where: { $0.serviceType == HMServiceTypeLightbulb }),
let brightness = bulbService.characteristics.first(where: { $0.characteristicType == HMCharacteristicTypeBrightness })
else { return }
try await brightness.writeValue(percent)
}
Subscribing to changes
brightness.enableNotification(true) { error in /* handle */ }
// Receive via HMAccessoryDelegate
extension HomeService: HMAccessoryDelegate {
nonisolated func accessory(_ accessory: HMAccessory,
service: HMService,
didUpdateValueFor characteristic: HMCharacteristic) {
// characteristic.value just changed (from physical button, automation, or other app)
}
}
Automations
let trigger = HMEventTrigger(
name: "Sunset porch lights",
events: [HMSignificantTimeEvent(significantEvent: .sunset, offset: nil)],
predicate: nil
)
let action = HMCharacteristicWriteAction(characteristic: bulb.powerCharacteristic, targetValue: NSNumber(value: true))
let actionSet = HMActionSet(name: "Turn on porch")
home.addActionSet(actionSet) { _, error in
actionSet.addAction(action) { _ in
trigger.updateActionSets([actionSet]) { _ in
home.addTrigger(trigger) { _, _ in }
}
}
}
(Yes, the callback-tower is rough. Most teams write an async wrapper.)
Matter commissioning
For Matter accessories, you don’t add them to HomeKit directly. You call MatterSupport to launch the system commissioning sheet, which discovers the accessory (over Bluetooth + Wi-Fi/Thread), gets the user to confirm, and onboards it across all ecosystems the user has enabled.
import MatterSupport
@MainActor
final class Commissioner {
func startSetup() async throws {
let topology = MatterAddDeviceRequest.Topology(ecosystemName: "MyBulbBrand", homes: [])
let request = MatterAddDeviceRequest(topology: topology)
try await request.perform() // Presents the system sheet
}
}
You also ship a Matter Extension target (MatterSupport extension) that handles the cryptographic onboarding payload on Apple’s behalf and reports back the new device’s identifier.
After commissioning, the accessory appears in HomeKit; your app interacts with it via HMAccessory like any other accessory.
Thread
Thread is a low-power mesh networking standard. Battery-powered Matter accessories (door locks, sensors) almost always use Thread, not Wi-Fi. Thread requires a border router: HomePod mini, HomePod 2, Apple TV 4K (3rd gen), or compatible non-Apple hubs.
Your app doesn’t directly drive Thread; you commission via Matter and the OS handles the network selection.
Cloud relays & remote access
When the user is away from home, HomeKit routes commands via iCloud + a home hub (HomePod / Apple TV / iPad). Your app code doesn’t change — the same HMCharacteristic.writeValue works whether local or remote. The user needs at least one home hub set up.
In the wild
- Apple Home app — the canonical HomeKit/Matter UI.
- Eve for HomeKit, Controller for HomeKit, Home+ 6 — third-party HomeKit-only superapps with advanced automation building.
- Aqara Home, Tapo, Nanoleaf — vendor apps using MatterSupport for cross-ecosystem setup.
- Lutron Caseta — original HomeKit accessory ecosystem; powerful bridged automation.
- HomeKit Secure Video (Logitech Circle, Aqara Hub G3) — privacy-preserving camera storage on iCloud.
Common misconceptions
- “Anyone can add the HomeKit entitlement.” Apple manually approves HomeKit entitlement requests; first-time apps are sometimes denied or require a brand justification.
- “Matter replaces HomeKit.” Matter is a network protocol; HomeKit is Apple’s local DB + APIs. Apple’s adoption of Matter means HomeKit also speaks Matter; the user-facing data model is unchanged.
- “I can read accessories without user permission.” No —
HMHomeManagerreturns nothing until the user grants permission via the system prompt that fires onmanager.delegateassignment. - “HomeKit lets me control my neighbor’s lights if I’m on the same Wi-Fi.” No — HomeKit accessories pair cryptographically to a specific HomeKit home. Even on the same LAN, another user can’t control them without an invite.
- “My app needs to keep a TCP connection open to receive changes.” Use
enableNotification(true)on a characteristic; HomeKit pushes updates to your delegate when the value changes.
Seasoned engineer’s take
HomeKit’s API surface looks dated — block-based, NS-prefixed types, no async sugar in many places. But the underlying model is exactly right: the user owns their home, the user grants access per-app, and apps speak through Apple’s privacy-preserving local-first transport. Two practical notes:
- Wrap the legacy API in actors. Build a
HomeServiceactor that exposes async methods. Keep all the block-based callbacks and delegate forwarding inside; the rest of your app never sees them. - Don’t rebuild Home.app. Users have invested in their Home setup. Your branded app’s value is the vertical experience — better visualizations for your specific accessory class, custom automation building for your devices, deeper accessory-state UI. Generic “control my lights” is what Home is for.
For Matter specifically: the hard part is the first-time setup story. If your accessory is Matter-only, MatterSupport gives you a polished system sheet. If it’s BLE + custom cloud (the old way), you’re rolling your own setup UI from scratch and asking users to install your app, sign up, and follow a 12-step wizard. The conversion delta is enormous. Ship Matter for new hardware.
TIP: Test your HomeKit code with the HomeKit Accessory Simulator (available on developer.apple.com). It mocks accessories so you can develop without buying hardware.
WARNING: Never cache the user’s HomeKit topology to a server you control. The Home graph (which devices, where, who has access) is some of the most sensitive smart-home data; App Review will scrutinize any backend that hoards it.
Interview corner
Junior: “How do you turn on a HomeKit bulb from a native iOS app?”
Add HomeKit entitlement +
NSHomeKitUsageDescription. CreateHMHomeManager, set yourself as delegate, wait forhomeManagerDidUpdateHomes. Find the user’s primary home → find the lightbulb accessory → find itsHMServiceTypeLightbulbservice → find itsHMCharacteristicTypePowerStatecharacteristic → callwriteValue(true).
Mid: “How would you commission a brand-new Matter accessory through your branded app?”
Add a MatterSupport extension target that handles the cryptographic onboarding payload. In the main app, when the user taps “Add device,” construct a
MatterAddDeviceRequestwith your ecosystem name and call.perform()— the system presents the standard Matter pairing sheet. Once commissioning completes, the accessory is in HomeKit and your app interacts with it viaHMAccessory. Apple shares the same accessory across other Matter ecosystems the user has connected (Google Home, Alexa).
Senior: “Design a third-party Home automation app that supports HomeKit and Matter, schedules complex automations, and integrates Apple Intelligence for natural-language scene creation.”
Wrap HomeKit in an async-friendly
HomeServiceactor (push the block-based delegate noise into a single bottleneck). Model the accessory tree as your own SwiftData entities mirroringHMAccessory/HMService/HMCharacteristic, refreshed on everyHMHomeManagerDelegatecallback — gives you SwiftUI-friendly observation. Automation builder UI lets users compose triggers (time, location, characteristic-changed) and action sets; persist asHMEventTrigger+HMActionSet. For natural-language (“turn off all upstairs lights at sunset”), expose your accessories asAppEntityand defineAppIntentactions (TurnOffAccessoryIntent, RunSceneIntent, ScheduleEventIntent). Apple Intelligence (iOS 18+) will invoke your intents as tools, parameterized from the user’s prompt. For Matter commissioning, ship a MatterSupport extension. For remote access, rely on the user’s home hub — no custom cloud needed unless you have features beyond HomeKit’s scope (e.g., analytics dashboards). Privacy: store no accessory state on your servers; if you must, encrypt with a per-user key the user controls.
Red flag: “We’re skipping HomeKit and shipping our own Bluetooth-direct app because HomeKit is too complicated.”
That choice forfeits remote access, Siri, automation, watch widgets, the Home app, cross-ecosystem (Matter) compatibility, and the user’s mental model. The pain of HomeKit’s older API is real but tiny next to those tradeoffs. Use HomeKit (or HomeKit + Matter) for any smart-home accessory in 2026.
Lab preview
HomeKit doesn’t have a dedicated lab in Phase 7 (it requires entitlement approval and physical or simulator accessories), but the Lab 7.2 — Widget extension stretch goal mentions exposing a “Turn off all lights” AppIntent — a clean way to surface HomeKit control via the unified intent system without building a full Home app.