原生设备支持HomeKit
为您的NativeScript应用提供HomeKit插件
npm i --save nativescript-homekit

原生设备支持HomeKit插件

安装

从命令提示符转到您的应用根目录并执行

tns plugin add nativescript-homekit

示例应用

推荐!查看示例,了解您可以使用HomeKit做什么。

您可以通过在项目根目录中输入 npm run demo.ios 来运行示例应用。

一些背景信息

此处所述,HomeKit是一个框架,用于与支持苹果HomeKit配件协议的智能家居配件进行通信和控制。HomeKit应用允许用户发现兼容的配件并对其进行配置。用户还可以创建动作来控制配件(如恒温器或灯具),将它们分组在一起,并使用Siri触发它们。

HomeKit对象存储在用户iOS设备上的数据库中,通过iCloud同步到其他iOS设备。HomeKit支持远程访问配件、多个用户设备和多个用户。HomeKit还为您处理安全和隐私。

住宅

在层次结构的顶部是“住宅”,例如您的家庭住宅和(永久性的)度假住宅。每个住宅可以包含多个房间。住宅中的配件可以分配到房间。最后,配件具有服务

区域

为了进一步结构化您的HomeKit布局并创建强大的场景,HomeKit可以将您的住宅划分为区域(“厨房”和“车库”房间可以聚集在“楼下”区域)

此插件的功能

此插件提供了一个简单直接的接口,用于管理HomeKit的SDK中的住宅、房间和区域,并将配件分配给这些住宅或房间。

除此之外还可以做更多的事情,但您需要直接与HomeKit SDK交互。不用担心,我们会解释如何操作,这比您想象的要简单。

您可能想知道为什么此插件没有暴露HomeKit的全部功能?主要是因为它非常庞大,而此插件之外的所有功能实际上都取决于您拥有的配件类型。这意味着我们会生成大量的未经测试的包装代码,而使用原始SDK本身并没有那么不同。

设置

在Xcode中打开您的项目,转到目标,然后启用HomeKit。除非您运行tns platforms remove ios & tns platform add ios,否则这只需要做一次。

下载HomeKit模拟器,它现在是硬件IO工具的一部分。这是测试您的HomeKit应用的一种非常方便的方式。

只需打开模拟器,并按图所示添加新的配件,您就可以在示例应用中玩转它了。

类型

HomeKit插件封装了原生iOS HomeKit SDK类,使您能够更方便地与之交互。以下API函数使用本节中列出的类型。

请注意,您可以跳过本节,直接查看此插件提供的TypeScript .ts.d文件。如果您使用VSCode或Webstorm/Intellij等不错的IDE,您将基于这些定义获得自动完成等功能。

主页

| 属性 | 类型 | 描述 | --- | --- | --- | --- | name | string | 这是由Siri使用的,因此是唯一的 | | primary | boolean | 您创建的第一个家将是“主要”家 | | zones | Array | 在此家中创建的所有区域 | | rooms | Array | 在此家中创建的所有房间 | | accessories | Array | 分配给此家的所有配件 | | ios | HMHome | 您可以进一步探索的本地HomeKit SDK类 |

区域

| 属性 | 类型 | 描述 | --- | --- | --- | --- | name | string | 这是由Siri使用的,因此对于家是唯一的 | | rooms | Array | 区域可以包含多个房间,每个房间都有一个独特的名称 | | ios | HMZone | 您可以进一步探索的本地HomeKit SDK类 |

房间

| 属性 | 类型 | 描述 | --- | --- | --- | --- | name | string | 这是由Siri使用的,因此对于家是唯一的 | | accessories | Array | 房间可以分配多个配件 | | ios | HMRoom | 您可以进一步探索的本地HomeKit SDK类 |

配件

| 属性 | 类型 | 描述 | --- | --- | --- | --- | name | string | 这是由Siri使用的,因此对于家是唯一的 | | bridged | boolean | 此配件是否通过桥(也是一种配件)连接 | | room? | Room | 配件可能或可能未分配给房间 | | ios | HMAccessory | 您可以进一步探索的本地HomeKit SDK类 |

API

大部分示例将使用TypeScript,因为我认为这是目前用JavaScript构建任何东西的最好方式。如果您计划与HomeKit的配件和服务进行深度交互,您还需要安装tns-platform-declarations模块,它提供了HomeKit SDK的类型声明。

听起来有点令人不知所措?只需查看示例应用即可,因为它已经配置了所有这些部分。这是一个由TypeScript和NativeScript驱动的非Angular应用,您可以从中复制代码片段。

请注意,所有这些API函数都使用Promises,因此它们的.then()将接收resolve和reject参数。reject将始终包含一个错误原因的字符串。大多数时间,这些错误将来自HomeKit本身。例如,如果您向家中添加一个与现有房间同名的房间。或者如果房间名称以Siri不喜欢的字符结尾。

为了简洁,我将省略大部分示例中的reject。

可用

在iOS上,此方法始终返回true,在Android上返回false。因此,如果您已经有了其他方便的方法在两者之间分支代码,则无需调用此方法。

JavaScript
// require the plugin
var HomeKit = require("nativescript-homekit").HomeKit;

// instantiate the plugin
var homeKit = new HomeKit();

homeKit.available().then(
function(available) {
console.log(available ? "YES!" : "NO");
}
);
TypeScript
// require the plugin
import { HomeKit } from "nativescript-homekit";

// instantiate the plugin (assuming the code below is inside a Class)
private homeKit = new HomeKit();

public checkAvailability(): void {
this.homeKit.available().then(
avail => console.log(available ? "YES!" : "NO"),
err => console.log(err)
);
}

init

没有init,就没有荣耀 - 哎,HomeKit交互。您需要传入一个函数,当HomeKit数据库中的任何内容发生变化时,该函数将接收更新,以便您的应用可以对这些更改做出响应。

this.homeKit.init((homes: Array<Home>) => {
// do anything with the Homes you received (look at the demo app!)
});

startSearchingForAccessories

配件可能会随时出现,但默认情况下,您的应用不会始终搜索它们。在您的应用UI中添加一个按钮以启动和停止搜索配件可能是一个好主意,因为用户将知道何时可以找到新的配件。

只能找到新的配件,而不能找到已分配给家或房间的配件。此外,当配件之前存储在本地HomeKit数据库中,现在已被删除(尝试一下,在HomeKit模拟器中删除一个)时,您也将收到通知。

为此,您可以传入2个不同的回调函数:第一个用于新发现的设备,第二个用于已删除的设备

this.homekit.startSearchingForAccessories(
(accessory: Accessory) => {
console.log("New accessory found: " + accessory.name);
// you can use this to further interact with the accessory:
console.log("Accessory native object: " + accessory.ios);
},
(accessory: Accessory) => {
console.log("Accessory removed: " + accessory.name);
}).then(
() => console.log("searching.."),
(err) => alert(err)
);

停止搜索配件

我不确定搜索配件会消耗多少电量,但允许用户停止搜索配件可能是个好主意。

此外,实现起来也很容易,所以赶快试试吧!

this.homekit.stopSearchingForAccessories().then(() => console.log("Searching stopped"));

管理家庭:addHomeremoveHomerenameHome

您可以为用户提供配置家庭、区域和房间(如演示应用所做的那样)的功能。以下是管理家庭的方法

添加家庭

import { prompt, PromptResult } from "ui/dialogs";

// ask the user for a name and add it to HomeKit
prompt("Name the home").then((promptResult: PromptResult) => {
if (promptResult.result) {
that.homekit.addHome(promptResult.text).then((home: Home) => {
console.log(JSON.stringify(home));
that.homes.push(home);
}, err => alert(err));
}
});

删除家庭

this.homekit.removeHome(name).then((home: Home) => {
// the returned home is the one deleted
}, err => alert(err));

重命名家庭

// ask the user for a new name, prefill the old one
prompt(`Rename home '${currentName}' to..`, currentName).then((promptResult: PromptResult) => {
if (promptResult.result) {
// since the name is unique we're using 'currentName' as an identifier
that.homekit.renameHome(currentName, promptResult.text).then((home: Home) => {
// the returned home is already updated with the new name
console.log(`Renamed ${currentName} to ${home.name}`);
}, err => alert(err));
}
});

管理区域:addZoneremoveZonerenameZone

与家庭管理类似,所以我们只在这里展示TypeScript定义,以免让您感到厌烦

addZone(name: string, toHome: string): Promise<Zone>;

removeZone(name: string, fromHome: string): Promise<Zone>;

renameZone(oldName: string, newName: string, inHome: string): Promise<Zone>;

管理房间:addRoomToHomeaddRoomToZoneremoveRoomFromZoneremoveRoomFromHomerenameRoom

与其他操作非常相似。唯一的区别是您只能将房间添加到已添加到家庭的区域。这很有道理,对吧?没错。因此,在操作区域时,您还需要传递家庭名称。

addRoomToHome(name: string, toHome: string): Promise<Room>;

addRoomToZone(name: string, toZone: string, inHome: string): Promise<Zone>;

removeRoomFromZone(name: string, fromZone: string, inHome: string): Promise<Zone>;

removeRoomFromHome(name: string, fromHome: string): Promise<Room>;

renameRoom(oldName: string, newName: string, inHome: string): Promise<Room>;

管理配件:addAccessoryToHomeremoveAccessoryFromHomeassignAccessoryToRoomrenameAccessory

现在这应该已经很熟悉了。但也有一些需要注意的事项

  • 区域不能分配配件,它们仅用于将房间分组。
  • 在将配件分配给房间之前,您首先需要将配件分配给家庭。这就是为什么您需要在assignAccessoryToRoom中传递家庭名称的原因。
  • 配件一次最多只能分配给一个家庭(和一个房间)。
  • 如果您想将配件分配给不同的房间,只需使用assignAccessoryToRoom
addAccessoryToHome(accessoryName: string, toHome: string): Promise<Home>;

removeAccessoryFromHome(accessoryName: string, fromHome: string): Promise<Home>;

assignAccessoryToRoom(accessoryName: string, roomName: string, homeName: string): Promise<Array<Room>>;

renameAccessory(oldName: string, newName: string): Promise<Accessory>;