本文由CocoaChina翻译组成员和浅夏@旧时光翻译自苹果开发文档:,敬请勘误。
第三部分:创建Home布局
第五部分:观察HomeKit数据库的变化
第六部分:访问服务和特性
用户发现兼容配件并配置它们。用户可以创建一些action来控制智能配件(例如恒温或者光线强弱),对其进行分组,并且可以通过Siri触发。HomeKit 对象被存储在用户iOS设备的数据库中,并且通过iCloud还可以同步到其他iOS设备。HomeKit支持远程访问智能配件,并支持多个用户设备和多个用户。HomeKit 还对用户的安全和隐私做了处理。
以下资源提供了更多关于创建HomeKit应用程序的信息:
提供了用户界面设计指南
提供了加快app审核的技巧
列出了系统提供的发现和配置无线智能家居产品UI
HomeKit应用服务只提供给通过App Store发布的app应用程序。在你的Xcode工程中, HomeKit应用程序需要额外的配置,你的app必须有开发证书和代码签名才能使用HomeKit。在Xcode的Capabilities面板使用HomeKit,可避免代码签名的问题。你无需直接在Xcode或者会员中心编辑授权文件(entitlements)。
为了完成本文档中所有步骤,你需要:
为了获得最佳体验,你的Mac电脑上最好安装最新的OS X 系统和最新的Xcode 版本。
在你开始使用HomeKit之前,请确保你已经完成以下任务。创建你团队的配置文件(Provisioning Profile),请参阅: .
当你成功地完成了之前的任务后,General面板中Team弹出菜单中的错误信息和问题修复按钮将会消失。代码签名配置被成功创建后会展示下方的General面板。
解决代码签名和证书配置问题,请参阅 文档中这一节。
想要使用HomeKit,首先要启用它。Xcode将会添加HomeKit权限到你的工程授权文件中和会员中心的App ID授权文件中,也会将HomeKit框架添加到你的工程中。HomeKit 需要一个明确的App ID, 这个App ID是为了你完成这些步奏而创建的。
启用HomeKit的步骤如下:
点击Capabilities查看你可以添加的应用服务列表。
滑到HomeKit 所在的行并打开关。
第三部分:创建Home布局
HomeKit 允许用户创建一个或者多个Home布局。每个Home()代表一个有网络设备的住所。用户拥有Home的数据并可通过自己的任何一台iOS设备进行访问。用户也可以和客户共享一个Home,但是客户的权限会有更多限制。被指定为primary home的home默认是Siri指令的对象,并且不能指定home。
每个Home一般有多个room,并且每个room一般会有多个智能配件。在home() 中,每个房间是独立的room,并具有一个有意义的名字,例如“卧室”或者“厨房”,这些名字可以在Siri 命令中使用。一个accessory()代表实际家庭中的自动化设备,例如车库开门器。一个sevice()是accessory提供的?种实际服务,例如打开或者关闭车库,或者车库上的灯。
如果你的app 缓存了home布局的信息,那么当其布局发声改变的时候,app就需要更新这些信息。使用对象可以从HomeKit数据库获取和其他相关的对象。本章描述的API获取对象后,你应该通过代理回调函数保持获取对象和HomeKit数据库同步,具体描述请参看“".
使用Home Manager—一个对象的访问home、room、配件、服务以及其他HomeKit对象。在创建家庭对象管理器(home manager)之后,直接设置它的代理,以便获取到这些对象之后及时的通知到你。
当你创建一个home manager对象时,HomeKit就开始从HomeKit数据库获取这些homes和相关对象,例如room和accessory对象。当HomeKit正在获取那些对象时,home manager 的属性是nil,并且属性是个空数组。你的app应该处理用户还没有完成创建home的情况,但是app应该等待直到HomeKit完成初始化。当获取对象完成之后,HomeKit
注意:当app进入前台或者在后台Home manager属性发生改变时,这个方法就会被调用,详情请参阅“”。
使用home manager的属性可以得到用户的所有home的集合;例如自家主要居所、度假别墅以及办公室。每个home都对应一个独立的home对象。
如果你要展示一个个accessory的相关信息或者允许用户控制它,可设置accessory的代理方法并实现这个代理方法,详情请见“”.
一旦你获取到一个accessory对象,你就可以访问它的服务和对象,详情请参阅“”。
使用类中的的方法,可以直接从Home对象中获取所有的accessory对象,而不用枚举home中的所有room对象(详情请见“”。
HomeKit对象被保存在一个可以共享的HomeKit数据库里,它可以通过HomeKit框架被多个应英程序访问。所有HomeKit调用的方法都是异步写入的,并且这些方法都包含一个完成处理后的参数。如果这个方法处理成功了,你的应用将会在完成处理函数里更新本地对象。应用程序启动时,HomeKit对象发生改变的并不能收到代理回调?法,只能接受处理完成后的回调函数。
想要观察其他应用程序启动时HomeKit对象的变化,请参阅:。查阅异步消息完成处理后传过来的错误码的信息,请参阅:.
HomeKit对象的名字,例如home、room和zone对象都可以被Siri识别,这一点已经在文档中指出。以下几点是HomeKit对象的命名规则:
对象名字在其命名空间内必须是唯一的。
属于用户所有的home名字都在一个命名空间内。
一个home对象及其所包含的对象在另一个命名空间内。
名字只能包含数字、字母、空格以及省略号字符。
名字必须以数字或者字母字符开始。
在名字比较的时候,空格或者省略号是忽略的(例如home1和home 1 同一个名字)。
想了用户可以使用哪些语言与Siri进行交互,请参阅文档中的"Siri Integration"
在类中使用异步方法可以添加一个home。作为参数传到那个方法中的home的名字,必须是唯一独特的,并且是Siri可以识别的home名字。
在else语句中,写入代码以更新你应的程序的视图。为了获取home manager对象,请参阅.
使用异步方法可以在一个home中添加一个room对象。作为参数传到那个方法中的room的名字,必须是唯一独特的,并且是Siri可识别的room名字。
在else语句中,写入代码更新应用程序的视图。
Accessories封装了物理配件的状态,因此它不能被用户创建。想要允许用户给家添加新的配件,我们可以使找到一个与home没有关联的配件。对象在后台搜寻配件,当它找到配件的时候,使用委托来通知你的应用程序。只有在方法调用之后或者方法调用之前,消息才被发送给代理对象。
1. 在你的类接口中添加配件浏览器委托协议,并且添加一个配件浏览器属性。代码如下:
2. 创建配件浏览器对象,并设置它的代理
4. 将找到的配件添加到你的收藏里
用你自己的代码实现上面的方法。 当然也可以实现 这个方法来移除配件,这个配件对你的视图或者收藏来说不再是新的。
如果一个视图控制器正在开始搜寻配件,那么可以通过重写方法来停止搜寻配件。代码如下:
注意: 在WiFi网络环境下,为了安全地获取新的并且能够被HomeKit发现的无线配件,请参阅.
配件归属于home,并且它可以被随意添加到home中的任意一个room中。使用这个异步方法可以在home中添加配件。这个配件的名字作为一个参数传递到上述异步方法中,并且这个名字在配件所属的home中必须是唯一的。使用 这个异步方法可以给home中
的room添加配件。配件默认的room是这个方法返回值room。下面的代码演示了如何给home和room添加配件:
配件可提供一项或者多项服务,这些服务的特性是由制造商定义。想了解配件的服务和特性目的,请参阅 .
使用 异步方法可以改变配件的名称,代码如下:
桥接口是配件中的一个特殊对象,它允许你和其他配件交流,但是不允许你直接和HomeKit交流。例如一个桥接口可以是控制多个灯的枢纽,它使用的是自己的通信协议,而不是HomeKit配件通信协议。想要给home添加多个桥接口 ,你可以按照中所描述的步骤,添加任何类型的配件到home中。当你给home添加一个桥接口时,在桥接口底层的配件也会被添加到home中。正如中所描述的那样,每次更改通知设计模,home的代理不会接收到桥接口的代理消息,而是接收一个有关于配件的代理消息。在home中,要把桥接口后的配件和任何类型的配件看成一样的--例如,把它们加入配件列表的配置表中。相反的是,当你给room增添一个桥接口时,这个桥接口底层的配件并不会自动地添加到room中,原因是桥接口和它的的配件可以位于到不同的room中。
分区 () 是任意可选的房间(rooms)分组;例如楼上、楼下或者卧室。房间可以被添加到一个或者多个区域。
可使用异步方法创建分区。所创建的作为参数传递到这个方法中分区的名称,在home中必须是唯一的,并且应该能被Siri识别。代码如下:
可使用异步方法给分区添加一个room,代码如下:
第五部分:观察HomeKit数据库的变化
每个Home都有一个HomeKit数据库。如下图所示,HomeKit数据库会安全地和home授权的用户的iOS设备以及潜在的客人的iOS设备进行同步。为了给用户展示当前最新的数据,你的应用需要观察HomeKit数据库的变化。
HomKit使用代理设计模式()来通知应用程序HomeKit对象的改变。一般来讲,如果你的应用程序调用了一个带有完成处理参数的HomeKit方法,并且这个方法被成功调用了,那么相关联的代理消息就会被发送给其他HomeKit应用,无论这些应用是安装在同一台iOS设备上还是远程iOS设备上。这些应用甚至可以运行在客人的iOS设备上。如果你的应用发起了数据改变,但是代理消息并没有发送到你的应用,那么添加代码到完成处理方法和相关联的代理方法中来刷新数据和更新视图就成为必须了。如果home布局发生了显著变化,那么就重新加载关于这个home的所有信息。在完成程序处理的情况下,请在更新应用之前检查那个方法是否成功。Homkit也会调用代理方法来通知你的应用程序home网络状态的改变。
例如,下图演示了使用代理方法的过程:响应用户的操作,你的应用程序调用了方法,并且没有错误发生,完成处理程序应当更新home的所有视图。如果成功了,homeKit将会发送消息给其他应用中homes的代理。因此,你实现的这个方法也应该更新home的所有视图。
应用程序只有在前台运行的时候才能接受代理消息。当你的应用在后台时,HomeKit数据库的改变并不会成批处理。也就是说,如果你的应用在后台,当其他的应用成功地添加一个room到home中的时候,你的应用程序并不会接收到消息。当你的应用程序到前台运行时,你的应用程序将会接收到消息,这个消息是表示你的应用程序要重新加载所有的数据。
观察Homes集合的改变
设置home manager的代理并且实现协议,当primary home或者home集合发生改变时,可以接收代理消息。
所有的应用都需要实现方法,这个方法在完成最初获取homes之后被调用。对新建的home manager来说,在这个方法被调用之前,属性的值是nil,数组是空的数组。当应用程序开始在前台运行时也会调用 方法,当其在后台运行时数据发生改变。该方法会重新加载与homes相关联的所有数据。
3. 实现homes发生改变时调用的代理方法。例如:如果多个视图控制器展示了homes相关信息,你可以发布一个更改通知去更新所有视图。
视图控制器注册更改通知并且执行适当的操作。
观察个别home的变化
展示home信息的视图控制器应该成为home对象的代理,并且当home发生改变时更新视图控制器的视图。
观察特定home对象的改变
1.在类接口中添加home代理协议。
例如:实现和方法来更新展示配件的视图。用类的属性可以获得配件所属的room。(对配件来说,默认的room是这个方法的返回值。)
Bridge Note:当你为home添加桥接口时,桥接口底层的配件会自动被添加到home中。你的代理会接收到桥接口后每个配件的 消息,但是你的代理不会接收到桥接口的消息。
配件的状态可以在任何时间发生变化。配件可能不能被获得,可以被移除,或者被关闭。请更新用户界面以反映配件状态的更改,尤其是如果你的app允许用户控制配件时。
这以下步骤中,我们假设你已经从HomeKit数据库中检索到了配件对象,正如中描述的那样。
在类接口中添加配件代理协议。
比如,执行方法以启用或者禁用配件控制。
如果你展示了配件的服务状态和特性,那么请执行以下代理方法来相应地更新其视图:
想了解配件的服务,请参阅.
第六部分:访问服务和特性
服务()代表了一个配件(accessory)的某个功能和一些具有可读写的特性()。一个配件可以拥有多项服务,一个服务也可以有很多特性。比如一个车库开门器可能拥有一个照明和开关的服务。照明服务可能拥有打开/关闭和调节亮度的特性。用户不能制造智能家电配件和它们的服务-配件制造商会制造配件和它们的服务-但是用户可以改变服务的特性。一些拥有可读写属性的特性代表着某种物理状态,比如,一个恒温器中的当前温度就是一个只可读的值,但是目标温度又是可读写的。苹果预先定义了一些服务和特性的名称,以便让Siri能够识别它们。
在依照中描述,你创建了一个配件对象之后,你可以获得配件的服务和特性。当然你也可以直接从home中按照类型获得不同的服务。
重要:不要暴露匿名服务-比如固件升级服务-给用户
通过类对象的属性,我们可以获得一个配件的服务。
要获得一个home当中配件提供的特定服务,使用类对象的方法。
使用类对象的属性来获得服务的名称
要获得一个服务的特性,请使用属性。
使用属性来获得服务的类型
苹果定义了一些服务类型,并能被Siri识别:
使用异步方法来改变服务名称。传入此方法的服务名称参数必须在一个home当中是唯一的,并且服务名可被Siri识别。
特性代表了一个服务的一个参数,它要么是只读、可读写或者只写。它提供了这个参数可能的值的信息,比如,一个布尔或者一个范围值。恒温器中的温度就是只读的,而目标温度又是可读写的。一个执行某个任务的命令且不要求任何返回-比如播放一段声音或者闪烁一下灯光来确认某个配件-可能就是只写的。
苹果定义了一些特性的类型,并能被Siri识别:
比如,对于一个车库开门器来说,目标状态就是打开或者关闭。对于一个锁来说,目标状态又是上锁和未上锁。
在你获得了一个对象之后,如 所描述的,你可以获得每个服务的特性的值。因为这些值是从配件中获得的,这些读写的方法都是异步的,并可以传入一个完成回调的block。
使异步方法来读取一个特性的值。
在if语句块中,加入你的代码以更新app的视图。
使用异步方法来向一个特性写入值。
不要以为函数调用完成就意味着写入成功,实际上只有在当完成回调执行并没有错误产生时才表示写入成功。比如,直到一个开关的特性改变之前都不要改变这个开关的状态。在if语句块中,加入你的代码,以更新app的视图。
另外,在别的app更新了特性的值时也需要更新视图,在中有描述。
一个服务组()提供了控制不同配件的任意数量服务的快捷方式-比如,当用户离开家之后控制家中的某些灯。
在你创建了一个对象之后,如中描述,你也就在这个家中创建一个服务组。
为了创建一个服务组,我们使用类对象的方法。方法中参数服务组的名称必须在此家中唯一,并可以被Siri识别。
我们使用类对象的方法来向服务组中添加一个服务。服务可以在一个或多个服务组中。
通过类对象的属性,来获得这个家的所有服务组。
通过类对象的属性,我们获得服务所对应的智能电器。
和配件类似,代理方法在别的app改变服务组时也会被调用。如果你的app使用了服务组,请阅读HMHomeDelegate Protocol Reference文档,获悉你应该实现哪些方法以观察这些变化。
如果你没有智能电器(智能配件),你可以使用HomeKit Accessroy Simulator来模拟home中的智能电器。每个模拟配件都拥有服务和特性,你可以从你的App当中控制它。你的App在HomeKit数据库中创建对象和关系。它可以创建home布局,可以添加新的配件到模拟的home环境当中,最后向home中的每个房间添加智能配件。然后,你的app就能控制这些在HomeKit
向网络中添加智能电器配件,请按照下面的步骤添加:
输入智能电器的名字和制造商。
如果想删除一个智能电器,请选择一个智能电器然后点击键盘上的Delete键。
向智能电器(配件)中添加服务
一个智能电器需要一项服务和特性,你可以从app控制它。从预定义了服务列表中选择一项服务,并自定义特性。
按照下面步骤向智能电器中添加服务
该配件的服务信息会展示在一个详情界面中。
注意:所有智能电器都有一个Accessory Information,显示在所有其他服务的下方。你可以向这个Accessory Information服务添加特性,但你不能删除默认的特性。
2. 点击添加服务(Add Service),并从弹出视图中选择一个服务类型。
新添加的服务会在右边详细显示。HomeKit Accessory Simulator为每种服务创建通用的特性。比如一个灯光服务的默认特性为色彩(Hue),饱和度(Saturation),亮度(Brightness)和开关。(开关特性和电源状态特性是一样的,正如中描述的那样。)一些特性是强制性的有一些也是可选择的。比如,开关特性就是强制性的,而色彩,饱和度,亮度这些特性都是可选择的。
你可以向服务中添加预定义的特性,或者自定义的特性。每种特性你都只能添加一个。
按照下面的步骤向服务中添加特性:
在特性类型菜单中,选择一个类型或者自定义类型。
在其他文本框中输入此特性的其他信息,并点击完成(Finish).新添加的特性会在详细视图展示出来。
点击特性右边的减号来删除一个特性。如果特性右边并没有减号显示,这说明这个特性对这个服务来说是必须的。比如,你可以删除电灯服务中的色彩(Hue),饱和度(Saturation)和亮度(Brightness),但是你不可以删除开关特性。
通过你的app向家庭中添加智能电器(配件)
在你通过HomeKit Accessory Simulator创建了一个智能电器后,运行你的App然后添加一个新的智能电器到你的家庭。
如何配对家庭中的智能电器:
关于如何编写代码来添加一个智能电器到家庭和房间请阅读。
在HomeKit Accessory Simulator中,你可以获得智能电器的服务,并在其他HomeKit App中设置服务的特性值来模拟控制这个智能电器,或者手动地模拟控制智能电器。
想要控制一个智能电器你需要:
操作一个特性的控件来改变它的值。
比如,为了改变一个灯泡的颜色(Hue),饱和度(Saturation)和亮度(Brightness),请滑动这个滑块。为了打开这个灯泡请选择On选项。
如果你的app展示了一个服务的特性,比如灯泡的开关状态,当你在HomeKit Accessory Simulator中改变这些特性的值时,它应当更新视图。
为了观察HomeKit数据库的变化,请阅读。如果你想从app中通过编写代码来控制一个智能电器,请阅读。
为了模拟那些不支持HomeKit Accessory Protocol协议的智能电器,需要添加一个虚拟桥接口,然后将智能电器添加到这个虚拟桥接口。配置虚拟桥接口底层的智能电器和配置其他类型的智能电器差不多。
添加一个虚拟桥接口到网络
添加一个代表这个虚拟桥接口的智能电器。
为了添加一个虚拟桥接口到网络你需要:
3. 输入一个智能电器的名称和制造商。
向虚拟桥接口添加智能电器配件
可向一个虚拟桥接口添加一个或多个智能电器。
为了向一个虚拟桥接口添加一个智能电器,需要:
输入一个智能电器名字和制造商。
想要了解虚拟桥接口中的智能电器的详细信息,请选择虚拟桥接口部分中的智能电器。如果需要的话你可以点击虚拟桥接口旁边的查看详情来查看这个虚拟桥接口的智能电器。在你添加了一个服务和特性到这些智能电器之后,如和中描述。它们会在这个虚拟桥接口被选择之后被展示出来。
在你的App中添加虚拟桥接口到home
将虚拟桥接口和home匹配的过程和将一个智能电器配置到一个home的过程是一样的,如描述的。在虚拟桥接口底层的智能电器配件也一样被加入到了home,如 所描述。
控制虚拟桥接口底层的智能电器
如何控制虚拟桥接口底层的智能电器和直接控制智能电器的步骤一致,如中描述,除了你直接选择虚拟桥接口下的智能电器之外。
在多设备和多用户环境中测试
在iOS模拟器中你不能测试分享HomeKit数据库到多个iOS设备和用户。你应该安装你的App到多台iOS设备上,在这些设备中输入iCloud证书,然后运行你的App。或者,使用ad hoc授权来在多台注册设备中测试你的app,如描述。
为了测试单用户多设备环境,你应该使用同一个iCloud账户在多台设备登陆。
为了测试多用户使用同一家庭的智能电器,你应该在多台设备使用不同的iCloud账户登陆。
你的App应该应该可以允许一个用户邀请客人到你的家中,如所述。
一个动作集合和触发器允许你同时控制多个智能电器。比如,一个动作集合可能会在用户上床休息之前执行一组动作。一个写动作向一个特性写入了值。动作集合中的动作是以不确定的顺序执行的。一个触发器会在一个特定的时间出发一个动作集并可以重复执行。每一个动作集合在一个家庭中都有唯一的名称并可被Siri识别。
写入动作会向一个服务的特性写入值并被加入到动作集合中去。类是具体类的抽象基类。一个动作有一个相关联的特性对象,你可以通过Accessing Services and Characteristics中描述的来获取相关的服务和特性,然后创建这个。
为了创建一个动作,我们使用类中的方法。
在你的代码中,你使用对应的特性的期望来替换value参数,并使用对应的对象来替换characteristic参数。
一个动作集就是一个共同执行的动作的集合。比如一个夜间动作集合可能包含关闭电灯,调低恒温水平和锁上房门。
为了创建一个动作集我们使用异步方法。
// 成功添加了一个动作集
// 添加一个动作集失败
为了添加一个动作到动作集,我们使用异步方法。
// 成功添加了一个动作到动作集
// 添加一个动作到动作集失败
想要移除一个动作,可使用方法。
想要执行一个动作集,可使用类的方法。比如,用户希望控制所有的节日彩灯。我们就创建一个动作集来打开所有的节日彩灯,另外一个动作集来关闭所有的节日彩灯。为了打开所有的节日彩灯,发送executeActionSet:completionHandler:消息给home对象,并传递"打开节日彩灯"动作集。
触发器会执行一个或多个动作集。iOS会在后台管理和运行你的触发器。类是具体类的抽象类。当你创建一个定时触发器时,你需要指定触发时间和触发的周期。创建并开启一个定时触发器需要多个步骤来完成。
遵循下面几步来创建并启动一个定时触发器
触发时间必须设置在将来的某个时刻,第二个参数必须为0.如果你设置了一个周期,周期的最小值是5分钟,最大值是5周。关于如何使用和来设置周期,请阅读
2. 添加一个动作集到触发器。
使用基类方法,来添加一个动作集到触发器。
3. 添加一个触发器到家庭。
使用HMHome类中的方法来添加一个触发器到家庭。
新创建的触发器默认是未启动的。需要使用方法启动触发器。
一个定时触发器被启动后,会周期性的运行它的动作集。
创建home的用户是该home的管理员,可以执行所有操作,包括添加一个客人用户到home。任何管理员添加到这个home的用户(HMUser)都有一个有限的权限。客人不能更改家庭的布局,但是可以执行下面的动作:
比如,一个家庭的户主可以创建一个home布局并向其中添加家庭成员。每个家庭成员必须拥有一个iOS设备和Apple ID以及相关的iCloud账户。iCloud需要个人输入的Apple ID和户主提供的Apple ID相吻合,以便让他们访问这个home。考虑到隐私问题,Apple ID对你的App是不可见的。
管理员需要遵从以下步骤来添加一个客人到home中:
1. 管理员调用一个动作将客人添加到home中。
2. 你的App调用异步方法。
5. 在完成回调中返回一个新的用户。
6. 你的App展示客人的名字。
添加一个客人到home,需要在客人的iOS设备上做以下操作:
2. 用户启动你的App。
4. 如果iCloud的凭证和管理员输入的Apple ID相同,那么管理员的home将会出现在homes属性中。
客人执行的操作可能会失败。如果一个异步方法中出现错误码的话,这就意味着用户没有足够的权限来执行动作-也许这个用户只是客人,而不是管理员。
为了测试你的App是否正确处理了客人用户,请阅读。
为了添加一个客人用户到home,请使用异步方法。
想要移除home中的用户,请使用类的方法。
通过实现协议中的和协议方法检查新添加和移除的用户并更新视图。关于如何创建一个delegate,请阅读。
出于隐私的考虑,你的app对用户名只有读得权限,并不能读写用户的Apple ID。使用对象的属性来获取用户。使用类的属性来获取用户名。