在 Android 上使用 Home API 构建移动应用

1. 准备工作

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

Google 为希望使用 Google Home API 访问实际示例的开发者提供了一个 Android 示例应用。此 Codelab 基于示例应用的一个分支,将引导您了解如何使用权限、调试、设备和结构 API。

前提条件

学习内容

  • 如何使用 Google Home API 并遵循最佳实践来构建 Android 应用。
  • 如何使用设备和结构 API 来表示和控制智能家居。
  • 如何使用调试 API 将设备添加到 Google Home 生态系统中。

可选:设置住宅

在使用 Google Home API 之前,您需要使用 Google Home 应用在 Google 账号中设置住宅,并添加一些设备。本部分将讨论如何使用 Google Home Playground(提供虚拟智能家居设备)来实现此目的。

在网络浏览器中打开 home-playground.withgoogle.com,使用您的 Google 账号登录,然后查看是否显示以下模拟设备:

  • outlet1:开启/关闭插座
  • light2:可调光灯
  • light3:开灯/关灯
  • ac3:空调
  • blinds4:窗饰
  • washer5:智能洗衣机

914d23a42b72df8f.png

在移动设备上打开 Google Home 应用,点按添加按钮,然后选择可与 Google Home 搭配使用。在列表中搜索“playground”,然后选择“Google Home Playground”项目,并点按继续

e9ec257b0d9b1ed2.png29fd7416e274d216.pngd974573af0611fd8.png

Google Home 游乐场会向您显示账号授权页面。点按授权使用 Google 账号登录。您会在移动应用中看到通过 Web 应用配置的所有设备。

13108a3a15440151.png8791a6d33748f7c8.png

选择所有设备,然后完成设置流程。返回到首页后,您会看到所有可用的设备。

2b021202e6fd1750.png

列表中的受支持设备现在可与 Google Home API 搭配使用。

2. 设置项目

下图展示了 Home API 应用的架构:

Android 应用的 Home API 架构

  • 应用代码:开发者用于构建应用的用户界面以及与 Home APIs SDK 交互的逻辑的核心代码。
  • Home APIs SDK:Google 提供的 Home APIs SDK 可与 GMSCore 中的 Home APIs 服务搭配使用,以控制智能家居设备。开发者通过将 Home API 与 Home API SDK 捆绑在一起,构建可与 Home API 搭配使用的应用。
  • Android 上的 GMSCore:GMSCore 也称为 Google Play 服务,是一个 Google 平台,可提供核心系统服务,从而在所有经过认证的 Android 设备上实现多种关键功能。Google Play 服务的首页模块包含与 Home API 交互的服务。

设置 Home SDK

按照设置 SDK 中概述的步骤获取最新 SDK。

获取示例应用

您可以在 GitHub 上找到示例应用的源代码。此 Codelab 使用的是示例应用的 codelab-branch-1 分支中的示例。

前往您要保存项目的位置,然后克隆 codelab-branch-1 分支:

$ git clone -b codelab-branch-1 https://github.com/google-home/google-home-api-sample-app-android.git

构建示例应用

按照构建应用中的步骤 1-5 操作。

32f2b3c0cd80fcf1.png

当应用在手机上成功运行时,您会看到“示例应用”主页面。不过,您需要先设置 OAuth 身份验证并使用 Permission API 实现缺失的部分,然后才能登录。

3. 设置身份验证

Home API 使用 OAuth 2.0 授予对结构中设备的访问权限。OAuth 允许用户向应用或服务授予权限,而无需泄露其登录凭据。

按照设置 OAuth 权限请求中的说明配置权限请求页面。请务必至少创建一个测试账号。

然后,按照设置 OAuth 凭据中的说明为应用创建凭据。

4. 初始化和处理权限

在本部分中,您将学习如何使用 Permissions API 完成缺失的部分,从而初始化 SDK 并处理用户权限。

定义支持的类型和特征

开发应用时,您需要明确注明应用将支持哪些设备类型和特征。在示例应用中,我们通过在 HomeApp.kt 的伴生对象中定义静态列表来实现此目的,然后可以在整个应用中根据需要引用这些列表:

companion object {

  // List of supported device types by this app:
  val supportedTypes: List<DeviceTypeFactory<out DeviceType>> = listOf(
    OnOffLightDevice,
    DimmableLightDevice,

  // ...
  )
  // List of supported device traits by this app:
  val supportedTraits: List<TraitFactory<out Trait>> = listOf(
  OnOff,
  LevelControl,
  // ...
  )
}

如需查看所有受支持的设备类型和特征,请参阅受支持的设备类型Android 上的特征索引

HomeApp.kt 源文件中取消注释步骤 4.1.1 和 4.1.2,以启用请求相应权限的源代码。

companion object {
// List of supported device types by this app:
val supportedTypes: List<DeviceTypeFactory<out DeviceType>> = listOf(
// TODO: 4.1.1 - Non-registered device types will be unsupported
//             ContactSensorDevice,
//             ColorTemperatureLightDevice,
//             DimmableLightDevice,
//             ExtendedColorLightDevice,
//             GenericSwitchDevice,
//             GoogleDisplayDevice,
//             GoogleTVDevice,
//             OccupancySensorDevice,
//             OnOffLightDevice,
//             OnOffLightSwitchDevice,
//             OnOffPluginUnitDevice,
//             OnOffSensorDevice,
//             RootNodeDevice,
//             SpeakerDevice,
//             ThermostatDevice,
)
// List of supported device traits by this app:
val supportedTraits: List<TraitFactory<out Trait>> = listOf(
// TODO: 4.1.2 - Non-registered traits will be unsupported
//             AreaAttendanceState,
//             AreaPresenceState,
//             Assistant,
//             AssistantBroadcast,
//             AssistantFulfillment,
//             BasicInformation,
//             BooleanState,
//             OccupancySensing,
//             OnOff,
//             Notification,
//             LevelControl,
//             TemperatureControl,
//             TemperatureMeasurement,
//             Thermostat,
//             Time,
//             Volume,
        )
}

初始化 HomeClient 对象

使用 Home API 的所有应用都会初始化一个 HomeClient 对象,该对象是与 API 交互的主要接口。我们在 HomeApp (HomeApp.kt) 类的初始化程序中准备此对象。

// Registry to record device types and traits used in this app:
val registry = FactoryRegistry(
  types = supportedTypes,
  traits = supportedTraits
)
// Configuration options for the HomeClient:
val config = HomeConfig(
  coroutineContext = Dispatchers.IO,
  factoryRegistry = registry
)
// Initialize the HomeClient, which is the primary object to use all Home APIs:
homeClient = Home.getClient(context = context, homeConfig = config)

首先,我们使用之前定义的受支持的类型和特征创建 FactoryRegistry。然后,使用此注册表初始化 HomeConfig,其中包含运行 API 所需的配置。接下来,我们使用 Home.getClient(...) 调用来获取 HomeClient 实例。

我们与 Home API 的所有互动都将通过此 HomeClient 对象进行。

使用 Permissions API

Home API 的用户身份验证通过 Permissions API 完成。示例应用的 PermissionsManager.kt 源文件包含用于用户身份验证的代码。取消注释 checkPermissions(...)requestPermissions(...) 函数的内容,以启用示例应用的权限。

注册:

homeClient.registerActivityResultCallerForPermissions(activity)

发布:

try {
    val result: PermissionsResult
    result = homeClient.requestPermissions(forceLaunch = true)
    when (result.status) {
        PermissionsResultStatus.SUCCESS -> // Success Case
        PermissionsResultStatus.CANCELLED -> // User Cancelled
        PermissionsResultStatus.ERROR -> // Some Error
else -> // Unsupported Case
    }
}
catch (e: HomeException) { ... }

检查:

try {
    val state: PermissionsState
    state = homeClient.hasPermissions().first { state ->
        state != PermissionsState.PERMISSIONS_STATE_UNINITIALIZED
    }
    when (state) {
        PermissionsState.GRANTED -> // Signed In
        PermissionsState.NOT_GRANTED -> // Not Signed In
        PermissionsState.PERMISSIONS_STATE_UNAVAILABLE -> // ...
        PermissionsState.PERMISSIONS_STATE_UNINITIALIZED -> // ...
else -> // Unsupported case
    }
}
catch (e: HomeException) { ... }

订阅:

       homeClient.hasPermissions().collect( { state ->
// Track the changes on state
        } )

PermissionsManager.kt 中取消注释步骤 4.3.1,以启用请求权限的代码:

fun requestPermissions() {
    scope.launch {
    try {
// TODO: 4.3.1 - Request the permissions from the Permissions API
//                 // Request permissions from the Permissions API and record the result:
//                 val result: PermissionsResult = client.requestPermissions(forceLaunch = true)
//                 // Adjust the sign-in status according to permission result:
//                 if (result.status == PermissionsResultStatus.SUCCESS)
//                     isSignedIn.emit(true)
//                 // Report the permission result:
//                 reportPermissionResult(result)
    }
    catch (e: HomeException) { MainActivity.showError(this, e.message.toString()) }
    }
}

现在,在手机上运行该应用,按照相应步骤操作并授予权限。您应该会看到以下流程:

c263dcee4e945bf1.png f518cfd1fdb8a9d8.png 59937372f28c472f.png 383073ae57d2ced4.png 89f774a2ba6898ae.png

“正在加载”消息始终未消失,但这是因为我们尚未实现读取结构和设备的代码。我们将在下一部分中进行此操作。

5. 了解数据模型

在 Home API 中,数据模型由以下部分组成:

  • Structure 表示包含房间和设备的住宅。
  • Room 是结构的一部分,包含设备。
  • 设备(定义为 HomeDevice)可以分配给结构(或住宅)或结构中的房间。
  • 设备由一个或多个 DeviceType 实例组成。
  • DeviceTypeTrait 实例组成。
  • TraitAttribute 实例(用于读取/写入)、Command 实例(用于控制属性)和 Event 实例(用于读取或订阅过去更改的记录)组成。
  • Automation 实例是结构的一部分,使用住宅元数据和设备来自动执行住宅中的任务。

76d35b44d5a8035e.png

在本部分中,您将学习如何开发源代码,以展示如何使用结构 API 来解析和呈现您的住宅结构、房间、设备等。

读取结构

Home API 设计基于 Kotlin Flow 来流式传输数据模型对象(例如 StructureHomeDevice 等)。开发者订阅 Flow 以获取对象中包含的所有对象(例如 StructureRoom 等)。

如需检索所有结构,请调用 structures() 函数,该函数会返回结构流。然后,对该流程调用 list 函数,以获取用户拥有的所有结构。

// Get the a snapshot of all structures from the current homeClient
val allStructures : Set<Structure> =
    homeClient.structures()   // HomeObjectsFlow<Structure>
    .list()                   // Set<Structure>

应用架构指南强烈建议采用现代响应式编程方法来改进应用数据流和状态管理。

以下是示例应用如何遵循响应式编码风格:

  • 视图模型(如 StructureViewModelDeviceViewModel,作为状态持有者)会订阅 Home APIs SDK 中的 flow 以接收值变化,并维护最新状态。
  • 视图(如 StructureViewDeviceView)会订阅视图模型以接收状态,并渲染界面以反映这些变化。
  • 当用户点击视图中的按钮(例如,灯设备的“开启”按钮)时,事件会触发视图模型的功能,这些功能会调用相应的 Home API 函数(例如,OnOff 特征的 On 命令)。

HomeAppViewModel.kt 的第 5.1.1 步中,我们通过调用 collect() 函数订阅结构更改事件。取消注释用于遍历 Structures API 响应返回的 structureSet 并在 StructureViewModel's StateFlow 中传送的部分。这允许应用监控结构状态变化:

   private suspend fun subscribeToStructures() {
// TODO: 5.1.1 - Subscribe the structure data changes
// // Subscribe to structures returned by the Structures API:
// homeApp.homeClient.structures().collect { structureSet ->
//     val structureVMList: MutableList<StructureViewModel> = mutableListOf()
//     // Store structures in container ViewModels:
//     for (structure in structureSet) {
//         structureVMList.add(StructureViewModel(structure))
//     }
//     // Store the ViewModels:
//     structureVMs.emit(structureVMList)
//
//     // If a structure isn't selected yet, select the first structure from the list:
//     if (selectedStructureVM.value == null && structureVMList.isNotEmpty())
//         selectedStructureVM.emit(structureVMList.first())
//
// }
}

DevicesView.kt 中,应用订阅 StructureViewModel'sStateFlow,,当结构数据发生变化时,该对象会触发界面重组。取消注释步骤 5.1.2 中的源代码,以将结构列表呈现为下拉菜单:

   val structureVMs: List<StructureViewModel> = homeAppVM.structureVMs.collectAsState().value
...
DropdownMenu(expanded = expanded, onDismissRequest = { expanded = false }) {
// TODO: 5.1.2 - Show list of structures in DropdownMenu
//  for (structure in structureVMs) {
//      DropdownMenuItem(
//          text = { Text(structure.name) },
//          onClick = {
//              scope.launch { homeAppVM.selectedStructureVM.emit(structure) }
//              expanded = false
//          }
//      )
//  }
}
...

再次运行应用。点按箭头后,您应该会看到该菜单:

f1fc2be1cb6436b6.png

解析结构

下一步是在结构中遍历住宅对象。从结构中检索房间:

val rooms: Set<Room>
rooms = structure.rooms().list()

然后,您可以遍历房间以检索设备:

val devices: Set<HomeDevice>
devices = room.devices().list()

重要提示:在 Home API 数据模型中,结构可以包含未分配给房间的设备,因此请务必在应用中捕获没有房间的设备:

val devicesWithoutRooms: MutableSet<HomeDevice> = mutableSetOf()

for (device in structure.devices().list())
if (device.roomId == null)
  devicesWithoutRooms.add(device)

同样,在现有示例代码中,我们订阅了一个流来获取最新的会议室和设备列表。检查 StructureViewModel.kt 源文件中的步骤 5.2.1 和 5.2.2 中的代码,并取消注释以启用 Room 数据订阅:

val roomVMs : MutableStateFlow<List<RoomViewModel>>
val deviceVMs : MutableStateFlow<List<DeviceViewModel>>
val deviceVMsWithoutRooms : MutableStateFlow<List<DeviceViewModel>>
private suspend fun subscribeToRooms() {
// TODO: 5.2.1 - Subscribe the room data changes
//   // Subscribe to changes on rooms:
//   structure.rooms().collect { roomSet ->
//       val roomVMs = mutableListOf<RoomViewModel>()
//       // Store rooms in container ViewModels:
//       for (room in roomSet) {
//           roomVMs.add(RoomViewModel(room))
//       }
//       // Store the ViewModels:
//       this.roomVMs.emit(roomVMs)
//   }
}
private suspend fun subscribeToDevices() {
// TODO: 5.2.2 - Subscribe the device data changes in a structure
//   // Subscribe to changes on devices:
//   structure.devices().collect { deviceSet ->
//       val deviceVMs = mutableListOf<DeviceViewModel>()
//       val deviceWithoutRoomVMs = mutableListOf<DeviceViewModel>()
//       // Store devices in container ViewModels:
//       for (device in deviceSet) {
//           val deviceVM = DeviceViewModel(device)
//           deviceVMs.add(deviceVM)
//           // For any device that's not in a room, additionally keep track of a separate list:
//           if (device.roomId == null)
//               deviceWithoutRoomVMs.add(deviceVM)
//       }
//       // Store the ViewModels:
//       this.deviceVMs.emit(deviceVMs)
//       deviceVMsWithoutRooms.emit(deviceWithoutRoomVMs)
//   }
    }

取消 DevicesView.kt 源文件中的步骤 5.2.3 和 5.2.4 的注释,以将会议室列表呈现为菜单:

val selectedRoomVMs: List<RoomViewModel> =
selectedStructureVM.roomVMs.collectAsState().value
...
for (roomVM in selectedRoomVMs) {
// TODO: 5.2.3 - Render the list of rooms
//   RoomListItem(roomVM)
// TODO: 5.2.4 - Render the list of devices in a room
//   val deviceVMsInRoom: List<DeviceViewModel> = roomVM.deviceVMs.collectAsState().value
//
//   for (deviceVM in deviceVMsInRoom) {
//       DeviceListItem(deviceVM, homeAppVM)
//   }
}

现在您已经拥有这些设备,接下来我们将学习如何使用它们。

e715ddda50e04839.png

6. 使用设备

Home API 使用 HomeDevice 对象来捕获设备及其功能。开发者可以订阅设备属性,并使用这些属性在其应用中表示智能家居设备。

读取设备状态

HomeDevice 对象提供了一组静态值,例如设备名称或连接状态。作为开发者,您可以在通过 API 获取设备后立即检索这些信息:

val id: String = device.id.id
val name: String = device.name
val connectivity: ConnectivityState =
    device.sourceConnectivity.connectivityState

为了获取设备功能,您需要从 HomeDevice 中检索类型和特征。为此,您可以按如下方式订阅设备类型流程,并从设备类型中检索特征:

device.types().collect { typeSet ->
var primaryType : DeviceType = UnknownDeviceType()
for (typeInSet in typeSet)
if (typeInSet.metadata.isPrimaryType)
                    primaryType = typeInSet
            val traits: List<Trait> = mutableListOf()
for (trait in primaryType.traits())
if (trait.factory in myTraits)
                    traits.add(trait)
for (trait in traits)
                parseTrait(trait, primaryType)
        }

每个设备都包含一组受支持的 DeviceType(捆绑的功能),您可以使用 device.types() 进行检索。这些设备类型包含可以使用 type.traits() 检索的特征。每种设备都会将其某一种类型标记为主要类型(可以使用 type.metadata.isPrimaryType 进行检查),您应在应用中表示该类型。为了向用户提供完整的体验,我们建议您遍历所有返回的类型,并集成所有可用的特征。

检索到特征后,您可以使用如下所示的函数来解析特征,以解读相应的值:

fun <T : Trait?> parseTrait(trait : T, type: DeviceType) {
    val status : String = when (trait) {
        is OnOff -> { if (trait.onOff) "On" else "Off" }
        is LevelControl -> { trait.currentLevel.toString() }
        is BooleanState -> {
            when (type.factory) {
                ContactSensorDevice -> {
if (trait.stateValue) "Closed"
else "Open"
                }
else -> ...
            }
        }
else -> ...
    }
}

请注意,特征所代表的含义可能会因采用该特征的设备类型而异(请参阅上例中的 BooleanState),因此您需要了解每种设备类型的上下文,才能了解其特征的真正含义。

取消 DeviceViewModel.kt 源文件中的步骤 6.1.1 和 6.1.2 的注释,以检索状态:

private suspend fun subscribeToType() {
// Subscribe to changes on device type, and the traits/attributes within:
device.types().collect { typeSet ->
// Container for the primary type for this device:
var primaryType : DeviceType = UnknownDeviceType()
...
// TODO: 6.1.1 - Determine the primary type for this device
//       // Among all the types returned for this device, find the primary one:
//       for (typeInSet in typeSet)
//           if (typeInSet.metadata.isPrimaryType)
//               primaryType = typeInSet
//
//       // Optional: For devices with a single type that did not define a primary:
//       if (primaryType is UnknownDeviceType && typeSet.size == 1)
//           primaryType = typeSet.first()
// Container for list of supported traits present on the primary device type:
val supportedTraits: List<Trait> = getSupportedTraits(primaryType.traits())
...
}
fun getSupportedTraits(traits: Set<Trait>) : List<Trait> {
           val supportedTraits: MutableList<Trait> = mutableListOf()
// TODO: 6.1.2 - Get only the supported traits for this device
//   for (trait in traits)
//       if (trait.factory in HomeApp.supportedTraits)
//           supportedTraits.add(trait)
return supportedTraits
}

取消 DeviceView.kt 中第 6.1.3 步的注释,以将 OnOff 特征(包括其名称和状态)呈现为 String

Box (Modifier.padding(horizontal = 24.dp, vertical = 8.dp)) {
when (trait) {
is OnOff -> {
// TODO: 6.1.3 - Render controls based on the trait type
// Column (Modifier.fillMaxWidth()) {
//     Text(trait.factory.toString(), fontSize = 20.sp)
//     Text(DeviceViewModel.getTraitStatus(trait, type), fontSize = 16.sp)
// }
...
}
is LevelControl -> {
      ...
  }
   is BooleanState -> {
      ...
  }
   is OccupancySensing -> {
      ...
  }
  ...
}

如果您现在使用受支持的设备类型(例如 Light 设备)运行应用,该应用应会显示所有设备的最新状态。

1bd8b3b2796c4c7a.png

发出设备命令

为了向设备下达指令,Home API 在特征对象(例如 trait.on()trait.moveToLevel(...))上提供了便捷函数:

fun <T : Trait?> issueCommand(trait : T) {
     when (trait) {
         is OnOff -> {
// trait.on()
// trait.off()
   }
   is LevelControl -> {
// trait.moveToLevel(...)
// trait.moveToLevelWithOnOff(...)
        }
    }
}

提示:确定特征的类型后,使用 Android Studio 的自动补全功能查看可用于与该特征互动的操作类型。

取消 DeviceView.kt 中第 6.2.1 步的注释,以在应用中添加功能控件:

Box (Modifier.padding(horizontal = 24.dp, vertical = 8.dp)) {
when (trait) {
is OnOff -> {
                ....
// TODO: 6.2.1 - Render controls based on the trait type
//   Switch (checked = (trait.onOff == true), modifier = Modifier.align(Alignment.CenterEnd),
//       onCheckedChange = { state ->
//           scope.launch { if (state) trait.on() else trait.off() }
//       },
//       enabled = isConnected
//   )
}

如果您现在运行该应用,它应该允许您控制现实生活中的实体设备。

如果您点按灯泡上的 OnOff 控制器,设备现在应该会亮起。

c8ed3ecf5031546e.png

如需详细了解如何控制设备,请参阅在 Android 上控制设备

7. 调试设备

借助调试 API,开发者可以将设备添加到 Google Home 生态系统中,并使用 Home API 控制这些设备。仅支持 Matter 设备。在本部分中,我们将探讨如何在应用中启用设备调试。

在开始本部分之前,请确保满足以下前提条件:

如果您有实体 Matter 设备,并且该设备具有用于调试的二维码,则可以跳到启用调试 API。否则,请继续阅读下一部分,其中介绍了如何使用 Matter 虚拟设备应用 (MVD) 创建可调试的虚拟设备。

可选:准备可调试的 Matter 设备

准备可调试的 Matter 设备最简单的方法是使用 Matter 虚拟设备 (MVD) 应用提供的模拟设备。

安装 MVD 并设置防火墙后,运行 MVD:

b20283893073ac1b.png

创建 OnOff 设备。请注意,该设备尚未完成调试,您将在本 Codelab 的后面部分完成调试。

5f4855b808312898.png

启用 Commissioning API

调试 API 在应用 Activity 之外运行,因此调试需要以不同于其他 Home API 的方式进行处理。为了让应用做好调试准备,您需要两个变量。

一个变量是 ActivityResultLauncher,用于发送调试 intent 和管理结果回调。另一个变量是 CommissioningResult,用于存储调试结果。如需了解如何设置调试,请参阅以下示例:

var launcher: ActivityResultLauncher<IntentSenderRequest>
lateinit var commissioningResult: CommissioningResult?
launcher = activity.registerForActivityResult(StartIntentSenderForResult()) { result ->
try {
  commissioningResult = CommissioningResult.fromIntentSenderResult(
      result.resultCode, result.data)
  } catch (exception: ApiException) {
// Catch any issues
 }
}

设置好调试流程后,您将构建调试 intent,并使用我们在上一个示例中创建的启动器启动该 intent。我们建议将 intent 和启动器放置在专用函数中,如下所示。专用功能可以与界面元素(例如添加设备按钮)相关联,并根据用户请求进行调用:

fun requestCommissioning() {
// Retrieve the onboarding payload used when commissioning devices:
val payload = activity.intent?.getStringExtra(Matter.EXTRA_ONBOARDING_PAYLOAD)
  scope.launch {
    // Create a commissioning request to store the device in Google's Fabric:
    val request = CommissioningRequest.builder()
      .setStoreToGoogleFabric(true)
      .setOnboardingPayload(payload)
      .build()
    // Initialize client and sender for commissioning intent:
    val client: CommissioningClient = Matter.getCommissioningClient(context)
    val sender: IntentSender = client.commissionDevice(request).await()
    // Launch the commissioning intent on the launcher:
    launcher.launch(IntentSenderRequest.Builder(sender).build())
  }
}

取消 CommissioningManager.kt 中第 7.1.1 步的注释,以启用调试功能,并使添加设备按钮在示例应用中正常运行。

// Called by +Add Device button in DeviceView.kt
fun requestCommissioning() {
// Retrieve the onboarding payload used when commissioning devices:
val payload = activity.intent?.getStringExtra(Matter.EXTRA_ONBOARDING_PAYLOAD)
// TODO: 7.1.1 - Launch the commissioning intent
// scope.launch {
//     // Create a commissioning request to store the device in Google's Fabric:
//     val request = CommissioningRequest.builder()
//         .setStoreToGoogleFabric(true)
//         .setOnboardingPayload(payload)
//         .build()
//     // Initialize client and sender for commissioning intent:
//     val client: CommissioningClient = Matter.getCommissioningClient(context)
//     val sender: IntentSender = client.commissionDevice(request).await()
//     // Launch the commissioning intent on the launcher:
//     launcher.launch(IntentSenderRequest.Builder(sender).build())
// }
}

运行此函数应会启动调试流程,该流程应会显示类似于以下屏幕截图的界面:

baae45588f460664.png

了解调试流程

调试流程包含一组界面,可引导用户将设备添加到其 Google 账号:

2fb0404820d4a035.png 3cbfa8ff9cfd5ee4.png a177c197ee7a67bf.png 3fdef24672c77c0.png dec8e599f9aa119.png

用户会看到一个二维码扫描器,可用于扫描 Matter 设备的二维码。然后,该流程将显示《用户协议》、设备发现和调试,以及为设备命名。当流程完成后,流程会将焦点重新移回应用,并在我们在上一部分中编写的回调函数中传递调试结果。

配置 API 的一个好处是,用户体验流程由 SDK 处理,因此开发者可以非常快速地启动并运行。此外,这还能让用户在不同应用中添加设备时获得一致的体验。

如需详细了解调试 API,请访问 Android 上的调试 API

8. 恭喜!

恭喜!您已成功使用 Google Home API 创建了一个 Android 应用。在本 Codelab 中,您探索了权限、设备、结构和调试 API。在下一个 Codelab(在 Android Codelab 上使用 Home API 创建高级自动化操作)中,我们将探索 Automation 和 Discovery API,并完成应用。

我们希望您能尽情开发应用,以富有创意的方式控制 Google Home 生态系统中的设备。

后续步骤