1. 简介

什么是 Home API?
Google Home API 提供了一组库,供开发者接入 Google Home 生态系统。借助 Home API,开发者可以构建可无缝调试和控制智能家居设备的应用。

此视频简要演示了您将构建的移动应用,因此请在完成 Codelab 的同时观看此视频。
Home API 的组成部分
Home API 由以下部分组成:
- 设备和结构 API:与用户的住宅互动。应用可以使用这些 API 读取有关设备、房间和结构的信息(例如,查看当前温控器温度),并控制设备(例如,更改温控器设定值)。
- 调试 API:以最少的精力将新的 Matter 设备调试(设置)到结构中。
- Automation API:创建、删除和查询在用户住宅中运行的自动化操作。
前提条件
- 最新稳定版 Xcode。
- 在住宅中至少有一个住宅结构的 Google 账号。
- 已设置测试账号且搭载 iOS 16.4 及更高版本的 iOS 设备。
- 已注册加入 Apple 开发者计划的 Apple ID,用于生成预配配置文件。
- 支持 Home API 的 Google 中枢。
学习内容
- 如何使用 Home API 按照最佳实践构建 iOS 应用。
- 如何使用设备和结构 API 来表示和控制智能家居。
- 如何使用调试 API 将设备添加到 Google Home 生态系统。
- 如何使用 Automation API 创建基本自动化操作。
2. 设置住宅
准备设备
Google Home Playground 提供各种预构建的模拟智能家居设备,建议您使用它来充分发掘 Home API 的潜力,尤其是在您家中的设备数量有限的情况下。
按照说明登录 Google Home Playground,然后在 Google Home 应用中完成账号关联。完成此操作后,您应该能够在 Google Home 应用的“设备”标签页中看到这些设备。

3. 准备工作
获取示例应用的代码
首先,从 GitHub 克隆源代码:
git clone https://github.com/google-home/google-home-api-sample-app-ios.git
示例目录中包含此 Codelab 的两个分支:start 和 finished。
start:该项目的起始代码;您将通过更改这些代码来完成此 Codelab。finished:该 Codelab 的完成后代码,用于检查您的工作。
探索起始代码
首先,切换到克隆的代码库的 start 分支:
git checkout start
此分支包含项目的起始代码。您将在整个 Codelab 中修改此代码,以实现完整的功能。此 Codelab 示例应用提供了一个使用 Swift 构建的基本结构,用于与 Home APIs iOS SDK 交互。我们来快速了解一下 start 项目中的关键组件:
Main Entry (GoogleHomeAPISampleIOSApp):位于GoogleHomeAPISampleIOS/Main/GoogleHomeAPISampleIOS.swift中,是应用的主要入口点。它会配置并初始化 SDK,并设置主界面。Core Views (View/):MainView.swift:启动后的根视图,包含主NavigationView。它负责处理选择有效的 Google Home 结构并显示相应的StructureView。StructureView.swift:显示当前所选结构的内容,使用标签页在设备网格和自动化操作列表之间切换。它还提供了用于添加房间或设备的菜单。DeviceView.swift:表示StructureView网格中单个设备的互动式功能块。AutomationsView.swift:显示结构的现有自动化列表,并提供用于创建或查看自动化详细信息的导航。
ViewModels (ViewModel/):这些类用于管理视图的状态和逻辑。AccountViewModel.swift:处理与Home对象的连接并管理身份验证状态。MainViewModel.swift:管理可用Structure对象的列表,并跟踪所选结构。StructureViewModel.swift:管理所选结构中房间和DeviceControl对象的显示。AutomationList.swift、AutomationViewModel.swift等:处理自动化操作的提取、显示、创建和管理。
Device Controls (ViewModel/Device/):DeviceControl.swift:用于在界面中表示可控制设备的基类。- 特定子类(
LightControl.swift、FanControl.swift、OnOffPlugInUnitControl.swift等):根据不同设备类型的特征,实现其界面逻辑、设备控制和状态映射。 DeviceControlFactory.swift:负责为给定的HomeDevice创建合适的DeviceControl子类。
Commissioning (Commissioning/):CommissioningManager.swift:包含用于管理 Matter 设备调试流程的逻辑。
Utilities & UX (Utils/, UX/, Storage/):包含界面元素(颜色、尺寸)、错误处理、数据存储 (SelectedStructureStorage.swift) 和其他实用程序的辅助代码。
在此 Codelab 中,您会在 start 项目中看到类似 TODO 的注释、已注释掉的代码块和提醒。这些标记表示您将添加或取消注释代码以实现所需功能的部分,请按照提供的步骤操作。
创建 Apple 部署配置文件
如需配置 App Attest,请按照有关创建 Apple 部署配置文件的说明操作。请注意,设置完成后,应用只能部署在真实设备上,而不能部署在模拟器中。
设置身份验证
如需获取 OAuth 客户端 ID 并启用 Home API,请先登录 Google Cloud,然后创建新项目或选择现有项目。然后,按照提供的步骤生成 OAuth 客户端 ID 并启用 Home API,并将您的账号添加到许可名单中。
设置 SDK
获取 Home APIs iOS SDK,并按照设置 SDK 中提供的设置说明对其进行配置。请记得将 HOME_API_TODO_ADD_APP_GROUP 替换为您自己的应用组。
构建并运行项目
使用 start 分支构建并运行项目后,系统应显示 TODO 对话框和显示“需要登录”的界面。Home API 互动将在以下部分中实现。

注意:通过在项目中搜索对话框中显示的文字,找到需要修改的代码。例如,搜索“TODO: initialize Home”。
4. 初始化
初始化 Home
在针对 iOS 使用任何 Home API 之前,您必须在应用中初始化 Home。Home 是 SDK 的顶级入口点,可用于访问用户结构中的所有实体。当您请求特定类型的所有实体时,API 会返回一个 Query 对象,让您选择接收结果的方式。在 GoogleHomeAPISampleIOS/Accounts/AccountViewModel.swift 中,移除 connect() 中的注释和提醒,以实现首页初始化。
/// TODO: initialize Home
/// Remove comments to initialize Home and handling permission.
private func connect() {
Task {
do {
self.home = try await Home.connect()
} catch {
Logger().error("Auth error: \(error).")
}
}
}
使用 Home API 的权限
运行应用时,系统会显示同意情况界面。选择 Google Home 结构,然后选择您的 Google Cloud 项目的许可名单中的账号。

5. 设备和结构
获取会议室和设备
在 GoogleHomeAPISampleIOS/ViewModel/StructureViewModel.swift 中,移除 getRoomsAndDevices() 中的注释和提醒,以分别通过 home.rooms() 和 home.devices() 获取所选结构中的会议室和设备。
/// TODO: get rooms and devices
/// Remove comments to get the rooms and devices from home entry
private func getRoomsAndDevices(){
self.home.rooms().batched()
.combineLatest(self.home.devices().batched())
.receive(on: DispatchQueue.main)
.catch { error in
Logger().error("Failed to load rooms and devices: \(error)")
return Just((Set<Room>(), Set<HomeDevice>()))
}
.map { [weak self] rooms, devices in
guard let self = self else { return [] }
self.hasLoaded = true
return self.process(rooms: rooms, devices: devices)
}
/// receive from .map and .assign() to publisher entries
.assign(to: &self.$entries)
}
process() 函数首先确保设备位于同一房间,然后使用 DeviceControl 和 DeviceControlFactory 使设备以 HomeDevices 方式互动。

注意:如果您的设备未列在 DeviceControlFactory 中,则会显示为“不支持”。如需详细了解支持的设备,请参阅 iOS 上支持的设备类型页面。
与设备互动
在设备上点按或滑动时,插头 outlet1 最初处于非活动状态。如需启用与该元素的互动,请找到 GoogleHomeAPISampleIOS/ViewModel/Device/OnOffPlugInUnitControl.swift 并移除 primaryAction() 函数中的注释和提醒。
/// TODO: primary action of OnOffPlug
/// Toggles the plug; usually provided as the `action` callback on a Button.
public override func primaryAction() {
self.updateTileInfo(isBusy: true)
Task { @MainActor [weak self] in
guard
let self = self,
let onOffPluginUnitDeviceType = self.onOffPluginUnitDeviceType,
let onOffTrait = onOffPluginUnitDeviceType.matterTraits.onOffTrait
else { return }
do {
try await onOffTrait.toggle()
} catch {
Logger().error("Failed to to toggle OnOffPluginUnit on/off trait: \(error)")
self.updateTileInfo(isBusy: false)
}
}
}
primaryAction() 函数位于 OnOffPlugInUnitControl 类中,用于切换智能插座或任何由 OnOffPluginUnitDeviceType 表示的设备的开启/关闭状态。
如需查看更多设备控制示例,请参阅 GoogleHomeAPISampleIOS/ViewModel/Device。
创建新房间
借助结构 API,您可以创建和删除房间,以及在房间之间转移设备。
在 GoogleHomeAPISampleIOS/ViewModel/StructureViewModel.swift 中,移除 addRoom() 中的注释和提醒。
/// TODO: add room
/// Add a new room in a given structure.
func addRoom(name: String, structure: Structure) {
Task {
do {
// The view will be updated with the values from the devices publisher.
_ = try await structure.createRoom(name: name)
} catch {
Logger().error("Failed to create room: \(error)")
}
}
}
如需使用 structure.createRoom() 创建新聊天室,请前往左上角,依次选择 “+”图标 > 添加聊天室。输入新聊天室名称,然后点击“创建聊天室”。新会议室会在几秒钟后显示。

将设备移至其他房间
在 GoogleHomeAPISampleIOS/ViewModel/StructureViewModel.swift 中,移除 moveDevice() 中的注释和提醒。
/// TODO: move device
/// Move a device into a different room.
func moveDevice(device deviceID: String, to roomID: String, structure: Structure) {
Task {
do {
_ = try await structure.move(device: deviceID, to: roomID)
} catch {
Logger().error("Failed to move to room: \(error)")
}
}
}
如需重新放置带有 structure.move() 的设备,请长按该设备,选择“移至其他房间”,然后选择新房间。

删除空会议室
在 GoogleHomeAPISampleIOS/ViewModel/StructureViewModel.swift 中,移除 removeRoom() 中的注释和提醒。
/// TODO: delete room
/// Delete an empty room in a given structure.
func removeRoom(id: String, structure: Structure) {
Task {
do {
// The view will be updated with the values from the devices publisher.
_ = try await structure.deleteRoom(id: id)
} catch {
Logger().error("Failed to remove room: \(error)")
}
}
}
如需删除包含 structure.deleteRoom() 的空聊天室,请点击聊天室名称右侧的回收站图标,然后确认操作。请注意,只能删除空聊天室。

注意:将设备移回原位,即可创建空房间。
6. 调试
注意:本部分需要 Google 中枢和 Matter 设备。确保结构中的 Google 集线器已联网且可访问。如果您没有 Matter 设备,请尝试改用 Matter 虚拟设备应用。
添加 Matter 设备
借助 Commissioning API,您的应用可以将新的 Matter 设备添加到用户的住宅和 Google 账号。这样一来,用户便可以直接在您的应用中顺畅地完成设置。
在 GoogleHomeAPISampleIOS/Commissioning/CommissioningManager.swift 中,移除 addMatterDevice() 中的注释和提醒。
/// TODO: add Matter Device
/// Starts the Matter device commissioning flow to add the device to the user's home.
/// - Parameters:
/// - structure: The structure to add the device to.
/// - add3PFabricFirst: Whether to add the device to a third party fabric first.
public func addMatterDevice(to structure: Structure, add3PFabricFirst: Bool) {
self.isCommissioning = true
/// pass if it's 1p or 3p commissioning
let userDefaults = UserDefaults(
suiteName: CommissioningManager.appGroup)
userDefaults?.set(
add3PFabricFirst, forKey: CommissioningUserDefaultsKeys.shouldPerform3PFabricCommissioning)
Task {
do {
try await structure.prepareForMatterCommissioning()
} catch {
Logger().error("Failed to prepare for Matter Commissioning: \(error).")
self.isCommissioning = false
return
}
// Prepare the Matter request by providing the ecosystem name and home to be added to.
let topology = MatterAddDeviceRequest.Topology(
ecosystemName: "Google Home",
homes: [MatterAddDeviceRequest.Home(displayName: structure.name)]
)
let request = MatterAddDeviceRequest(topology: topology)
do {
Logger().info("Starting MatterAddDeviceRequest.")
try await request.perform()
Logger().info("Completed MatterAddDeviceRequest.")
let commissionedDeviceIDs = try structure.completeMatterCommissioning()
Logger().info("Commissioned device IDs: \(commissionedDeviceIDs).")
} catch let error {
structure.cancelMatterCommissioning()
Logger().error("Failed to complete MatterAddDeviceRequest: \(error).")
}
self.isCommissioning = false
}
}
如需创建包含 structure.prepareForMatterCommissioning() 的新房间,请前往左上角,依次选择 “+”图标 > 将设备添加到 Google Fabric。它使用 MatterAddDeviceRequest 将 Matter 设备添加到房间中。选择房间和设备名称后,设备会显示在“设备”界面中。

7. 自动化
查看结构中的所有自动化操作
点按底部导航栏中的自动化。它会使用 structure.listAutomations() 列出结构中的所有自动化。

注意:如果您未设置任何家居自动化操作,系统会显示“添加自动化操作以开始使用”。
创建自动化操作
现在,您已熟悉设备和结构 API 以及添加新设备,接下来可以使用自动化 API 创建新的自动化操作。
在 GoogleHomeAPISampleIOS/ViewModel/Automation/AutomationsRepository.swift 中,移除 lightAutomation() 中的注释、提醒和空自动化操作。
/// TODO: create automation
/// - Parameter devices: devices in current selected structure
/// - Returns: the automation object to be created
/// This automation will turn off the light after 5 seconds.
public func lightAutomation(devices: Set<HomeDevice>) async throws -> any DraftAutomation {
let light = devices.first { $0.name == "light2" }
guard let light else {
Logger().error("Unable to find light device with name light2")
throw HomeError.notFound("No devices support OnOffLightDeviceType")
}
return automation(
name: "Turn off light after 5 seconds",
description:
"""
Turns off light2 after it has been on for 5 seconds.
"""
) {
let onOffStarter = starter(light, OnOffLightDeviceType.self, OnOffTrait.self)
onOffStarter
condition {
onOffStarter.onOff.equals(true)
}
delay(for: Duration.seconds(5))
action(light, OnOffLightDeviceType.self) {
OnOffTrait.off()
}
}
}
如需创建在灯开启 5 秒后将其关闭的自动化操作,请前往自动化视图,然后点击“+ 添加”按钮。然后,选择“5 秒后关灯”。系统会显示自动化操作详细信息,包括 starter、condition 和 action。点击“保存”,即可通过 structure.createAutomation() 创建自动化。

注意:可用的自动化操作取决于您家中的设备。如果您没有看到任何可用的自动化操作,请尝试将灯具设备重命名为“light2”。
返回“设备”标签页,然后开启名为“light2”的灯。它会在 5 秒后自动关闭。
自动化的组成部分包括:
- 启动方式:用于启动自动化操作的事件。在此示例中,一旦
OnOffTrait发生变化,自动化操作就会启动。 - 条件:此检查用于确定启动器设备是否符合特定要求。在这种情况下,如果灯亮着,自动化操作就会执行。
- 操作:这是您希望执行的自动化操作,但前提是启动方式满足要求。如果满足相应条件,灯具就会关闭。
如需查看更多示例,请参阅自动化示例页面。
删除自动化操作
当您在现有自动化上向左滑动并点按回收站图标以将其从结构中移除时,系统会调用 structure.deleteAutomation() 方法。

8. 恭喜
恭喜!您已成功使用适用于 iOS 的 Home API 构建了一个基本的智能家居应用。
您的成就:
- 初始化:使用
Home.connect()将应用连接到 Google Home 生态系统。 - 权限:处理用户身份验证和授权,以访问住宅数据。
- 设备和结构:使用
home.rooms()和home.devices()获取并显示房间和设备。 - 设备控制:已实现的设备互动,例如通过调用
OnOffPluginUnitDeviceType的特征来切换其状态。 - 结构管理:新增了以下功能:创建新房间 (
structure.createRoom())、在房间之间移动设备 (structure.move()) 以及删除空房间 (structure.deleteRoom())。 - 调试:集成了 SDK 的调试流程,以添加新的 Matter 设备 (
MatterAddDeviceRequest)。 - 自动化:探讨了如何在结构中列出、创建 (
structure.createAutomation()) 和删除 (structure.deleteAutomation()) 自动化操作。
现在,您已经对如何利用 Home API 在 iOS 上打造丰富的智能家居控制体验有了基本的了解。
后续步骤:
- 探索如何控制示例应用中提供的其他设备类型(灯具、风扇、百叶窗等)。
- 深入了解适用于各种设备的不同特征和命令。
- 尝试使用不同的启动方式、条件和操作创建更复杂的自动化操作。
- 如需了解更高级的功能和详细信息,请参阅 Home API 文档。
太棒了!