將新的 Matter 裝置新增至住家

iOS 適用的 Home API 會使用 Matter 中樞,將裝置委派至網狀架構。在委派期間,應用程式會將指令傳送至 SDK,然後傳送至中樞。

Xcode 專案設定

導入 Commissioning API 前,請務必先將必要功能、權利和 Info.plist 屬性新增至 Xcode 目標:

授權

在主要應用程式目標和擴充功能的 .entitlements 檔案中加入下列項目:

  • 管理 Thread 網路憑證:

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

    如要在發布的建構版本中使用這項授權,您必須向 Apple 提交授權要求表單。Apple 要求你證明自己是 Thread Group 的成員,並驗證你的 Thread 邊界路由器已通過 Thread Group 認證。

  • Wi-Fi 資訊:

    <key>com.apple.developer.networking.wifi-info</key>
    <true/>
    
  • 應用程式群組: 新增共用應用程式群組,允許主要應用程式和「新增裝置」擴充功能進行通訊 (例如 group.com.yourdomain.appgroupname)。 這個 ID 由開發人員在 Apple Developer Console 中建立及註冊,且必須與 Xcode 中目標功能的應用程式群組相符。MatterGoogle Home SDK 會在兩個目標中使用這個 ID,透過共用的 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 Developer Console 中建立 App Group ID,允許應用程式在委派裝置時與 MatterAddDevice 擴充功能通訊。

    您也需要更新應用程式軟體包 ID 和佈建設定檔,才能使用這個群組 ID。

  5. 初始化時,請將 Home 例項設為使用群組 ID。

    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 Framework 新增至擴充功能目標,並覆寫三種方法來呼叫 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
        }
      }
    }