将新的 Matter 设备添加到住宅

适用于 iOS 的 Home API 使用 Matter 中枢将设备委托到功能区。在调试期间,应用会向 SDK 发送命令,然后将命令发送到 hub。

Xcode 项目配置

在实现 Commissioning API 之前,请务必将所需的功能、授权和 Info.plist 属性添加到您的 Xcode 目标:

使用权

在主应用目标和扩展程序的 .entitlements 文件中添加以下条目:

  • Thread 网络凭据管理:

    <key>com.apple.developer.networking.manage-thread-network-credentials</key>
    <true/>
    

    如需在分布式 build 中使用此授权,您必须向 Apple 提交授权请求表单。Apple 要求您证明自己是 Thread Group 的会员,并验证您的 Thread 边界路由器是否已获得 Thread Group 的认证。

  • Wi-Fi 信息:

    <key>com.apple.developer.networking.wifi-info</key>
    <true/>
    
  • 应用群组:添加共享应用群组,以允许主应用和“添加设备”扩展程序进行通信(例如 group.com.yourdomain.appgroupname)。此标识符由开发者在其 Apple 开发者控制台中创建和注册,并且必须与在 Xcode 的目标功能中配置的应用群组相匹配。MatterGoogle Home SDK 会在两个目标平台中使用此标识符,以使用共享的 UserDefaults 容器自动同步调试状态、功能区凭据和房间列表。

钥匙串共享(可选)

如果您的应用扩展程序需要使用 UserInfo.authorizationToken() 检索主应用存储的凭据或访问令牌,您必须在主应用和应用扩展程序目标的授权 plist 中配置共享密钥链访问组:

<key>keychain-access-groups</key>
<array>
    <string>$(AppIdentifierPrefix)your.shared.keychain.group</string>
</array>

Info.plist 属性

在主应用目标的 Info.plist 中添加以下说明键:

  • 位置信息使用说明:

    <key>NSLocationWhenInUseUsageDescription</key>
    <string>Your custom message explaining why location access is needed to read the current Wi-Fi SSID</string>
    
  • Bonjour 服务:在 NSBonjourServices 下,包含本地 Matter 和 Thread 发现所需的服务:

    <key>NSBonjourServices</key>
    <array>
        <string>_matter._tcp</string>
        <string>_matterc._udp</string>
        <string>_matterd._udp</string>
        <string>_meshcop._udp</string>
    </array>
    
  • 本地网络使用情况说明: 包含 NSLocalNetworkUsageDescription 键,其中包含一条说明本地网络发现权限的消息。

调试设备

如需调试 Matter 设备,请执行以下操作:

  1. 通知 Home APIs iOS SDK 准备好通过 structure.prepareForMatterCommissioning() 处理 Matter 调试请求。 此命令将执行以下操作:

    • 验证权限是否已授予。
    • 确保中枢处于在线状态且可访问。
    • 确保没有其他正在进行的主动调试会话。
    do {
      try await structure.prepareForMatterCommissioning()
    } catch {
      // Failed to prepare for Matter Commissioning
      return
    }
    
  2. 使用 MatterAddDeviceRequest() 创建请求,以启动 Apple 的 Matter 支持流程。

    let topology = MatterAddDeviceRequest.Topology(
      ecosystemName: "Google Home",
      homes: [MatterAddDeviceRequest.Home(displayName: structure.name)]
    )
    
    let request = MatterAddDeviceRequest(topology: topology)
    
  3. 使用 perform() 执行请求。如果发生错误,请使用 structure.cancelMatterCommissioning() 取消调试请求。

    do {
      // Starting MatterAddDeviceRequest.
      try await request.perform()
      // Successfully completed MatterAddDeviceRequest.
      let commissionedDeviceIDs = try structure.completeMatterCommissioning()
      // Commissioned device IDs.
    } catch let error {
      structure.cancelMatterCommissioning()
      // Failed to complete MatterAddDeviceRequest.
    }
    
  4. Apple 开发者控制台中创建 App Group ID,以便应用在调试设备时与 MatterAddDevice 扩展程序通信。

    您还需要更新应用软件包标识符和配置文件,以使用此群组 ID。

  5. 在初始化时,配置 Home 实例以使用群组标识符。

    func application(_ application: UIApplication, didFinishLaunchingWithOptions
    launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
      Home.configure {
        $0.sharedAppGroup = "group.com.sample.app.commissioning"
      }
    
      return true
    }
    
  6. 实现 Apple 的 iOS Matter 应用扩展。

    此示例代码展示了如何实现 Apple 的 MatterAddDeviceExtensionRequestHandler API 的子类。

    至少,将 GoogleHomeMatterCommissionerSDK 框架添加到扩展目标,并替换三种方法以调用 Google Home platformHomeMatterCommissioner API。

    • commissionDevice
    • rooms
    • configureDevice
    import MatterSupport
    import GoogleHomeSDK
    import OSLog
    
    final class RequestHandler: MatterAddDeviceExtensionRequestHandler {
      // The App Group ID defined by the application to share information between the extension and main app.
      private static var appGroup = "group.com.sample.app.commissioning"
    
      ...
    
      // MARK: - Home API commissioning handlers
    
      /// Commissions a device to the Google Home ecosystem.
      /// - Parameters:
      ///   - home: The home that the device will be added to
      ///   - onboardingPayload: The payload to be sent to the Matter Commissioning SDK to commission the device.
      ///   - commissioningID: An identifier not used by the Home API SDK.
      override func commissionDevice(in home: MatterAddDeviceRequest.Home?, onboardingPayload: String, commissioningID: UUID) async throws {
        // Commission Matter device with payload.
    
        var onboardingPayloadForHub = onboardingPayload
        let homeMatterCommissioner = try HomeMatterCommissioner(appGroup: RequestHandler.appGroup)
        try await homeMatterCommissioner.commissionMatterDevice(
        onboardingPayload: onboardingPayloadForHub)
      }
    
      /// Obtains rooms from the Home Ecosystem to present to the user during the commissioning flow.
      /// - Parameter home: The home that the device will be added to.
      /// - Returns: A list of rooms if obtained from the Google Home ecosystem or an empty list if there was an error in getting them.
      override func rooms(in home: MatterAddDeviceRequest.Home?) async -> [MatterAddDeviceRequest.Room] {
        do {
          let homeMatterCommissioner = try HomeMatterCommissioner(appGroup: RequestHandler.appGroup)
          let fetchedRooms = try homeMatterCommissioner.fetchRooms()
          // Returning fetched rooms.
          return fetchedRooms
        } catch {
          // Failed to fetch rooms with error
          return []
        }
      }
    
      /// Pushes the device's configurations to the Google Home Ecosystem.
      /// - Parameters:
      ///   - name: The friendly name the user chose to set on the device.
      ///   - room: The room identifier that the user chose to put the device in.
      override func configureDevice(named name: String, in room: MatterAddDeviceRequest.Room?) async {
        // Configure Device name: room
        do {
          let homeMatterCommissioner = try HomeMatterCommissioner(appGroup: RequestHandler.appGroup)
          await homeMatterCommissioner.configureMatterDevice(
            deviceName: name, roomName: room?.displayName)
        } catch {
          // Configure Device failed with error
        }
      }
    }