iOS HomeKit詳解

前言

HomeKit開發(fā)準(zhǔn)備工作

  • HomeKit應(yīng)用服務(wù)只提供給通過AppStore發(fā)布的app應(yīng)用程序。在Xcode工程中,HomeKit需要額外的配置,你的app必須有開發(fā)者證書和代碼簽名才能使用HomeKit,不過可以在Xcode的Capablities面板使用HomeKit,可避免代碼簽名的問題。

  • Xocde 項(xiàng)目的plist文件要配置 Privacy - HomeKit Usage Description 這個(gè)key,否則會(huì)奔潰,老鐵,你懂得~~

  • Xcode將會(huì)添加HomeKit權(quán)限到你的工程授權(quán)文件中和會(huì)員中心的App ID授權(quán)文件中,也會(huì)將HomeKit框架添加到你的工程中。HomeKit 需要一個(gè)明確的App ID, 這個(gè)App ID是為了你完成這些步奏而創(chuàng)建的。
    創(chuàng)建具有HomeKit功能的證書,如下圖


    image.png

在創(chuàng)建Xcode項(xiàng)目的時(shí)候需要勾選好Team,否則會(huì)出錯(cuò)

image.png

啟動(dòng)HomeKitde 步驟如下:

  • 在Xcode中,選擇View > Navigators > Show Project Navigator。
  • 從Project/Targets彈出菜單中target(或者從Project/Targets的側(cè)邊欄)
  • 點(diǎn)擊Capabilities查看你可以添加的應(yīng)用服務(wù)列表。
  • 滑到HomeKit 所在的行并打開關(guān)。

下載HomeKit Accessory Simulator

無(wú)需為了開發(fā)Homekit 應(yīng)用程序而購(gòu)買硬件產(chǎn)品。你可以使HomeKit Accessory Simulator來測(cè)試HomeKit app和模擬配件設(shè)備之間的通信。HomeKit Accessory Simulator不是和Xcode一起發(fā)布的。

下載HomeKit Accessory Simulator步驟如下:

  • 在Capabilities面板的HomeKit分區(qū),點(diǎn)擊Download HomeKit Accessory Simulator按鈕。(或者選擇Xcode > Open Developer Tool > More Developer Tools)
  • 在瀏覽器中搜索并且下載"Hardware IO Tools for Xcode ".dmg文件。
  • 在 Finder中雙擊~/Downloads中的.dmg文件。
  • 把HomeKit Accessory Simulator拖拽到/Application文件中。


    image.png

之后,你可以使用使用HomeKit Accessory Simulator測(cè)試你的HomeKit應(yīng)用程序。可參考 yourHomeKit App

HomeKit布局

HomeKit允許用戶創(chuàng)建一個(gè)或者多個(gè)Home布局。每個(gè)Home代表一個(gè)有網(wǎng)絡(luò)涉筆的住所。用戶擁有Home的數(shù)據(jù)并可通過自己的任何一條iOS設(shè)備進(jìn)行訪問。用戶也可以和客戶共享一個(gè)Home,但客戶的權(quán)限會(huì)有更多限制。被置頂為Primary home的home默認(rèn)是Siri指令的對(duì)象,并且不能指定home。

每個(gè)Home一般有多個(gè)room,并且每個(gè)room一般會(huì)有多個(gè)智能配件。在home中,每個(gè)房間是獨(dú)立的room,并且具有一個(gè)有意義的名字,例如“臥室”或者“廚房”,這些名字可以在Siri命令中使用。一個(gè)accessory(HMAccessory)代表實(shí)際家庭中的自動(dòng)化設(shè)備,例如車庫(kù)開門器。每個(gè)sevice中也會(huì)有多個(gè)特征(characteristic), 一個(gè)sevice(HMService)是accessory提供的一種實(shí)際服務(wù),例如打開或者關(guān)閉車庫(kù),或者車庫(kù)上的燈


image.png

如果你的app緩存了home布局的信息,那么當(dāng)其布局發(fā)聲改變的時(shí)候,app就需要更新這些信息。使用HMHomeManager對(duì)象可以從HomeKit數(shù)據(jù)庫(kù)獲取HMHome和其他相關(guān)的對(duì)象。獲取對(duì)象后,最應(yīng)該做的就是通過代理回調(diào)函數(shù)保持獲取對(duì)象和HomeKit數(shù)據(jù)庫(kù)同步,可參考Observing HomeKit Database Changes

創(chuàng)建Home Manager對(duì)象

使用Home Manager一個(gè)HMHomeMagager對(duì)象的訪問home,room,配件,服務(wù)以及其他HomeKit對(duì)象。在創(chuàng)建家庭對(duì)象管理器(home manager) 之后,直接設(shè)置它的代理,以便獲取到這些對(duì)象之后及時(shí)的通知你。

self.homeManager = [[HMHomeManager alloc] init];

self.homeManager.delegate = self;

當(dāng)你創(chuàng)建一個(gè)home manager對(duì)象時(shí),HomeKit就開始從HomeKit數(shù)據(jù)庫(kù)獲取這些homes和相關(guān)對(duì)象,例如room和accessory對(duì)象。當(dāng)HomeKit正在獲取哪些對(duì)象時(shí),home manager 的primaryHome屬性時(shí)nil,并且homes屬性是個(gè)空數(shù)組。你的app應(yīng)該處理用戶還沒有完成創(chuàng)建home的其概況,但是app應(yīng)該等待知道HomeKit完成初始化。當(dāng)獲取對(duì)象完成之后,HomeKit會(huì)發(fā)送homeManagerDidUpdateHomes:消息給home manager的代理。
ps:當(dāng)app進(jìn)入前臺(tái)或者在后臺(tái)Home manager屬性發(fā)生改變時(shí),這個(gè)homeManagerDidUpdateHomes: 方法就會(huì)調(diào)用,可參考Observing Changes to the Collection of Homes

獲取Primary Home 和Homes集合

homeKit允許用戶有多個(gè)home,每一個(gè)home代表一個(gè)有智能設(shè)備的住所。用戶擁有Home的數(shù)據(jù)并可通過自己的任何一臺(tái)iOS設(shè)備進(jìn)行訪問。用戶也可以和客戶共享一個(gè)Home,但是客戶的權(quán)限會(huì)有更多限制。在用戶的所有home中,會(huì)有一個(gè)常用的home,即為primary home。被指定為primary home的home默認(rèn)是Siri指令的對(duì)象,并且不能指定home,就是說primary home是只讀的不能去設(shè)定。

我們可以通過創(chuàng)建一個(gè)HMHomeManager對(duì)象去管理home。使用這個(gè)HMHomeManager對(duì)象的訪問home、room、配件、服務(wù)以及其他HomeKit對(duì)象

通過home manager的primaryHome屬性,可以得到peimary home,代碼如下:

HMHome *home = self.homeManager.primaryHome;

使用home manager的homes屬性可以得到用戶的所有home集合,例如自家主要居所,度假別墅以及辦公室。每個(gè)home都對(duì)應(yīng)一個(gè)獨(dú)立的home對(duì)象


HMHome *home;

 for(home in self.homeManager.homes ){

 …}
 
獲取 Home中的所有room

在一個(gè)home中,rooms屬性定義accessories的物理位置。用home的rooms屬性可以枚舉home中的room

HMHome *home = self.homeManager.primaryHome;

 HMRome *room;

 for(room in home.rooms){

 …

 }
 

*** Accessories ***
*** Accessories 數(shù)組屬于home,但是被指定給了home中不同的room。假如用戶沒有給一個(gè)accessory指定room,那么這個(gè)accessories被指定一個(gè)默認(rèn)的room ,這個(gè)room是roomForEntireHome方法的返回值。用room的accessories屬性可以枚舉room中所有的accessory ***

*** 比如說我的home中有一個(gè)智能燈泡,一個(gè)智能冰箱,一個(gè)智能熱水器,一個(gè)智能電視。我把燈泡指定給了臥室這個(gè)room,冰箱指定給了廚房這個(gè)room,熱水器指定給了衛(wèi)生間room。電視沒有指定room,那么就默認(rèn)給它指定了一個(gè)room,這個(gè)room就是 HMRoom *defultRoom = [home roomForEntireHome]。當(dāng)我需要獲取到我的智能硬件對(duì)象的時(shí)候,我通過home.accessories獲取到的是我家的所有智能硬件,也就是燈泡,冰箱和洗衣機(jī)以及電視。如果room是臥室,我通過room.accessories獲得到的就是燈泡(我這里就舉一個(gè)例子,臥室也可以有多個(gè)硬件),如果room是廚房,我通過room.accessories獲得到的就是冰箱 ***

示例代碼:

HMAccessory *accessory;

for(accessory in room.accessories)

{ 
 //獲取到room中的所有 accessory對(duì)象
 
}

HMAccessory *accessory;

for(accessory in hoom.accessories)

{
  //獲取到hoom中的所有accessory對(duì)象
  
 }


一旦我們獲取到accessory對(duì)象,我們就可以展示一個(gè)個(gè)accessory的相關(guān)信息或者訪問它的服務(wù)和對(duì)象這樣就可以允許用戶控制它,可設(shè)置accessory的代理方法并實(shí)現(xiàn)這個(gè)代理方法

獲取room中的Accessories

Accessories 數(shù)組屬于home,但是被指定給了home中的room。假如用戶沒有給一個(gè)accessory指定room,那么這個(gè)accessories被指定一個(gè)默認(rèn)的room,這個(gè)room是roomForEntireHome方法的返回值。用room的accessores屬性可以枚舉room中所有的accessory

HMAccessory *accessory;

 for(accessory in room.accessories){

 …

 }

如果你要展示一個(gè)個(gè)accessory的相關(guān)信息或者允許用戶控制它,可設(shè)置accessory的代理方法并實(shí)現(xiàn)這個(gè)代理方法, 如果一旦獲取到一個(gè)accessory對(duì)象,你就可以訪問它的服務(wù)的對(duì)象
具體內(nèi)容可參考
Observing Changes to Accessories
Accessing Services and Characteristics

獲取Home 中的Accessories屬性

使用HMHome類中的accessories的方法,可以直接從Home對(duì)象中獲取所有的accessory對(duì)象,而不用枚舉home中的所有room對(duì)象,詳情見Getting the Accessories in a Room

創(chuàng)建Homes和添加Accessories

--
我們所添加或者移除的這些homeKit對(duì)象都是會(huì)保存在一個(gè)共享的homeKit數(shù)據(jù)庫(kù)中的。我們?cè)谧约簩懙膆omeKitAPP中添加和移除的home,room等homekit對(duì)象,在系統(tǒng)自帶的家庭APP中的數(shù)據(jù)都是同步的。

HomeKit對(duì)象被保存在一個(gè)可以共享的HomeKit數(shù)據(jù)庫(kù)里,它可以通過HomeKit框架被多個(gè)應(yīng)用程序訪問,所以HomeKit調(diào)用的方法都是異步寫入的,并且這些方法都包含一個(gè)完成處理后的參數(shù)。如果這個(gè)方法處理成功了,你的應(yīng)用將會(huì)在完成處理函數(shù)里更新本地對(duì)象。應(yīng)用程序啟動(dòng)時(shí),HomeKit對(duì)象發(fā)生改變的并不能收到代理回調(diào),只能接受處理完成后的回調(diào)函數(shù)。

想要觀察其他應(yīng)用程序啟動(dòng)的HomeKit對(duì)象的變化請(qǐng)參閱:Observing HomeKit Database Changes。查閱異步消息完成處理后傳過來的錯(cuò)誤碼的信息,請(qǐng)參閱:HomeKit Constants Reference.

對(duì)象命名規(guī)則

HomeKit對(duì)象的名字,例如home,room和zone對(duì)象都可以被Siri識(shí)別,這一點(diǎn)已經(jīng)在文檔中指出。
以下幾點(diǎn)是HomeKit對(duì)象的命名規(guī)則:

  • 對(duì)象名字在其命名空間內(nèi)必須是唯一的。
  • 屬于用戶所有的home名字都在一個(gè)命名空間內(nèi)。
  • 一個(gè)home對(duì)象及其所包含的對(duì)象在另一個(gè)命名空間內(nèi)。
  • 名字只能包含數(shù)字、字母、空格以及省略號(hào)字符。
  • 名字必須以數(shù)字或者字母字符開始。
  • 在名字比較的時(shí)候,空格或者省略號(hào)是忽略的(例如home1和home 1 同一個(gè)名字)。
  • 名字沒有大小寫之分。
    關(guān)于那些語(yǔ)言可以與Siri進(jìn)行交互,請(qǐng)參閱HomeKit User Interface Guidelines文檔中的"Siri Integration"

創(chuàng)建Homes
在HMHomeManager類中使用addHomeWithName:completionHandler: 異步方法可以添加一個(gè)home。作為參數(shù)傳到那個(gè)方法中的home的名字,必須是唯一獨(dú)特的,并且是Siri 可以識(shí)別的home名字。


[self.homeManager addHomeWithName:@"My Home"

completionHandler:^(HMHome *home, NSError *error) {

if (error != nil) {

// Failed to add a home

} else {

// Successfully added a home

} }];

在else語(yǔ)句中,寫入代碼以更新應(yīng)用程序的視圖。為了獲取home manager對(duì)象,請(qǐng)參閱 Getting the Home Manager Object.

在Home中添加一個(gè)Room

--
每個(gè)Home一般有多個(gè)room,并且每個(gè)room一般會(huì)有多個(gè)智能配件。在home中,每個(gè)房間是獨(dú)立的room
使用addRoomWithName:completionHandler: 異步方法可以在一個(gè)home中添加一個(gè)room對(duì)象。作為參數(shù)傳到那個(gè)方法中的room的名字,必須是唯一獨(dú)特的,并且是Siri可識(shí)別的room的名字。

NSString *roomName = @"Living Room";

[home addRoomWithName:roomName completionHandler:^(HMRoom

*room, NSError *error) {

if (error != nil) {

// Failed to add a room to a home

} else {

// Successfully added a room to a home

} }];

在else語(yǔ)句中,寫入代碼更新應(yīng)用程序的視圖。

發(fā)現(xiàn)配件

Accessories封裝了物理配件的狀態(tài),因此它不能被用戶創(chuàng)建。想要允許用戶給家添加新的配件,我們可以使HMAccessoryBrowser對(duì)象找到一個(gè)與home沒有關(guān)聯(lián)的配件。HMAccessoryBrower對(duì)象在后臺(tái)搜尋配件,當(dāng)它找到配件的時(shí)候,使用委托來通知你的應(yīng)用程序。只有在startSearchingForNewAccessories方法調(diào)用之后或者stopSearchingForNewAccessories方法調(diào)用之前,HMAccessoryBrowserDelegate消息才被發(fā)送給代理對(duì)象。

發(fā)現(xiàn)home中的配件

一個(gè)accessory代表一個(gè)家庭中的自動(dòng)化設(shè)備,例如一個(gè)智能插座,一個(gè)智能燈具等

  • 在類接口中天啊及配件瀏覽器委托協(xié)議,并且添加一個(gè)配件瀏覽器屬性。代碼如下:
@interface EditHomeViewController ()

@property HMAccessoryBrowser *accessoryBrowser;

@end

用自己的類名代替EditHomeViewController

  • 創(chuàng)建配件瀏覽器對(duì)象,并設(shè)置它的代理
self.accessoryBrowser = [[HMAccessoryBrowser alloc] init];

self.accessoryBrowser.delegate = self;

  • 開始搜尋配件
[self.accessoryBrowser startSearchingForNewAccessories];

  • 將找到的配件添加到你的收藏里

- (void)accessoryBrowser:(HMAccessoryBrowser *)browser

didFindNewAccessory:(HMAccessory *)accessory {

// Update the UI per the new accessory; for example,

reload a picker

view.

[self.accessoryPicker reloadAllComponents];

}

用你自己的代碼實(shí)現(xiàn)上面的accessoryBrowser:didFindNewAccessory:方法。 當(dāng)然也可以實(shí)現(xiàn)accessoryBrowser:didRemoveNewAccessory: 這個(gè)方法來移除配件,這個(gè)配件對(duì)你的視圖或者收藏來說不再是新的。

  • 停止搜尋配件
    如果一個(gè)視圖控制器正在開始搜尋配件,那么可以重寫viewWillDisappear:方法來停止搜尋配件
- (void)viewWillDisappear:(BOOL)animated {

[self.accessoryBrowser stopSearchingForNewAccessories];

}

在WIFI網(wǎng)絡(luò)環(huán)境下,為了安全的獲取新的并且能夠被HomeKit發(fā)現(xiàn)的無(wú)線配件,可參閱External Accessory Framework Reference

為home和room添加配件(Accessory)

配件歸屬于home,并且它可以被隨意添加到home中的任意一個(gè)room中。使用addAccessory:completionHandler:這個(gè)異步方法可以在home中添加配件。這個(gè)配件的名字作為一個(gè)參數(shù)傳遞到上述異步方法中,并且這個(gè)名字在配件所屬的home中必須是唯一的。使用assignAccessory:toRoom:completionHandler: 這個(gè)異步方法可以給home中的room添加配件。配件默認(rèn)的room是roomForEntireHome這個(gè)方法返回值room,下面的代碼演示了如何給home和room添加配件

// Add an accesory to a home and a room

// 1. Get the home and room objects for the completion

handlers.

__block HMHome *home = self.home;

__block HMRoom *room = roomInHome;

// 2. Add the accessory to the home

[home addAccessory:accessory completionHandler:^(NSError

*error) {

if (error) {

// Failed to add accessory to home

} else {

if (accessory.room != room) {

// 3. If successfully, add the accessory to

the room

[home assignAccessory:accessory toRoom:room

completionHandler:^(NSError *error) {

if (error) {

// Failed to add accessory to room

} }];

} }

}];

配件可提供一項(xiàng)或者多項(xiàng)服務(wù),這些服務(wù)的特性是由制造商定義.配件的服務(wù)和特性,可參閱Accessing Services and Characteristics.

更改配件名稱

使用updateName:completionHandler: 異步方法可以改變配件的名稱,代碼如下:

[accessory updateName:@"Kid's Night Light"

completionHandler:^(NSError *error) {

if (error) {

// Failed to change the name

} else {

// Successfully changed the name

}

}];

為Homes和Room添加Bridge (橋接口)

橋接口是配件中的一個(gè)特殊對(duì)象,它允許你和其他配件交流,但是不允許你直接和HomeKit交流,例如一個(gè)橋接口可以是控制多個(gè)燈的樞紐,它使用的是自己的通信協(xié)議,而不是HomeKit配件通信協(xié)議。想要給home添加多個(gè)橋接口,你可以安裝Adding Accessories to Homes and Rooms 中描述的步驟,添加任何類型的配件到home中。當(dāng)你給home添加一個(gè)橋接口時(shí),在橋接口底層的配件也會(huì)被添加到home中。正如Observing HomeKit Database Changes 中所描述的那樣,每次更改通知設(shè)計(jì)模型,home的代理不會(huì)接受到橋接口的home:didAddAccessory:代理消息,而是接收一個(gè)有關(guān)于配件的home:didAddAccessory:代理消息。在home中,要把橋接口后的配件和任何類型的配件看成一樣的,例如:把他們加入配件列表的配置表中,相反的是,當(dāng)你給room增添一個(gè)橋接口時(shí),這個(gè)橋接口底層的配件并不會(huì)自動(dòng)添加到room中,原因是橋接口和它的配件可以位于不同的room中。

創(chuàng)建分區(qū)
分區(qū)(HMZone)是任意可選的房間rooms分組,例如樓上,樓下,或者臥室。房間可以被天機(jī)到一個(gè)或者多個(gè)區(qū)域

image.png

可使用addZoneWithName:completionHandler: 異步方法創(chuàng)建分區(qū)。所創(chuàng)建的行為參數(shù)傳遞到這個(gè)方法中分區(qū)的名稱,在home中必須是唯一的,并且應(yīng)該能被Siri識(shí)別。代碼如下:

__block HMHome *home = self.home;

NSString *zoneName = @"Upstairs";

[home addZoneWithName:zoneName completionHandler:^(HMZone

*zone, NSError *error)

{

if (error) {

// Failed to create zone

} else {

// Successfully created zone, now add the rooms

}

}];

可使用addRoom:completionHandler:異步方法給分區(qū)添加一個(gè)room,代碼如下:


__block HMRoom *room = roomInHome;

[zone addRoom:room completionHandler:^(NSError *error) {

if (error) {

// Failed to add room to zone

} else {

// Successfully added room to zone

} }];

觀察HomeKit數(shù)據(jù)庫(kù)的變化

每個(gè)Home都有一個(gè)HomeKit數(shù)據(jù)庫(kù)。如圖,HomeKit數(shù)據(jù)庫(kù)會(huì)安全地和home授權(quán)的用戶的iOS設(shè)備以及潛在的客人的iOS設(shè)備進(jìn)行同步。為了給用戶展示當(dāng)前最新的數(shù)據(jù),你的應(yīng)用需要觀察HomeKit數(shù)據(jù)庫(kù)的變化。


image.png
HomeKit代理方法

HomeKit使用代理設(shè)計(jì)模式(delegate design pattern)來通知應(yīng)用程序HomeKit對(duì)象的改變。一般來講,如果你的應(yīng)用程序調(diào)用了一個(gè)帶有完成處理參數(shù)的HomeKit方法,并且這個(gè)方法被成功調(diào)用了,那么相關(guān)聯(lián)的代理消息就會(huì)被發(fā)送給其他HomeKit應(yīng)用,無(wú)論這些應(yīng)用時(shí)安裝在同一臺(tái)iOS設(shè)備上還是遠(yuǎn)程iOS設(shè)備上。這些應(yīng)用甚至可以運(yùn)行在客人的iOS設(shè)備上。如果你的應(yīng)用發(fā)起了數(shù)據(jù)改變,但是代理消息并沒有發(fā)送到你的應(yīng)用,那么添加代碼到完成代理方法和相關(guān)聯(lián)的代理方法中來刷新數(shù)據(jù)和更新視圖就成為必須了。如果home布局發(fā)生了顯著變化,那么就重新加載關(guān)于這個(gè)home的所有信息。在完成程序處理的情況下,請(qǐng)?jiān)诟聭?yīng)用之前檢查那個(gè)方法是否成功。HomeKit也會(huì)調(diào)用代理方法來通知你的應(yīng)用程序home網(wǎng)絡(luò)狀態(tài)的改變。

下圖演示了 使用代理方法的過程:響應(yīng)用戶的操作,你的應(yīng)用程序調(diào)用了addRoomWithName:completionHandler:方法,并沒有錯(cuò)誤發(fā)生,完成處理程序應(yīng)當(dāng)更新home的所有視圖。如果成功了,homekit將會(huì)發(fā)送home:didAddRoom:消息給其他應(yīng)用中homes的代理。因此,你實(shí)現(xiàn)的這個(gè)home:didAddRoom:方法也應(yīng)該更新home的所有視圖

image.png

應(yīng)用程序只有在前臺(tái)運(yùn)行的時(shí)候才能接受代理消息。當(dāng)你的應(yīng)用在后臺(tái)時(shí),homeKit數(shù)據(jù)庫(kù)的改變并不會(huì)成批處理。也就是說,如果你的應(yīng)用在后臺(tái),當(dāng)其他的應(yīng)用成果地添加一個(gè)room到home中的時(shí)候,你的應(yīng)用程序并不會(huì)接受到home:didAddRoom: 消息。當(dāng)你的應(yīng)用程序到前臺(tái)運(yùn)行時(shí),你的應(yīng)用程序?qū)?huì)接受到homeManagerDidUpdateHomes:消息,這個(gè)消息是表示你的應(yīng)用程序要重新加載所有的數(shù)據(jù)。

觀察Homes集合的改變

設(shè)置home manager的代理并且實(shí)現(xiàn)HMHomeManagerDelegate協(xié)議,當(dāng)primary home或者h(yuǎn)ome集合發(fā)生改變時(shí),可以接受代理消息。

所有的應(yīng)用都需要實(shí)現(xiàn)homeManagerDidUpdateHomes:方法,這個(gè)方法在完成最初獲勝homes之后被調(diào)用。對(duì)新建的home manager來說,在這個(gè)方法被調(diào)用之前,primaryHome屬性的值是nil,homes數(shù)組是空的數(shù)組。當(dāng)應(yīng)用程序開始在前臺(tái)運(yùn)行時(shí)也會(huì)調(diào)用homeManagerDidUpdateHomes: 方法,當(dāng)其在后臺(tái)運(yùn)行時(shí)數(shù)據(jù)發(fā)生改變,改homeManagerDidUpdateHomes:方法會(huì)重新加載與homes相關(guān)聯(lián)的所有數(shù)據(jù)。

觀察homes的變化
  • 在類的接口中添加HMHomeManagerDelegate代理和homeManager屬性。代碼如下:
@interface AppDelegate () @property (strong, nonatomic) HMHomeManager *homeManager;

@end
  • 創(chuàng)建home manager對(duì)象并設(shè)置其代理
- (BOOL)application:(UIApplication *)application

didFinishLaunchingWithOptions:(NSDictionary *)launchOptions

{

self.homeManager = [[HMHomeManager alloc] init];

self.homeManager.delegate = self;

return YES;

}

  • 實(shí)現(xiàn)hoems發(fā)生改變時(shí)調(diào)用的代理方法。例如:如果多個(gè)視圖控制器展示了hoems相關(guān)信息,你可以發(fā)布一個(gè)更改通知去更新所有視圖
- (void)homeManagerDidUpdateHomes:(HMHomeManager *)manager {

// Send a notification to the other objects

[[NSNotificationCenter defaultCenter]

postNotificationName:@"UpdateHomesNotification"

object:self];

}

- (void)homeManagerDidUpdatePrimaryHome:(HMHomeManager

*)manager {

// Send a notification to the other objects

[[NSNotificationCenter defaultCenter]

postNotificationName:@"UpdatePrimaryHomeNotification"

object:self];

}

視圖控制器注冊(cè)更改通知并且執(zhí)行適當(dāng)?shù)牟僮?/p>

[[NSNotificationCenter defaultCenter] addObserver:self

selector:@selector(updateHomes:)

name:@"UpdateHomesNotification"

object:nil];

[[NSNotificationCenter defaultCenter] addObserver:self

selector:@selector(updatePrimaryHome:)

name:@"UpdatePrimaryHomeNotification" object:nil];

觀察個(gè)別home的變化

展示home信息的視圖控制器應(yīng)該成為home對(duì)象的代理,并且當(dāng)home發(fā)生改變時(shí)更新視圖控制器的視圖。

觀察特定home對(duì)象的改變
  • 在類的接口中添加home代理協(xié)議
@interface HomeViewController ()<HMHomeDelegate>
@end

  • 設(shè)置配件代理
home.delegate = self;

  • 實(shí)現(xiàn)HMHomeDelegate協(xié)議
    實(shí)現(xiàn)home:didAddAccessory:和home:didRemoveAccessory: 方法來更新展示配件的視圖。用HMAccessory類的room屬性可以獲取配件所屬的room。對(duì)配件來說,默認(rèn)的room是roomForEntireHome這個(gè)方法的返回值

Bridge Note: 當(dāng)你為home添加橋接口時(shí),橋接口底層的配件會(huì)自動(dòng)被添加到home中。你的代理會(huì)接收到橋接口后每個(gè)配件的 home:didAddAccessory:消息,但是你的代理不會(huì)接收到橋接口的home:didAddAccessory:消息。

觀察配件的變化
配件的狀態(tài)可以在任何時(shí)間發(fā)生變化。配件可能不能被獲得,可以被移除,或者被關(guān)閉。請(qǐng)更新用戶界面以反映配件狀態(tài)的更改,尤其是如果你的app允許用戶控制配件時(shí)。
如果從HomeKit數(shù)據(jù)庫(kù)中檢索到了配件對(duì)象,可以觀察個(gè)別配件的變化,具體步驟如下:

  • 在類接口中添加配件代理協(xié)議
@interface AccessoryViewController () < HMAccessoryDelegate> 

@end
  • 設(shè)置配件的代理
accessory.delegate = self;

  • 實(shí)現(xiàn)HMAccessoryDelegate 協(xié)議
    比如,執(zhí)行 accessoryDidUpdateReachability: 方法以啟用或者禁用配件控制
- (void)accessoryDidUpdateReachability:(HMAccessory *)accessory {

    if (accessory.reachable == YES) {

       // Can communicate with the accessory

    } else {

       // The accessory is out of range, turned off, etc

    }

}

如果你展示了配件的服務(wù)狀態(tài)和特性,那么請(qǐng)執(zhí)行以下代理方法來相應(yīng)地更新視圖

accessoryDidUpdateServices:

accessory:service:didUpdateValueForCharacteristic:

配件的服務(wù)具體內(nèi)容,請(qǐng)參閱Accessing Services and Their Characteristics

訪問服務(wù)和特性

服務(wù)(HMService)代表了一個(gè)配件(accessory)的某個(gè)功能和一些具體可讀寫的特性(HMCharacteristic)。一個(gè)配件可以擁有多項(xiàng)服務(wù),一個(gè)服務(wù)可以有很多特性。比如一個(gè)車庫(kù)開門器可能擁有一個(gè)照明和開關(guān)的服務(wù)。照明服務(wù)可能擁有打開/關(guān)閉和調(diào)節(jié)亮度的特性。用戶不能制造智能家電配件和他們的服務(wù)-配件制造商會(huì)制造配件和它們的服務(wù)-但是用戶可以改變服務(wù)的特性。一些擁有可讀寫屬性的特性代表著某種物理狀態(tài),比如,一個(gè)恒溫器中的當(dāng)前問題就是一個(gè)只可讀的值,但是目標(biāo)溫度又是可讀寫的。蘋果預(yù)先定義了一些服務(wù)和特性的名稱,以便讓Siri能夠識(shí)別它們。

獲得配件的服務(wù)和屬性

在依照Getting the Accessroties in a Room 中描述,你創(chuàng)建了一個(gè)配件對(duì)象之后,你可以獲得配件的服務(wù)和特性。當(dāng)然你也可以直接從home中按照類型獲得不同的服務(wù)。

通過HMAccessory類對(duì)象的services屬性,我們可以獲得一個(gè)配件的服務(wù)。

NSArray *services = accessroy.services;

要獲得一個(gè)home當(dāng)中配件提供的特定服務(wù),使用HMHome類對(duì)象的servicesWithTypes:方法

NSArray *lightServices = [home servicesWithTypes:[HMServicesTypeLightbulb]];

NSArray *thermostatServices = [home servicesWithTypes:[HMServicesTypeThermostat]];

使用HMServices類對(duì)象的name屬性來獲得服務(wù)的名稱

NSString *name = services.name;

要獲得一個(gè)服務(wù)的特性,可以使用characteristics屬性

NSArray *characteristics = service.characteristics

使用servicesType屬性來獲得服務(wù)的類型

NSString *serviceType = service.serviceType

蘋果定義了一些服務(wù)類型,并能被Siri識(shí)別:

  • 門鎖(Door locks)
  • 車庫(kù)開門器(Garage door openers)
  • 燈光(Lights)
  • 插座(Outlets)
  • 恒溫器(Thermostats)
改變服務(wù)名稱

使用updateName:completionHandler:異步方法來改變服務(wù)名稱。傳入此方法的服務(wù)名稱參數(shù)必須在一個(gè)home當(dāng)中是唯一的,并且服務(wù)名可被Siri識(shí)別。

[service updateName:@"Garage 1 Opener" completionHandler:^(NSError *error) {

    if (error) {

        // Failed to change the name

    } else {

        // Successfully changed the name

    }

}];

訪問特性的值

特性代表了一個(gè)服務(wù)的一個(gè)參數(shù),它可以是只讀,只寫或者可讀寫,它提供了這個(gè)參數(shù)可能的值的信息,比如,一個(gè)布爾或者一個(gè)范圍值。恒溫器中的溫度就是只讀的,而目標(biāo)溫度又是可續(xù)寫的,一個(gè)執(zhí)行某個(gè)任務(wù)命令且不要求任何返回,比如播放一段聲音或者閃爍一下燈光確認(rèn)某個(gè)配件,可能就是只寫的。

蘋果定義了一些特性的類型,并能被Siri識(shí)別:

  • 亮度(Brightness)
  • 最近溫度(Current temperature)
  • 鎖的狀態(tài)(Lock state)
  • 電源的狀態(tài)(Power state)
  • 目標(biāo)狀態(tài)(Target state)
  • 目標(biāo)溫度(Target temperature)

當(dāng)對(duì)于一個(gè)車庫(kù)開門器來說,目標(biāo)狀態(tài)就是打開或者關(guān)閉。對(duì)于一個(gè)鎖來說,目標(biāo)狀態(tài)就是上鎖和未上鎖。

在你獲得了一個(gè)HMService對(duì)象之后,如 Getting Services and Their Properties所描述的,你可以獲得每個(gè)服務(wù)的特性的值。因?yàn)檫@些值是從配件中獲得的,這些讀寫的方法都是異步的,并可以傳入一個(gè)完成回調(diào)的block

使用readValueWithCompletionHandler:異步方法來讀取一個(gè)特性的值。

[characteristic readValueWithCompletionHandler:^(NSError *error) {

    if (error == nil) {
        //可以加入代碼更新app視圖
       // Successfully read the value 
       id value = characteristic.value;

    }

    else {

       // Unable to read the value

} }];

使用writeValue:completionHandler:異步方法來向一個(gè)特性寫入值

[self.characteristic writeValue:@42 withCompletionHandler:^(NSError *error) {

    if (error == nil) {

       // Successfully wrote the value

    }

    else {

       // Unable to write the value

} }];

不要以為函數(shù)調(diào)用完成就以為這寫入成功,實(shí)際上只有在當(dāng)完成回調(diào)執(zhí)行并沒有錯(cuò)誤產(chǎn)生時(shí)才表示寫入成功。比如,知道一個(gè)開關(guān)的特性改變之前都不要改變這個(gè)開關(guān)的狀態(tài)。在if語(yǔ)句中,加入你的代碼,以更新app的視圖

另外,在別的app更新了特性的值時(shí)也需要更新視圖,在Observing Changes to Accessories中有描述。

創(chuàng)建服務(wù)組

一個(gè)服務(wù)組(HMServiceGroup)提供了控制不同配件的任意數(shù)量服務(wù)的快捷方式-比如,當(dāng)用戶離開家之后控制家中的某些燈。


image.png

在你創(chuàng)建了一個(gè)HMHome對(duì)象之后,如Getting the Primary Home and Collection of Homes中描述,你也就在這個(gè)家中創(chuàng)建一個(gè)服務(wù)組。

為了創(chuàng)建一個(gè)服務(wù)組,我們使用HMHome類對(duì)象的addServiceGroupWithName:completionHandler:方法,方法中參數(shù)服務(wù)組的名稱必須在此家中唯一,并可以被Siri識(shí)別

[self.home addServiceGroupWithName:@"Away Lights" completionHandler:^(HMServiceGroup *serviceGroup, NSError *error) {

    if (error == nil) {

       // Successfully created the service group

} else {

       // Unable to create the service group

    }];
    

我們使用HMServiceGroup類對(duì)象的addService:completionHandler:方法來向服務(wù)組中添加一個(gè)服務(wù)。服務(wù)可以在一個(gè)或多個(gè)服務(wù)組中。

[serviceGroup addService:service completionHandler:^(NSError *error) {

    if (error == nil) {

       // Successfully added service to service group

    }

       // Unable to add the service to the service group

    }];

通過HMServiceGroup類對(duì)象的accessory屬性,我們獲得服務(wù)所對(duì)應(yīng)的智能電器。

HMAccessory *accessory = service.accessory;

和配件類似,代理方法在別的app改變服務(wù)組時(shí)也會(huì)被調(diào)用。如果你的app使用了服務(wù)組,請(qǐng)參閱HMHomeDelegate Protocol Reference文檔,獲悉你應(yīng)該事先哪些方法以觀察這些變化。

測(cè)試HomeKitApp

如果你沒有智能電器,你可以使用HomeKit Accessroy Simulator來模擬home中的智能電器。每個(gè)模擬配件都擁有服務(wù)和特性,你可以從你的App當(dāng)中控制它。你的App在HomeKit數(shù)據(jù)庫(kù)中創(chuàng)建對(duì)象和關(guān)系。它可以創(chuàng)建home布局,可以添加新的配件到模擬的home環(huán)境中,最后向home中的每個(gè)房間添加只能配件,然后,你的app就能控制這些在HomeKitAccessory Simulator展示的模擬智能配件了。為了使用HomeKit Accessory Simulator,請(qǐng)?jiān)趇OS模擬器中運(yùn)行你的應(yīng)用程序,或者使用Xcode在Ios設(shè)備上運(yùn)行應(yīng)用程序。

HomeKitAccessory Simulator是一個(gè)附加的開發(fā)者工具,怎么安裝,之前已經(jīng)講過。

添加智能電器(配件)

使用HomeKit Accessory Simulator來添加只能電器到模擬網(wǎng)絡(luò)中。
向網(wǎng)絡(luò)中添加只能電器配件,請(qǐng)按照下面的步驟添加:

  • 在HomeKit Accessory Simulator中,點(diǎn)擊底部左邊‘+’按鈕。
  • 從彈出菜單中選擇添加智能電器(Add Accessory)
  • 輸入智能電器的名字和制造商。
  • 點(diǎn)擊完成
image.png
向智能電器中添加服務(wù)

一個(gè)智能電器需要一項(xiàng)服務(wù)和特性,你可以從app控制它。從預(yù)定了服務(wù)列表中選擇一項(xiàng)服務(wù),并自定義特性。

按照下面步驟向智能電器中添加服務(wù)

  • 在HomeKit Accessory Simulator中,選擇Accessories列中的某個(gè)配件。

該配件的服務(wù)信息會(huì)展示在一個(gè)詳情界面中。

注意:所有智能電器都有一個(gè)Accessory Information,顯示在所有其他服務(wù)的下方。你可以向這個(gè)Accessory Information服務(wù)添加特性,但你不能刪除默認(rèn)的特性。

  • 點(diǎn)擊添加服務(wù)(Add Service),并從彈出視圖中選擇一個(gè)服務(wù)類型。
    新添加的服務(wù)會(huì)在右邊詳細(xì)顯示。HomeKit Accessory Simulator為每種服務(wù)創(chuàng)建通用的特性。比如一個(gè)燈光服務(wù)的默認(rèn)特性為色彩(Hue),飽和度(Saturation),亮度(Brightness)和開關(guān)。(開關(guān)特性和電源狀態(tài)特性是一樣的,正如 Accessing Values of Characteristics中描述的那樣。)一些特性是強(qiáng)制性的有一些也是可選擇的。比如,開關(guān)特性就是強(qiáng)制性的,而色彩,飽和度,亮度這些特性都是可選擇的


    image.png

向服務(wù)中添加特性

你可以向服務(wù)中添加預(yù)定義的特性,或者自定義的特性。每種特性你都只能添加一個(gè)
按照下面的步驟向服務(wù)中添加特性

  • 在HomeKit Accessory Simulator中,服務(wù)詳情視圖,點(diǎn)擊添加特性(Add Characteristic)
  • 在特性類型菜單中,選擇一個(gè)類型或者自定義類型。
  • 在其他文本框中輸入此特性的其他信息,并點(diǎn)擊完成(Finish).新添加的特性會(huì)在詳細(xì)視圖展示出來。
  • 點(diǎn)擊特性右邊的減號(hào)來刪除一個(gè)特性。如果特性右邊并沒有減號(hào)顯示,這說明這個(gè)特性對(duì)這個(gè)服務(wù)來說是必須的。比如,你可以刪除電燈服務(wù)中的色彩(Hue),飽和度(Saturation)和亮度(Brightness),但是你不可以刪除開關(guān)特性。
image.png
通過你的app向家庭中添加智能電器(配件)

在你通過HomeKit Accessory Simulator創(chuàng)建了一個(gè)智能電器后,運(yùn)行你的App然后添加一個(gè)新的智能電器到你的家庭。

控制智能電器(配件)

在HomeKit Accessory Simulator中,你可以獲得智能電器的服務(wù),并在其他HomeKit App中設(shè)置服務(wù)的特性值來模擬控制這個(gè)智能電器,或者手動(dòng)地模擬控制智能電器

想要控制一個(gè)智能電器你需要:

  • 在HomeKit Accessory Simulator中的智能電器列表(Accessories column)中選擇一個(gè)智能電器。這個(gè)智能電器的服務(wù)和特性會(huì)被展示在詳情界面。
  • 操作一個(gè)特性的控件來改變它的值。

比如,為了改變一個(gè)燈泡的顏色(Hue),飽和度(Saturation)和亮度(Brightness),請(qǐng)滑動(dòng)這個(gè)滑塊。為了打開這個(gè)燈泡請(qǐng)選擇On選項(xiàng)

image.png

如果你的app展示了一個(gè)服務(wù)的特性,比如燈泡的開關(guān)狀態(tài),當(dāng)你在HomeKit Accessory Simulator中改變這些特性的值時(shí),它應(yīng)當(dāng)更新視圖。

++++++++++++++++++++++++++++

觀察HomeKit數(shù)據(jù)庫(kù)的變化,可參閱Observing HomeKit Database Changes
如果你想從app中通過編寫代碼來控制一個(gè)智能電器,請(qǐng)閱讀Accessing Services and Characteristics

++++++++++++++++++=

添加橋接口

為了模擬哪些不支持HomeKit Accessory Protocol協(xié)議的智能電器,需要添加一個(gè)虛擬橋接口,然后將智能家電添加到這個(gè)虛擬橋接口。配置虛擬橋接口底層的智能電器和配置其他類型的智能電器差不多。

添加一個(gè)虛擬橋接口到網(wǎng)絡(luò)
具體步驟如下:

  • 在HomeKit Accessory Simulator中,點(diǎn)擊智能電器列表底部的“+”按鈕。
  • 在彈出框中選擇Add 虛擬橋接口。
  • 輸入一個(gè)智能電器的名稱和制造商
  • 點(diǎn)擊完成


    image.png

向虛擬橋接口添加智能電器配件
可向一個(gè)虛擬橋接口添加一個(gè)或多個(gè)智能電器。

為了向一個(gè)虛擬橋接口添加一個(gè)智能電器,需要:

在HomeKit Accessory Simulator左邊的列表中,選擇虛擬橋接口中的一個(gè)虛擬橋接口。
在詳情頁(yè)面選擇Add Accessory。
輸入一個(gè)智能電器名字和制造商。
點(diǎn)擊完成


image.png
在你的app中添加虛擬橋接口到home

將虛擬橋接口和home匹配的過程和講一個(gè)智能電器配置到一個(gè)home的過程是一樣的,可參考Adding Accessories to a Home in Your App 在虛擬橋接口底層的智能電器配件也一樣被加入到了home,可參閱 Adding Bridges to Homes and Rooms

控制虛擬橋接口底層的智能電器

如何控制虛擬橋接口的智能電器和直接控制智能電器的步驟一致,可參閱Controlling Accessories in HomeKit Accessory Simulator除了你直接選擇虛擬橋接口下的智能電器之外。

在多設(shè)備和多用戶環(huán)境中測(cè)試

在iOS模擬器中你不能測(cè)試分享HomeKit數(shù)據(jù)庫(kù)到多個(gè)iOS設(shè)備和用戶。你應(yīng)該安裝你的App到多臺(tái)iOS設(shè)備上,在這些設(shè)備中輸入iCloud證書,然后運(yùn)行你的App?;蛘?,使用ad hoc授權(quán)來在多臺(tái)注冊(cè)設(shè)備中測(cè)試你的app。

為了測(cè)試單用戶多設(shè)備環(huán)境,你應(yīng)該使用同一個(gè)iCloud賬戶在多臺(tái)設(shè)備登陸。
為了測(cè)試多用戶使用同一家庭的智能電器,你應(yīng)該在多臺(tái)設(shè)備使用不同的iCloud賬戶登陸。
你的App應(yīng)該應(yīng)該可以允許一個(gè)用戶邀請(qǐng)客人到你的家中,如Managing Users所述。

創(chuàng)建動(dòng)作集(Action Sets)和觸發(fā)器(Triggers)

一個(gè)動(dòng)作集合HMActionSet和觸發(fā)器HMTimerTrigger允許你同時(shí)控制多個(gè)智能電器。比如,一個(gè)動(dòng)作集合可能會(huì)在用戶上床休息之前執(zhí)行一組動(dòng)作HMAction。一個(gè)寫作向一個(gè)特性寫入了值。動(dòng)作集合中的動(dòng)作是以不確定的順序執(zhí)行的。一個(gè)觸發(fā)器會(huì)在一個(gè)特定的時(shí)間觸發(fā)一個(gè)動(dòng)作集并可以重復(fù)執(zhí)行。每一個(gè)動(dòng)作集合在一個(gè)家庭中都有唯一的名稱并可被Siri識(shí)別。


image.png
創(chuàng)建寫入動(dòng)作

寫入動(dòng)作會(huì)想一個(gè)服務(wù)的特性寫入值并被加入到動(dòng)作集合中去。HMAction類是HMCharacteristicWriteAction具體類的抽象基類。一個(gè)動(dòng)作有一個(gè)相關(guān)聯(lián)的特性對(duì)象,你可以通過Accessing Services and Characteristics中描述的來獲取相關(guān)的服務(wù)和特性,然后創(chuàng)建這個(gè)HMCharacteristicWriteAction

為了創(chuàng)建一個(gè)動(dòng)作,我們使用HMCharacteristicWriteAction類中的initWithCharacteristic:targetValue:方法。

HMCharacteristicWriteAction *action = [[HMCharacteristicWriteAction alloc] initWithCharacteristic:characteristic targetValue:value];

在你的代碼中,你使用對(duì)應(yīng)的特性的期望來替換value參數(shù),并使用對(duì)應(yīng)的HMCharacteristic對(duì)象來替換characteristic參數(shù)

創(chuàng)建并執(zhí)行動(dòng)作集

一個(gè)動(dòng)作集就是一個(gè)共同執(zhí)行的動(dòng)作的集合。比如一個(gè)夜間動(dòng)作集合可能包含關(guān)閉電燈,調(diào)低恒溫水平和鎖上房門。

為了創(chuàng)建一個(gè)動(dòng)作集我們使用addActionSetWithName:completionHandler:異步方法

[self.home addActionSetWithName:@"NightTime" completionHandler:^(HMActionSet *actionSet, NSError *error) {

    if (error == nil) {

        // 成功添加了一個(gè)動(dòng)作集

    } else {

        // 添加一個(gè)動(dòng)作集失敗

    }

}];

為了添加一個(gè)動(dòng)作到動(dòng)作集,我們使用addAction:completionHandler:異步方法

[actionSet addAction:action completionHandler:^(NSError *error) {

    if (error == nil) {

        // 成功添加了一個(gè)動(dòng)作到動(dòng)作集

    } else {

    // 添加一個(gè)動(dòng)作到動(dòng)作集失敗

    }

}];

想要移除一個(gè)動(dòng)作,可使用removeAction:completionHandler:方法。
想要執(zhí)行一個(gè)動(dòng)作集,可使用HMHome類的executeActionSet:completionHandler:方法。比如,用戶希望控制所有的節(jié)日彩燈。我們就創(chuàng)建一個(gè)動(dòng)作集來打開所有的節(jié)日彩燈,另外一個(gè)動(dòng)作集來關(guān)閉所有的節(jié)日彩燈。為了打開所有的節(jié)日彩燈,發(fā)送executeActionSet:completionHandler:消息給home對(duì)象,并傳遞"打開節(jié)日彩燈"動(dòng)作集。

用戶管理

創(chuàng)建home的用戶是該home的管理員,可以執(zhí)行所有操作,包括添加一個(gè)客人用戶到home。任何管理員添加到這個(gè)home的用戶(HMUser)都有一個(gè)有限的權(quán)限??腿瞬荒芨募彝サ牟季?,但是可以執(zhí)行下面的動(dòng)作:

  • 識(shí)別智能電器
  • 讀寫特性
  • 觀察特性值變化
  • 執(zhí)行動(dòng)作集

比如,一個(gè)家庭的戶主可以創(chuàng)建一個(gè)home布局并向其中添加家庭成員。每個(gè)家庭成員必須擁有一個(gè)iOS設(shè)備和Apple ID以及相關(guān)的iCloud賬戶。iCloud需要個(gè)人輸入的APPle ID和戶主提供的APPle ID 相吻合,以便讓他們?cè)L問這個(gè)home??紤]到隱私問題,Apple ID對(duì)你的App是不可見的。

管理員需要遵從一下步驟來添加一個(gè)客人到home中:

  • 管理員調(diào)用一個(gè)動(dòng)作將客人添加到home中。
  • 你的App調(diào)用addUserWithCompletionHandler:異步方法
  • HomeKit展示一個(gè)對(duì)話框,要求輸入客人的Apple ID
  • 用戶輸入客人的Apple ID
  • 在完成回調(diào)中返回一個(gè)新的用戶
  • 你的App展示客人的名字

添加一個(gè)客人到home,需要在客人的iOS設(shè)備上做一下操作:
用戶在iCloud偏好設(shè)置中輸入iClound憑證(Apple ID 和密碼)
用戶啟動(dòng)你的App
你的App通過home manager object 獲得一個(gè)home集合
如果iClound的憑證和管理員輸入的Apple ID相同,那么管理員的home將會(huì)出現(xiàn)在homes屬性中。
客人執(zhí)行的操作可能會(huì)失敗。如果一個(gè)異步方法中出現(xiàn)HMErrorCodeInsufficientPrivileges錯(cuò)誤碼的話,這就意味著用戶沒有足夠的權(quán)限來執(zhí)行動(dòng)作-也許這個(gè)用戶是客人,而不是管理員。
為了測(cè)試你的App是否正確處理了客人用戶,可參閱Testting Multiple iOS Devices and Users

添加和移除用戶

Xcode10, iOS12 使用下面方法:

//MARK:-添加刪除用戶
- (void)_addHomeUser
{
    [self.currentHome manageUsersWithCompletionHandler:^(NSError * _Nullable error) {
        
        if (error == nil)
        {
            // Successfully added a user
            NSLog(@"---Successfully added a user");
        }
        else
        {
            // Unable to add a user
            NSLog(@"---Unable to add a user---%@", error);
        }
        
    }];
    
    NSLog(@"----users----%@", self.currentHome.users);
    NSLog(@"---current-users----%@", self.currentHome.currentUser.name);
    
}

會(huì)彈出一個(gè)頁(yè)面進(jìn)行添加,這個(gè)地方添加時(shí),使用Apple ID


image.png

添加之后,你添加的用戶會(huì)收到一個(gè)推送消息,同意之后會(huì)看到我共享給他的所有home的信息,界面如下:


image.png

獲得用戶名

你的app對(duì)用戶名只有讀寫權(quán)限,并不能讀寫用戶的Apple ID。使用HMHome對(duì)象的users屬性來獲取用戶。使用HMUser類的name屬性來獲取用戶名。

++++++++++++++++++++++++++++++++++++++++++++++++++++++

代碼示例

獲取homes

初始化之后我們?cè)谄浠卣{(diào)方法中可以獲取到manager.homes,這是一個(gè)數(shù)組,里邊是用戶的全部HMhome對(duì)象,我們可以遍歷這個(gè)數(shù)組獲取到全部的home,通過home.name得到home的名字。代碼如下:

#pragma mark - HMHomeManager delegate

- (void)homeManagerDidUpdateHomes:(HMHomeManager *)manager
{
    NSLog(@"---primaryHome 主房間只有一個(gè)--");
    NSLog(@"----已經(jīng)獲取到homes數(shù)據(jù),primary:是不是主房間---%@", manager.homes);
    [[NSNotificationCenter defaultCenter] postNotificationName:@"gethomes" object:nil];
    
    for (HMHome *home in manager.homes) {
        NSLog(@"------查看home---%@", home);
        NSLog(@"------查看home---%@", @(home.primary).stringValue);
    }
    
}

- (void)homeManagerDidUpdatePrimaryHome:(HMHomeManager *)manager
{
    NSLog(@"--已經(jīng)更新了primaryhome: %@", manager.primaryHome);
}

添加刪除home

使用homeManager對(duì)象來調(diào)用。這兩個(gè)方法同樣有兩個(gè)回調(diào)方法來告訴我們是否操作成功

- (void)initHomeKitManager
{
    self.homeManager = [[HMHomeManager alloc] init];
    self.homeManager.delegate = self;
}

#pragma mark - Home 添加刪除操作
- (void)addHome:(NSString *)homeName
{
    [self.homeManager addHomeWithName:homeName completionHandler:^(HMHome * _Nullable home, NSError * _Nullable error) {
        NSLog(@"----添加了home----%@----%@", home, home.name);
    }];
}

- (void)removeHome:(HMHome *)home
{
    [self.homeManager removeHome:home completionHandler:^(NSError * _Nullable error) {
        NSLog(@"-----刪除了home---%@----%@", home, home.name);
    }];
}


獲取room

獲取到HMhome對(duì)象之后可以通過home.rooms獲取到該home的全部room。同樣通過遍歷這個(gè)數(shù)組獲取到全部的HMroom對(duì)象,然后通過room.name獲取到room的名字

- (void)_updateCurrentHomesRooms:(HMHome *)home
{
    NSLog(@"------開始更新rooms數(shù)據(jù)");
    if (home.rooms.count)
    {
        self.roomArray = home.rooms;
        for (NSInteger i = 0; i < self.roomArray.count; i++) {
            HMRoom *room = self.roomArray[i];
            NSLog(@"++++++%@", room.name);
        }
    }
    else
    {
        self.roomArray = home.rooms;
    }
    
    [self.collectionView reloadData];
    
}


添加和移除room

同添加和移除home,不過是使用HMhome對(duì)象來調(diào)用

//刪除room
- (void)romoveRoom:(HMHome *)home
{
    if (home.rooms.count > 0)
    {
        [home removeRoom:home.rooms.firstObject completionHandler:^(NSError * _Nullable error) {
            NSLog(@"-----刪除了Room---%@----%@", home, home.rooms);
        }];
    }
    
}

//添加room
[self.currentHome addRoomWithName:newName completionHandler:^(HMRoom * _Nullable room, NSError * _Nullable error) {
                if (!error) {
                    [weakSelf _updateCurrentHomesRooms:weakSelf.currentHome];
                }
 }];
            

Accessories

尋找一個(gè)新的accessory

Accessories封裝了物理配件的狀態(tài),因此它不能被用戶創(chuàng)建,也就是說我們不能去創(chuàng)建智能硬件對(duì)象,只能通過去搜尋它,然后添加。想要允許用戶給家添加新的配件,我們可以使HMAccessoryBrowser對(duì)象在后臺(tái)搜尋一個(gè)與home沒有關(guān)聯(lián)的配件,當(dāng)它找到配件的時(shí)候,系統(tǒng)會(huì)調(diào)用委托方法來通知你的應(yīng)用程序。
具體步驟如下:

  • 設(shè)置 HMAccessoryBrowserDelegate的代理
  • 添加一個(gè)HMAccessoryBrowser對(duì)象屬性
- (void)_initConfigure
{
    self.browser = [[HMAccessoryBrowser alloc] init];
    self.browser.delegate = self;
    self.accessoryArray = [NSMutableArray array];
    [self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:@"cell"];
    self.tableView.delegate = self;
    self.tableView.dataSource = self;
}

  • 創(chuàng)建一個(gè)搜索按鈕,在按鈕的點(diǎn)擊方法里開始搜索硬件,需要實(shí)現(xiàn)代理方法
#pragma mark - HMAccessoryBrowser delegate
- (void)accessoryBrowser:(HMAccessoryBrowser *)browser didFindNewAccessory:(HMAccessory *)accessory
{
    NSLog(@">>>>>>>>>>>已經(jīng)發(fā)現(xiàn)了一個(gè)新的硬件<<<<<<<<<<<");
    [self.accessoryArray addObject:accessory];
    [self.tableView reloadData];
}

- (void)accessoryBrowser:(HMAccessoryBrowser *)browser didRemoveNewAccessory:(HMAccessory *)accessory
{
    NSLog(@"-----一個(gè)硬件已經(jīng)移除了------");
    
}


  • 點(diǎn)擊按鈕開始搜索新的智能硬件,如果搜索到硬件系統(tǒng)會(huì)通過didFindNewAccessory這個(gè)回調(diào)方法來通知我們發(fā)現(xiàn)了硬件,每次發(fā)現(xiàn)一個(gè)智能硬件這個(gè)方法都會(huì)調(diào)用一次

搜索結(jié)果如下:

2018-11-20 15:50:05.846864+0800 TETETE[14430:2872234] -------開始搜索設(shè)備----
2018-11-20 15:50:06.326251+0800 TETETE[14430:2872234] >>>>>>>>>>>已經(jīng)發(fā)現(xiàn)了一個(gè)新的硬件<<<<<<<<<<<
2018-11-20 15:50:06.330283+0800 TETETE[14430:2872234] >>>>>>>>>>>已經(jīng)發(fā)現(xiàn)了一個(gè)新的硬件<<<<<<<<<<<
2018-11-20 15:50:06.330490+0800 TETETE[14430:2872234] >>>>>>>>>>>已經(jīng)發(fā)現(xiàn)了一個(gè)新的硬件<<<<<<<<<<<
2018-11-20 15:50:06.330645+0800 TETETE[14430:2872234] >>>>>>>>>>>已經(jīng)發(fā)現(xiàn)了一個(gè)新的硬件<<<<<<<<<<<
2018-11-20 15:50:06.330839+0800 TETETE[14430:2872234] >>>>>>>>>>>已經(jīng)發(fā)現(xiàn)了一個(gè)新的硬件<<<<<<<<<<<
2018-11-20 15:50:06.331000+0800 TETETE[14430:2872234] >>>>>>>>>>>已經(jīng)發(fā)現(xiàn)了一個(gè)新的硬件<<<<<<<<<<<
2018-11-20 15:50:06.331163+0800 TETETE[14430:2872234] >>>>>>>>>>>已經(jīng)發(fā)現(xiàn)了一個(gè)新的硬件<<<<<<<<<<<
2018-11-20 15:50:06.331322+0800 TETETE[14430:2872234] >>>>>>>>>>>已經(jīng)發(fā)現(xiàn)了一個(gè)新的硬件<<<<<<<<<<<
2018-11-20 16:02:06.950860+0800 TETETE[14430:2872234] >>>>>>>>>>>已經(jīng)發(fā)現(xiàn)了一個(gè)新的硬件<<<<<<<<<<<

對(duì)應(yīng)的設(shè)備信息


image.png
為新的Accessory對(duì)象,指定一個(gè)room
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    //選取目標(biāo) 進(jìn)行配置
    //獲取當(dāng)前選擇的外設(shè)對(duì)象
    HMAccessory *acc = self.accessoryArray[indexPath.row];
    __block HMHome *home = self.currentHome;
    
    __weak typeof(self) weakSelf = self;
    [self.currentHome addAccessory:acc completionHandler:^(NSError * _Nullable error) {
        if (!error)
        {
            //如果添加home成功,將設(shè)備指定給某一個(gè)room
            if (acc.room != weakSelf.currentRoom)
            {
                [home assignAccessory:acc toRoom:weakSelf.currentRoom completionHandler:^(NSError * _Nullable error) {
                    if (!error) {
                        NSLog(@"---已經(jīng)將設(shè)備加入了%@",weakSelf.currentRoom.name);
                    }
                    else
                    {
                        NSLog(@"---指定房間失敗");
                        
                    }
                }];
            }
        }
        else
        {
            NSLog(@"--添加硬件到home失敗--%@-", error);
        }
    }];
    
}

添加外設(shè)和指定room的方法都是由HMHome對(duì)象調(diào)用的。如果我們只是向home中添加了設(shè)備,沒有指定room那么它就會(huì)被放入到一個(gè)默認(rèn)的room中


image.png
image.png
image.png
移除一個(gè)已經(jīng)添加到home中的accessory對(duì)象
//MARK:- 移除一個(gè)已經(jīng)添加到home中的accessory對(duì)象
- (void)_updateAccessoryName:(HMAccessory *)accessory
{
    [accessory updateName:@"測(cè)試Home" completionHandler:^(NSError * _Nullable error) {
        if (error)
        {
            NSLog(@"-----更改名字失敗---");
        }
        else
        {
            NSLog(@"-----更改名字成功---");
        }
        
    }];
}

//MARK:- 移除Accessory
- (void)_removeAccessory:(HMAccessory *)accessory
{
    [self.currentHome removeAccessory:accessory completionHandler:^(NSError * _Nullable error) {
    
        if (error)
        {
            NSLog(@"-----移除設(shè)備失敗---");
        }
        else
        {
            NSLog(@"-----移除設(shè)備成功---");
        }
        
    }];
}

查看當(dāng)前的設(shè)備
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    NSLog(@"-----w進(jìn)入了我的房間-------");
    [self.currentRoom.accessories enumerateObjectsUsingBlock:^(HMAccessory * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        NSLog(@"----當(dāng)前的設(shè)備----%@", obj.name);
    }];
}

*** 注意事項(xiàng) ***
*** 使用真機(jī)調(diào)試,連接時(shí)要先打開手機(jī)藍(lán)牙

  1. 電腦使用WiFI 一定要和手機(jī)使用的WIFI同一個(gè),電腦的藍(lán)牙也打開
  2. 連接會(huì)不穩(wěn)當(dāng),時(shí)而可以連接,時(shí)而又會(huì)不彈出添加設(shè)備的界面
  3. 建議可以先使用手機(jī)自帶的家庭App進(jìn)行連接,如果手機(jī)自帶的App可以連接成功,再去測(cè)試你自己寫的Demo
  4. 一旦設(shè)備添加到Room中,再次搜素就不會(huì)再出現(xiàn)

使用APP實(shí)現(xiàn)對(duì)硬件對(duì)象的基本控制

我是這樣處理的,如果有設(shè)備了則給一個(gè)展示設(shè)備的頁(yè)面,如果沒有設(shè)備的,跳轉(zhuǎn)到搜索設(shè)備的界面,當(dāng)然你也可以都用一個(gè),只是測(cè)試Demo
在展示設(shè)備的頁(yè)面中


image.png

在tableView的cell點(diǎn)擊方法中,設(shè)置設(shè)備的代理,進(jìn)行對(duì)設(shè)備的值進(jìn)行讀寫操作,代碼如下:


- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    //拿到只能硬件 首先 獲取硬件開啟的所有服務(wù)
    HMAccessory *acc = self.currentRoom.accessories[indexPath.row];
    NSArray *serviceArray = acc.services;
    acc.delegate = self;
    NSLog(@">>>>>這個(gè)外設(shè)中有%lu個(gè)服務(wù)>>>", serviceArray.count);
    //遍歷所有的服務(wù), 獲取每個(gè)服務(wù)的特征
    for (HMService *service in serviceArray) {
        NSLog(@">>>>服務(wù)的名字>>%@", service.name);
        /*
         獲取該服務(wù)中所有的特性
         判斷遍歷到的特征的讀寫屬性 然后賦值
         通過打印可看到HMCharacteristic是可讀可寫的
         */
        NSArray *arr = service.characteristics;
        for (HMCharacteristic *chara in arr) {
            NSLog(@"-0000000000000-特征為:%@", chara.properties);
            if ([chara.properties isEqual:HMCharacteristicPropertyReadable])
            {
                 self.charaWrite = chara;
            }
            else
            {
                 self.charaRead = chara;
                //接收外設(shè)的notifiy,類似于Ble開發(fā)中的通知
                [self.charaRead enableNotification:YES completionHandler:^(NSError * _Nullable error) {
                    
                }];
                
            }
        }
        
        if (self.charaRead)
        {//判斷一下如果有這個(gè)讀寫特性的話 就讀取它的值
            [self.charaRead readValueWithCompletionHandler:^(NSError * _Nullable error) {
                if (!error)
                {
                    /*
                     如果讀取成功那么打印該值,根據(jù)當(dāng)前值來改變外設(shè)狀態(tài)
                     如果服務(wù)是開關(guān),則讀取到的值是0(關(guān)閉) 1(打開)
                     */
                    id value = self.charaRead.value;
                    NSLog(@"--讀取到了值%@", value);
                    if ([value intValue] == 0)
                    {//q讀取到的值如果是0 那么當(dāng)前狀態(tài)為關(guān)閉, 那么就寫入1
                        [self.charaRead writeValue:@(1) completionHandler:^(NSError * _Nullable error) {
                            if (!error)
                            {
                                NSLog(@"---寫入成功");
                            }
                            else
                            {
                               NSLog(@"---寫入失敗");
                            }
                       }];
                        
                        
                    }
                    else
                    {//讀取到的為1, 寫入0
                        [self.charaRead writeValue:@(0) completionHandler:^(NSError * _Nullable error) {
                            if (!error)
                            {
                                NSLog(@"---寫入成功");
                            }
                            else
                            {
                                NSLog(@"---寫入失敗");
                            }
                        }];
                    }
                }
                else
                {
                    NSLog(@"---讀取失敗---");
                }
            }];
        }
    }
    
}

打印結(jié)果:

2018-11-21 16:57:51.869010+0800 TETETE[12656:1982261] >>>>服務(wù)的名字>>Switch 466044934
2018-11-21 16:57:51.869178+0800 TETETE[12656:1982261] -0000000000000-特征為:(
    HMCharacteristicPropertyReadable
)
2018-11-21 16:57:51.869399+0800 TETETE[12656:1982261] -0000000000000-特征為:(
    HMCharacteristicPropertyWritable,
    HMCharacteristicPropertyReadable,
    HMCharacteristicPropertySupportsEventNotification
)
2018-11-21 16:57:51.902866+0800 TETETE[12656:1982261] --讀取到了值0
2018-11-21 16:57:51.908635+0800 TETETE[12656:1982261] --讀取到了值0
2018-11-21 16:57:51.918117+0800 TETETE[12656:1982261] ---寫入成功
2018-11-21 16:57:51.919101+0800 TETETE[12656:1982261] ---寫入成功

當(dāng)你點(diǎn)擊cell的時(shí)候,進(jìn)行讀寫設(shè)備的數(shù)據(jù),可以通過HomeKit Accessory Simulator 模擬器看到界面上的控件(比如開關(guān)在變化)


image.png

------------我是分哥線------------------------
需要思考的小問題O(∩_∩)O,路過大神如果知道請(qǐng)賜教~~
Question:
1.添加過的設(shè)備,無(wú)法再次添加,即便把這個(gè)設(shè)備的room刪除了也不行
2.在現(xiàn)有Room,再添加一個(gè)其他的設(shè)備,則會(huì)無(wú)法控制設(shè)備開關(guān)

演示Demo

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 本文由CocoaChina翻譯組成員iBenjamin_Go和淺夏@舊時(shí)光翻譯自蘋果開發(fā)文檔:HomeKit De...
    涅槃簡(jiǎn)書閱讀 5,619評(píng)論 6 15
  • 本文轉(zhuǎn)載xianghuibeijingCSDN 轉(zhuǎn)載過程中部分內(nèi)可能丟失!請(qǐng)參考原作者:http://blog....
    大熊Q閱讀 3,302評(píng)論 0 12
  • 簡(jiǎn)介 簡(jiǎn)介1> HomeKit庫(kù)是用來溝通和控制家庭自動(dòng)化配件的,這些家庭自動(dòng)化配件都支持蘋果的HomeKit A...
    Rui哥閱讀 2,270評(píng)論 0 0
  • (一)創(chuàng)建Home布局 1> 允許用戶創(chuàng)建一個(gè)或多個(gè)Home布局,每個(gè)Home代表一個(gè)有網(wǎng)絡(luò)設(shè)備的住所.2> 用戶...
    Rui哥閱讀 991評(píng)論 1 0
  • 版本記錄 前言 目前全世界都在積極投入AI領(lǐng)域,我國(guó)的互聯(lián)網(wǎng)公司也是積極在AI方面進(jìn)行投入布局,比如BAT以及今日...
    刀客傳奇閱讀 1,886評(píng)論 0 1

友情鏈接更多精彩內(nèi)容