Cómo agregar dispositivos Matter nuevos a una casa

Las APIs de Home para iOS usan un Matter hub para acondicionar un dispositivo en una estructura. Durante el acondicionamiento, la app envía un comando al SDK y, luego, al hub.

Configuración del proyecto de Xcode

Antes de implementar la API de Commissioning, asegúrate de agregar las capacidades, las autorizaciones y las propiedades de Info.plist requeridas a tus objetivos de Xcode:

Autorizaciones

Incluye las siguientes entradas en el objetivo principal de la app y en los archivos .entitlements de la extensión:

  • Administración de credenciales de red de Thread:

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

    Para usar esta autorización en una compilación distribuida, debes enviar un formulario de solicitud de autorización a Apple. Apple requiere que demuestres la membresía en el Grupo de Thread y verifiques que tu router de borde de Thread esté certificado por el Grupo de Thread.

  • Información de Wi-Fi:

    <key>com.apple.developer.networking.wifi-info</key>
    <true/>
    
  • Grupos de apps: Agrega un grupo de apps compartidas para permitir que tu app principal y la Matter extensión de Add Device se comuniquen (por ejemplo, group.com.yourdomain.appgroupname). El desarrollador crea y registra este identificador en su Apple Developer Console, y debe coincidir con el grupo de apps configurado en las capacidades de destino en Xcode. El SDK de Google Home usa este identificador en ambos objetivos para sincronizar automáticamente el estado de acondicionamiento, las credenciales de la estructura y las listas de habitaciones con un contenedor UserDefaults compartido.

Uso compartido de Keychain (opcional)

Si la extensión de tu app necesita recuperar credenciales o tokens de acceso almacenados por la app principal con UserInfo.authorizationToken(), debes configurar un grupo de acceso de Keychain compartido para la app principal y los objetivos de extensión de la app en su plist de autorizaciones:

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

Propiedades de Info.plist

Incluye las siguientes claves de descripción en el Info.plist del objetivo principal de la app:

  • Descripción del uso de la ubicación:

    <key>NSLocationWhenInUseUsageDescription</key>
    <string>Your custom message explaining why location access is needed to read the current Wi-Fi SSID</string>
    
  • Servicios de Bonjour: En NSBonjourServices, incluye los servicios necesarios para el descubrimiento local de Matter y Thread:

    <key>NSBonjourServices</key>
    <array>
        <string>_matter._tcp</string>
        <string>_matterc._udp</string>
        <string>_matterd._udp</string>
        <string>_meshcop._udp</string>
    </array>
    
  • Descripción del uso de la red local: Incluye la clave NSLocalNetworkUsageDescription con un mensaje que explique los permisos de descubrimiento de la red local.

Acondiciona un dispositivo

Para acondicionar un dispositivo Matter, haz lo siguiente:

  1. Notifica al Home APIs iOS SDK para que se prepare para las solicitudes de Matter acondicionamiento con structure.prepareForMatterCommissioning(). Este comando hará lo siguiente:

    • Verifica que se haya otorgado el permiso.
    • Asegúrate de que el hub esté en línea y sea accesible.
    • Asegúrate de que no haya otra sesión de acondicionamiento activa en curso.
    do {
      try await structure.prepareForMatterCommissioning()
    } catch {
      // Failed to prepare for Matter Commissioning
      return
    }
    
  2. Crea una solicitud con MatterAddDeviceRequest() para iniciar el flujo de compatibilidad con Matter de Apple.

    let topology = MatterAddDeviceRequest.Topology(
      ecosystemName: "Google Home",
      homes: [MatterAddDeviceRequest.Home(displayName: structure.name)]
    )
    
    let request = MatterAddDeviceRequest(topology: topology)
    
  3. Realiza la solicitud con perform(). Si se produce un error, cancela la solicitud de acondicionamiento con 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. Crea un App Group ID en la Apple Developer Console para permitir que la app se comunique con la extensión MatterAddDevice cuando se acondiciona el dispositivo.

    También deberás actualizar el identificador del paquete de la aplicación y los perfiles de aprovisionamiento para usar este ID de grupo.

  5. Cuando inicialices, configura la instancia Home para usar el identificador de grupo.

    func application(_ application: UIApplication, didFinishLaunchingWithOptions
    launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
      Home.configure {
        $0.sharedAppGroup = "group.com.sample.app.commissioning"
      }
    
      return true
    }
    
  6. Implementa la extensión de la app Matter de Matter para iOS de Apple.

    El código de muestra muestra un ejemplo de implementación de una subclase de la API de Apple's MatterAddDeviceExtensionRequestHandler.

    Como mínimo, agrega el framework GoogleHomeMatterCommissionerSDK al objetivo de la extensión y anula tres métodos para llamar a las APIs Google Home platformHomeMatterCommissioner.

    • 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
        }
      }
    }