homekit

homekit

热门

使用 HomeKit 和 MatterSupport 控制智能家居配件并完成 Matter 设备配网。适用于管理家庭/房间/配件、创建动作集与触发器、读取配件特征值、接入 Matter 设备,或开发第三方智能家居生态 App。

967Star
49Fork
更新于 2026/7/31
SKILL.md
只读
名称
homekit
描述

使用 HomeKit 和 MatterSupport 控制智能家居配件并完成 Matter 设备配网。适用于管理家庭/房间/配件、创建动作集与触发器、读取配件特征值、接入 Matter 设备,或开发第三方智能家居生态 App。

HomeKit

使用 HomeKit 控制自动化家居配件,并配合 MatterSupport 完成 Matter 设备配网。HomeKit 负责管理“家庭-房间-配件”模型、动作集(Action Set)和触发器(Trigger);MatterSupport 则专门处理将 Matter 设备配网接入你的生态系统。

目录

环境配置

HomeKit 配置

  1. 在 Xcode 的 Signing & Capabilities 中启用 HomeKit 能力。
  2. 在 Info.plist 中添加 NSHomeKitUsageDescription 权限说明:
<key>NSHomeKitUsageDescription</key>
<string>此应用需要控制你的智能家居配件。</string>

MatterSupport 配置

如果要将 Matter 设备配网接入你自己的 App 生态:

  1. 添加一个 MatterSupport Extension Target,并将它的主类(Principal Class)设置为 MatterAddDeviceExtensionRequestHandler 的子类。
  2. NSBonjourServices 中添加 _matter._tcp_matterc._udp 以及 _matterd._udp 广播服务项。
  3. 仅当调用方需要通过代码主动传入 Matter 配网 Payload 时,才添加 com.apple.developer.matter.allow-setup-payload 权限说明。

Framework 职责边界

需求 使用的 Framework
家庭、房间、配件、特征值、动作、触发器 HomeKit
将 Matter 设备配网接入 App 自有生态 MatterSupport
选择并授权附近的蓝牙或 Wi-Fi 配件 AccessorySetupKit
完成选择后进行蓝牙 GATT 数据交互 CoreBluetooth
完成选择后加入或配置配件的 Wi-Fi 网络 NetworkExtension

HomeKit 数据模型

HomeKit 采用层级化结构组织家居自动化:

HMHomeManager
  -> HMHome (一个或多个家庭)
       -> HMRoom (家庭中的各个房间)
            -> HMAccessory (房间内的具体设备)
                 -> HMService (具体功能:如灯光、恒温器等)
                      -> HMCharacteristic (可读写的具体数值/状态)
       -> HMZone (房间分组/区域)
       -> HMActionSet (批量组合动作)
       -> HMTrigger (基于时间或事件的触发器)

初始化 Home Manager

在应用中只需创建一个单例或唯一的 HMHomeManager 实例,并实现相关 Delegate 协议以监听数据加载完成通知。HomeKit 采用异步加载模式 —— 在 Delegate 回调触发之前,切勿访问 homes 属性。

import HomeKit

final class HomeStore: NSObject, HMHomeManagerDelegate {
    let homeManager = HMHomeManager()

    override init() {
        super.init()
        homeManager.delegate = self
    }

    func homeManagerDidUpdateHomes(_ manager: HMHomeManager) {
        // 此时可以安全访问 manager.homes
        let homes = manager.homes
        let primaryHome = manager.primaryHome
        print("已加载 \(homes.count) 个家庭")
    }

    func homeManager(
        _ manager: HMHomeManager,
        didUpdate status: HMHomeManagerAuthorizationStatus
    ) {
        if status.contains(.authorized) {
            print("已获得 HomeKit 访问权限")
        }
    }
}

访问房间

guard let home = homeManager.primaryHome else { return }

let rooms = home.rooms
let kitchen = rooms.first { $0.name == "Kitchen" }

// 获取未分配给特定房间的默认房间
let defaultRoom = home.roomForEntireHome()

管理配件

发现与添加配件

在添加配件之前,请先查阅 Framework 职责边界 表格;本 Skill 仅聚焦 HomeKit 与 MatterSupport 相关的开发工作。

// 调起系统原生 UI 查找并添加配件
home.addAndSetupAccessories { error in
    if let error {
        print("添加配件失败: \(error)")
    }
}

遍历配件与服务

for accessory in home.accessories {
    print("\(accessory.name) 位于 \(accessory.room?.name ?? "未分配房间")")

    for service in accessory.services {
        print("  服务: \(service.serviceType)")

        for characteristic in service.characteristics {
            print("    特征: \(characteristic.characteristicType): \(characteristic.value ?? "nil")")
        }
    }
}

将配件移动至指定房间

guard let accessory = home.accessories.first,
      let bedroom = home.rooms.first(where: { $0.name == "Bedroom" }) else { return }

home.assignAccessory(accessory, to: bedroom) { error in
    if let error {
        print("移动配件失败: \(error)")
    }
}

读写特征值

读取数值

let characteristic: HMCharacteristic = // 从某个 service 中获取

characteristic.readValue { error in
    guard error == nil else { return }
    if let value = characteristic.value as? Bool {
        print("电源开关状态: \(value)")
    }
}

写入数值

// 打开灯光
characteristic.writeValue(true) { error in
    if let error {
        print("写入特征值失败: \(error)")
    }
}

监听状态变更

开启通知以获取实时更新回调:

characteristic.enableNotification(true) { error in
    guard error == nil else { return }
}

// 在 HMAccessoryDelegate 的回调方法中处理:
func accessory(
    _ accessory: HMAccessory,
    service: HMService,
    didUpdateValueFor characteristic: HMCharacteristic
) {
    print("特征值已更新: \(characteristic.value ?? "nil")")
}

动作集与触发器

创建动作集

HMActionSet 用于将多个特征值的写入操作打包,实现一键协同批量执行:

home.addActionSet(withName: "Good Night") { actionSet, error in
    guard let actionSet, error == nil else { return }

    // 关闭客厅灯光
    let lightChar = livingRoomLight.powerCharacteristic
    let action = HMCharacteristicWriteAction(
        characteristic: lightChar,
        targetValue: false as NSCopying
    )
    actionSet.addAction(action) { error in
        guard error == nil else { return }
        print("已成功将动作添加到晚安场景中")
    }
}

执行动作集

home.executeActionSet(actionSet) { error in
    if let error {
        print("场景执行失败: \(error)")
    }
}

创建定时触发器

var timeOfDay = DateComponents()
timeOfDay.hour = 22
timeOfDay.minute = 30

let firstFireDate = Calendar.current.nextDate(
    after: Date(),
    matching: timeOfDay,
    matchingPolicy: .nextTime
)!

let trigger = HMTimerTrigger(
    name: "Nightly",
    fireDate: firstFireDate,
    recurrence: DateComponents(day: 1)  // 首次触发后每天重复执行
)

home.addTrigger(trigger) { error in
    guard error == nil else { return }

    // 将动作集绑定到触发器上
    trigger.addActionSet(goodNightActionSet) { error in
        guard error == nil else { return }

        trigger.enable(true) { error in
            print("触发器启用状态: \(error == nil)")
        }
    }
}

创建事件触发器

let motionDetected = HMCharacteristicEvent(
    characteristic: motionSensorCharacteristic,
    triggerValue: true as NSCopying
)

let eventTrigger = HMEventTrigger(
    name: "Motion Lights",
    events: [motionDetected],
    predicate: nil
)

home.addTrigger(eventTrigger) { error in
    // 如上所示绑定动作集即可
}

Matter 设备配网

使用 MatterAddDeviceRequest 将 Matter 设备配网拉入你的 App 生态。该机制独立于 HMHome 自动化数据模型,主要负责处理 Matter 设备的原生配网流程并回调你的 MatterSupport 扩展。

基础配网流程

import MatterSupport

func addMatterDevice() async throws {
    guard MatterAddDeviceRequest.isSupported else {
        print("当前设备不支持 Matter 功能")
        return
    }

    let topology = MatterAddDeviceRequest.Topology(
        ecosystemName: "My Smart Home",
        homes: [
            MatterAddDeviceRequest.Home(displayName: "Main House")
        ]
    )

    let request = MatterAddDeviceRequest(
        topology: topology,
        setupPayload: nil,
        showing: .allDevices
    )

    // 调起系统配网 UI 进行设备配对
    try await request.perform()
}

如果是在 App 代码中直接传入配网码,需 import Matter 并把 MTRSetupPayload 作为 setupPayload 参数传入;此时需要在项目签名配置中开通 setup-payload 权限(entitlement)。

设备过滤

// 仅展示特定厂商(Vendor ID)的设备
let criteria = MatterAddDeviceRequest.DeviceCriteria.vendorID(0x1234)

let request = MatterAddDeviceRequest(
    topology: topology,
    setupPayload: nil,
    showing: criteria
)

可以通过 .all([.vendorID(...), .not(.productID(...))]) 组合多个过滤条件,或者使用 .any(...) 满足任意条件即可。

MatterAddDeviceExtensionRequestHandler

如果需要全面支持生态配网,请创建 MatterSupport Extension 扩展。该扩展负责接收配网过程中的各种回调。重写所需方法时,切勿调用 super
请参阅完整文档 Advanced Matter Extension Handler,了解凭据校验、房间选择、参数配置、配网绑定与网络关联等重写细节。

常见踩坑点

常见错误 正确做法
在 Delegate 回调前读取 homes 数据 保持单个 manager 实例,设置其 delegate,并等待 homeManagerDidUpdateHomes 回调后再使用数据。
使用 HomeKit 的添加配件流程去配网 Matter 生态设备 改用 MatterAddDeviceRequest 并配合配置好的 MatterSupport 扩展。
Matter 相关配置缺失 仔细检查 Principal Class 处理器、Bonjour 服务配置,且仅在显式传入配网码时才添加 setup-payload 权限。
实例化多个 HMHomeManager 导致数据库重复加载 在全局共享并持久化单例对象(Manager/Store)。
写入特征值时忽略了 Metadata 限制 写入操作前,先校验权限(permissions)、数据格式、最小值/最大值/步长以及允许值列表。

检查清单

  • [ ] Xcode 项目中已启用 HomeKit 能力
  • [ ] Info.plist 中已配置 NSHomeKitUsageDescription
  • [ ] 应用中全局共享唯一的 HMHomeManager 单例
  • [ ] 已实现 HMHomeManagerDelegate;在 homeManagerDidUpdateHomes 触发前未提前读取 homes
  • [ ] 已在家庭对象上设置 HMHomeDelegate 以监听配件与房间的变动
  • [ ] 已在配件对象上设置 HMAccessoryDelegate 以接收特征值的状态更新
  • [ ] 在写入特征值前已检查其 Metadata 属性限制
  • [ ] 所有 completion handler 中均包含了错误处理逻辑
  • [ ] 已配置 MatterSupport Extension Target 及其 Principal Handler 主类
  • [ ] 已在 NSBonjourServices 中添加 Matter 搜索广播服务项
  • [ ] 仅在代码直接提供配网码时才声明 com.apple.developer.matter.allow-setup-payload 权限
  • [ ] 执行请求前已通过 MatterAddDeviceRequest.isSupported 检查设备支持情况
  • [ ] Matter Extension Handler 已实现 commissionDevice(in:onboardingPayload:commissioningID:)
  • [ ] 发布上线前,已使用 HomeKit Accessory Simulator 对动作集进行测试
  • [ ] 创建触发器后已执行启用操作(trigger.enable(true)

参考资料