如何获取 HomeKit 值以在 iOS 14 小组件中使用?

the*_*max 7 entitlements homekit widgetkit swiftui ios14

我正在编写一个 HomeKit 应用程序,它可以成功显示应用程序内支持的配件的实时数据。我可以读取单个值 ( HMCharacteristic.readValue) 或使用通知来保持更新 ( HMCharacteristic.enableNotification)。

现在我想实现在用户主屏幕上显示这些数据的小部件。这包括四个步骤:

  1. 动态意图从 中获取所有已注册(和支持)的附件,HMHomeManager并使用户能够选择其中一个以显示在小部件上。
  2. IntentTimelineProvidergetTimeline函数内部,我可以再次使用HMHomeManager来检索我想要在小部件上显示的附件(基于存储在 的参数 - 意图中的附件的 UUID getTimelineconfiguration
  3. 仍在该getTimeline功能内,我可以选择显示附件小部件所需的服务和特征HMHomeManager

到目前为止,一切正常。

  1. 但是,当我尝试从使用之前选择的特征中读取值时HMCharacteristic.readValue,回调包含一个错误,说明

错误域=HMErrorDomain 代码=80“缺少 API 权利。”

Widget 的 Info.plist 包含“隐私 - HomeKit 使用说明”字段,并且 Target 具有 HomeKit 功能。

经过一番研究,我得出了以下理论:显然整个 WidgetKit API 在后台运行我的代码。而且 HomeKit 似乎不允许从后台上下文进行访问。好吧,它确实允许访问 Homes/Services/Characteristics,但它不允许读取或写入 Characteristics(我想确保应用程序开发人员使用 HomeKit 自动化,并且不要尝试实现由某些后台进程控制的自定义自动化他们的应用程序在 iPhone 上运行)。

我的(简化的)getTimeline代码:

func getTimeline(for configuration: SelectAccessoryIntent, in context: Context, completion: @escaping (Timeline<Entry>) -> ()) {
        // id stores the uuid of the accessory that was chosen by the user using the dynamic Intent
        if let id = configuration.accessory?.identifier {
            // Step 2.: fetch the accessory
            // hm is a HMHomeManager
            let hm = HomeStore.shared.homeManager
            // take a short nap until the connection to the local HomeKit instance is established (otherwise hm.homes will create an empty array on first call)
            sleep(1)
            
            let accessories = hm.homes.flatMap({ h in h.accessories })
            
            if let a = accessories.filter({ a in a.uniqueIdentifier.uuidString == id }).first {
                // a holds our HMAccessory
                
                // Step 3.: select the characteristic I want
                // obviously the real code chooses a specific characteristic
                let s: HMService = a.services.first!
                let c: HMCharacteristic = s.characteristics.first!
                
                // Step 4.: read the characteristic's value
                c.readValue(completionHandler: {err in
                    if let error = err {
                        print(error)
                    } else {
                        print(c.value ?? "nil")
                    }
                    
                    // complete with timeline
                    completion(Timeline(entries: [RenderAccessoryEntry(date: Date(), configuration: configuration, value: c.value)], policy: .atEnd))
                })
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

我的问题:

第一:我的理论正确吗?

如果是这样:我能做什么?是否有任何权利允许我在后台或类似情况下访问 HomeKit?我需要readValue在其他地方执行呼叫吗?或者在当前版本的 HomeKit/WidgetKit/iOS 中使用 HomeKit API 和 WidgetKit 是不可能的吗?我能做的最好的事情就是希望他们在将来的某个时候引入此功能?

如果不是:我错过了什么?