system.interconnect 设备互联(跨设备通信)
在手表等设备与手机端应用之间建立连接,实现跨设备消息收发、连接状态监听与连接诊断。官方标准文档中本模块名为"设备通信 interconnect":用于和搭配使用的手机 app 进行通信,收发手机 app 数据。
| 项目 | 说明 |
|---|---|
| 模块名 | system.interconnect |
| Feature 类型 | 标准 Feature |
| 所需权限 | 无 |
接口声明
{ "name": "system.interconnect" }导入方式
// 快应用标准写法
import interconnect from '@system.interconnect'
// 本仓库运行时/测试中使用的写法
const interconnect = require('system.interconnect')功能概述
system.interconnect 用于设备端(如手表)与手机端指定应用之间的互联通信。底层基于 uv_miwear(libuv 扩展,通过管道与手机端 miwear 服务通信),按包名连接并验证手机上的目标应用,连接建立后可双向收发消息。
官方说明:通信连接会自动建立,应用内不用关心连接的创建和销毁,但是可以注册回调函数来接收连接状态改变的信息,以便于进行相应处理,例如对用户进行提示。
require('system.interconnect')时,Native 会自动以当前快应用的包名发起连接;- 通过
interconnect.instance(info)可以获取互联实例(InterConn),并可用info.package指定/覆盖手机端目标应用包名;该实例在快应用线程内是单例,多次调用返回同一个对象(官方说明:获取连接对象,在 app 中以单例形式存在,后续的数据收发都是基于这个连接对象); - 实例提供
send(发送数据到手机 App 端)、getReadyState(获取 App 连接状态)、diagnosis(连接诊断)三个方法,以及onmessage/onopen/onclose/onerror四个事件属性; - 连接断开期间发送的消息会在
timeout时间内缓存,连接恢复后自动补发,超时则失败。
API
interconnect.instance(info)
获取一个互联实例(InterConn),用于与手机端应用通信。当前底层实现是单例,重复调用返回同一个实例。调用时若连接尚未建立,会自动发起连接。
参数(params 对象字段)
| 字段 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
| package | string | 否 | 无 | 手机端目标应用的包名,用于连接手机上的应用;传入后会覆盖默认包名 |
| fingerprint | string | 否 | 无 | 应用指纹信息(用于连接验证);当前 Native 实现中仅接收该字段,实际未使用 |
(参数整体可选:instance(AppInfo info = null),不传时使用当前快应用包名连接。官方文档中 instance 标记为无参数。)
返回值
| 字段 | 类型 | 说明 |
|---|---|---|
| 返回值 | object(InterConn 实例) | interconnect 的连接实例 connect 对象,拥有下文的方法与事件属性;单例,多次调用返回同一对象 |
示例
const interconnect = require('system.interconnect')
// 指定手机端目标应用包名,获取互联实例
const conn = interconnect.instance({
package: 'com.example.phoneapp',
fingerprint: 'xxxxxxxxxxxxxxxxx'
})
// 也可以不传参数,使用当前快应用包名连接
const conn2 = interconnect.instance官方示例:
const connect = interconnect.instanceconn.getReadyState(parms)
获取 App 连接状态。异步模型:Promise 风格(promise<object>),同时参数对象中也支持 success / fail 回调(以 JIDL 为准)。
参数(ReadystateParams 对象字段)
| 字段 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
| success | function(ReadyStateSuccessCb) | 否 | 无 | 成功回调,参数为 StatusInfo,见下 |
| fail | function(ReadyStateFailCb) | 否 | 无 | 失败回调,参数为 (errMsg: string, code: number) |
(参数整体可选:getReadyState(ReadystateParams parms = null)。)
成功返回 / success 回调参数
StatusInfo 对象:
| 字段 | 类型 | 说明 |
|---|---|---|
| status | number(int) | 连接状态:1 表示连接成功(手机端应用连接建立);2 表示连接断开/未连接(连接断开、连接失败、手机端应用未安装、连接已关闭等;当前 Native 实现中连接建立过程中也返回 2) |
Native 源码注释中曾约定
0表示连接中,但当前实现对未连接状态统一返回2,具体以 Native 实现为准。
失败回调 fail / Promise reject
- 参数:
(errMsg: string, code: number) - 错误码/错误信息:
| code | message | 触发场景 |
|---|---|---|
| 1000 | conn has been shoutdown | 互联实例已销毁(Feature 销毁后调用) |
官方错误码说明:支持通用错误码,
1006表示连接断开。
示例
const interconnect = require('system.interconnect')
const conn = interconnect.instance
// 回调风格
conn.getReadyState({
success: function (ret) {
if (ret.status === 1) {
console.log('连接成功')
} else if (ret.status === 2) {
console.log('连接失败')
}
},
fail: function (errMsg, code) {
console.log('getReadyState fail', code, errMsg)
}
})
// Promise 风格
conn.getReadyState.then(function (ret) {
console.log('status =', ret.status)
}).catch(function (err) {
console.log('fail', err)
})conn.send(parms)
发送数据到手机 App 端。异步模型:Promise 风格(promise<void>)。
- 已连接时立即发送;
- 连接正在建立时,消息会缓存为 pending 任务,连接建立后自动发送;在
timeout时间内连接仍未建立则超时失败; - 已断开连接时直接失败。
参数(SendParams 对象字段)
| 字段 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
| data | object | 是 | null | 发送的数据,必须为对象;Native 会将其序列化为字符串(JSON)后发送,序列化结果不能为空字符串 |
| timeout | number(int) | 否 | 1000 | 连接未建立时消息缓存的最长等待时间,单位毫秒;超时后本次发送失败 |
成功返回 / success 回调参数
无(promise<void>,resolve 不带数据)。
失败回调 fail / Promise reject
- 参数:
(errMsg: string, code: number) - 错误码/错误信息:
| code | message | 触发场景 |
|---|---|---|
| 202 | invalid args | data 为空、不是对象、无法序列化为字符串或序列化为空字符串 |
| 204 | send timeout | 连接建立过程中缓存的发送任务等待超时(timeout 毫秒内未连上;官方错误码说明:204 链接超时) |
| 1006 | disconnect | 当前处于断开状态,无法发送(官方错误码说明:1006 连接断开) |
| 1006 | connection broken | 消息已发出但底层发送失败(连接中断) |
| 1006 | conn has been shoutdown | 互联实例已销毁 |
示例
const interconnect = require('system.interconnect')
const conn = interconnect.instance
// Promise 风格
conn.send({
data: { hello: 'world' },
timeout: 2000
}).then(function {
console.log('发送成功')
}).catch(function (err) {
console.log('发送失败', err)
})
// 使用默认 timeout(1000ms)
conn.send({ data: { msg: 'hello phone' } })官方示例(回调风格):
connect.send({
data: {
str: 'test',
num: 123
},
success: => {
console.log(`handling success`)
},
fail: (data, code) => {
console.log(`handling fail, errMsg = ${data.data}, errCode = ${data.code}`)
}
})conn.diagnosis(param)
诊断手表应用和对端应用的连接情况:如果连接成功则返回 ok,连接失败则返回失败原因。连接正在建立时,会等待连接结果(最多等待 timeout 毫秒)后再返回最终状态;连接已有明确结果(已连接/已断开/应用未安装等)时立即返回。同一时间只允许一个诊断任务。异步模型:Promise 风格(promise<object>)。
参数(DiagnosisParams 对象字段)
| 字段 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
| timeout | number(int) | 否 | 10000 | 等待诊断/连接结果的超时时间,单位毫秒(官方默认值:10000ms);必须为正数,同一时间只允许一个诊断任务 |
(参数整体可选:diagnosis(DiagnosisParams param = null),不传时使用默认超时 10000ms。)
成功返回 / resolve 值
resolve 一个对象,status 字段表示诊断结果(注意:诊断完成本身走 resolve,具体连接结果看 status):
| 字段 | 类型 | 说明 |
|---|---|---|
| status | number(int) | 0:OK 链接成功;204:CONNECT_TIMEOUT 连接超时;1001:APP_UNINSTALLED 对端应用未安装;1000:OTHERS 其他链接错误(连接失败/连接断开) |
失败回调 fail / Promise reject
- 参数:
(errMsg: string, code: number) - 错误码/错误信息:
| code | message | 触发场景 |
|---|---|---|
| 1000 | timeout should be positive | timeout 小于等于 0 |
| 1000 | diag | 上一个诊断任务尚未结束(同一时间只允许一个 pending 诊断) |
| 1006 | conn has been shoutdown | 互联实例已销毁 |
示例
const interconnect = require('system.interconnect')
const conn = interconnect.instance
conn.diagnosis({ timeout: 5000 }).then(function (ret) {
switch (ret.status) {
case 0:
console.log('连接正常')
break
case 204:
console.log('诊断超时')
break
case 1001:
console.log('手机端应用未安装')
break
default:
console.log('连接异常,status =', ret.status)
}
}).catch(function (err) {
console.log('diagnosis fail', err)
})Promise 返回形式(社区资料:洛汐文档库——同源 JIDL 把 getReadyState/diagnosis/send 定义为 Promise;不同框架版本可能同时支持 callback 与 Promise 两种风格,应以返回对象是否具有 .then 为准):
const state = await connect.getReadyState
const diagnosis = await connect.diagnosis({ timeout: 10000 })
await connect.send({ data: payload, timeout: 1000 })conn.getApkStatus
已废弃:JIDL 注释标明"废弃的接口,保持兼容性",新代码请使用
getReadyState/diagnosis/onopen/onclose(社区资料:洛汐文档库同样标注该方法在 JIDL 中明确标记为废弃,新代码应使用getReadyState和diagnosis,因为后者能区分连接超时、应用未安装和其他错误)。
同步获取手机端应用的连接状态字符串。
参数
无。
返回值
| 字段 | 类型 | 说明 |
|---|---|---|
| 返回值 | string | CONNECTED(手机端应用已连接)、DISCONNECTED(通道存在但当前未连接/已断开/其他状态/实例已销毁)、UNINSTALLED(手机端应用未安装)三者之一 |
示例
const interconnect = require('system.interconnect')
const conn = interconnect.instance
console.log(conn.getApkStatus) // 'CONNECTED' | 'DISCONNECTED' | 'UNINSTALLED'
// 社区资料:调用前可做能力判断
if (typeof conn.getApkStatus === 'function') {
console.log(conn.getApkStatus)
}属性(事件)
| 属性 | 类型 | 读写 | 说明 |
|---|---|---|---|
| onmessage | function(OnMessage) | 可读写 | 接收手机 App 端数据时触发,回调参数为 Message 对象({ data: string }),data 为消息内容字符串 |
| onopen | function(OnOpen) | 可读写 | 连接打开时触发(首次连接与断线重连都会触发),回调参数为 object,Native 实现中该对象包含布尔字段 isReconnected(是否是重新连接) |
| onclose | function(OnClose) | 可读写 | 连接关闭时触发,回调参数为 CloseInfo 对象({ data: string, code: number }),data 为原因描述 |
| onerror | function(OnError) | 可读写 | 连接出错时触发,回调参数为 ErrorInfo 对象({ data: string, code: number }) |
赋值新回调会替换并移除旧回调。
onclose / onerror 事件的 code 与 data(Native 实证)
| 事件 | code | data | 触发场景 |
|---|---|---|---|
| onerror | 1000 | connect to app failed | 连接手机端应用失败(未知错误) |
| onerror | 1006 | connect to miwear server failed | 连接建立过程中连接断开(连接失败) |
| onclose | 1000 | disconnect | 已连接后连接断开 |
| onclose | 1001 | phone app uninstalled | 手机端应用被卸载 |
官方标准文档描述:官方文档将错误码
1000(未知错误)、1001(手机 APP 未安装)、1006(连接断开)均列在onerror的错误码说明中。
示例
const interconnect = require('system.interconnect')
const conn = interconnect.instance
conn.onmessage = function (msg) {
console.log('received message:', msg.data)
}
conn.onopen = function (info) {
// info 为对象,Native 实现中包含 isReconnected 布尔字段
console.log('connection opened isReconnected: ', info.isReconnected)
}
conn.onclose = function (info) {
console.log('connection closed, reason =', info.data, 'code =', info.code)
}
conn.onerror = function (err) {
console.log('connection error, errMsg =', err.data, 'errCode =', err.code)
}数据结构
AppInfo
instance(info) 的参数,描述手机端目标应用信息。
| 字段 | 类型 | 说明 |
|---|---|---|
| package | string | 手机端应用包名,用于连接并验证手机上的应用 |
| fingerprint | string | 应用指纹(当前 Native 实现中未实际使用) |
StatusInfo
getReadyState 成功回调 / resolve 值。
| 字段 | 类型 | 说明 |
|---|---|---|
| status | int | 连接状态:1 连接成功;2 连接断开 |
Message
onmessage 回调参数。
| 字段 | 类型 | 说明 |
|---|---|---|
| data | string | 接收的数据(消息内容字符串) |
CloseInfo
onclose 回调参数。
| 字段 | 类型 | 说明 |
|---|---|---|
| data | string | 连接关闭返回的数据(关闭原因 reason) |
| code | int | 链接关闭状态码 |
ErrorInfo
onerror 回调参数。
| 字段 | 类型 | 说明 |
|---|---|---|
| data | string | 错误信息 |
| code | int | 错误码 |
FailInfo
send 失败回调结构(JIDL 中定义,Promise reject 时对应 (data, code))。
| 字段 | 类型 | 说明 |
|---|---|---|
| data | string | 错误描述 |
| code | int | 错误码 |
SendParams
send 的参数。
| 字段 | 类型 | 说明 |
|---|---|---|
| data | object | 待发送数据,默认 null;Native 序列化为字符串发送,不能为空 |
| timeout | int | 发送缓存等待超时(毫秒),默认 1000 |
DiagnosisParams
diagnosis 的参数。
| 字段 | 类型 | 说明 |
|---|---|---|
| timeout | int | 诊断等待超时(毫秒),默认 10000 |
ReadystateParams
getReadyState 的参数。
| 字段 | 类型 | 说明 |
|---|---|---|
| success | callback(ReadyStateSuccessCb) | 成功回调,参数为 StatusInfo |
| fail | callback(ReadyStateFailCb) | 失败回调,参数为 (errMsg: string, code: int) |
错误码汇总
Native 实现(StatusCode)中定义的错误码:
| code | 枚举名 | 含义 |
|---|---|---|
| 0 | kOk | 成功(diagnosis 的 status) |
| 202 | kInvalidArgs | 参数错误(send 的 data 非法;diagnosis 内部校验超时参数时使用,reject 给 JS 时为 1000) |
| 203 | kUnsupported | 不支持(已有 pending 诊断任务时内部返回,reject 给 JS 时为 1000) |
| 204 | kTimeout | 超时(send 超时失败;diagnosis 的 status) |
| 1000 | kUnknown | 未知错误(连接失败/断开;onerror/onclose 事件码;diagnosis 的 status 与 reject 码;实例销毁后 getReadyState reject) |
| 1001 | kAppUninstall | 手机端应用未安装(diagnosis 的 status;onclose 事件码) |
| 1006 | kDisconnect | 连接断开(send reject;实例销毁后 send/diagnosis reject;onerror 事件码) |
注意事项
- 自动连接:
require('system.interconnect')时 Native 即以当前快应用包名自动发起连接(底层uv_miwear_connect,基于管道连接手机端 miwear 服务);instance返回单例,多次调用得到同一个InterConn对象。应用无需关心连接的创建和销毁,注册事件回调即可接收连接状态变化(官方说明)。 - 消息缓存:连接建立过程中调用
send,消息会缓存并在连接成功后自动发送(ProcessPendingSendTasks);超过timeout未连上则以 204 超时失败。连接已断开时send立即以 1006 失败。 - 数据格式:
send的data必须是对象,Native 通过字符串转换(JSON 序列化)后发送;空字符串/非对象都会返回 202invalid args。 - 诊断串行:同一时间只允许一个 pending 的
diagnosis调用,重复调用会 reject(diag);timeout必须为正数。 - 事件补发:
onerror未注册时发生的错误会被缓存(仅保留最新一条),之后注册onerror时立即补发;连接已建立后再注册onopen,也会补发一次连接事件。 - onopen 参数:JIDL 声明回调参数为
object is_reconnect,Native 实际传入对象的字段名为isReconnected(boolean);源码注释中首次连接/重连的布尔取值描述存在不一致,具体行为以 Native 实现为准。 - 生命周期:Feature 销毁时会关闭 miwear 连接、停止定时器并清理 pending 的发送/诊断任务;此时尚未 settle 的 Promise 不会再回调(Native 打印
unrejected ...警告日志),实例销毁后调用各方法会以 1006/1000 失败。 getApkStatus为废弃接口,仅为兼容性保留;新代码使用getReadyState与diagnosis(后者可区分连接超时、应用未安装和其他错误,社区资料:洛汐文档库)。
官方开发注意事项:包名与签名
interconnect 通信前提要保证快应用和三方应用安卓端两者的包名及签名保持一致(官方标准文档):
- 保证快应用
manifest.json里package字段与需要接入的三方 app 安卓端包名一致。 - 快应用签名需要使用三方应用安卓端签名,可以从
.jks中提取证书及私钥,方法如下:
- 先将 jks 转换成 p12,执行以下命令,输入相应密码后,在同级目录下生成对应的 p12 格式文件:
keytool -importkeystore -srckeystore keystore.jks -destkeystore keystore.p12 -srcstoretype jks -deststoretype pkcs12- 再将 p12 转 pem,执行以下命令,输入上一步设置的 p12 文件密码后,在同级目录下生成对应的 pem 格式文件:
openssl pkcs12 -nodes -in keystore.p12 -out keystore.pem- 从 pem 格式文件中复制出私钥和证书:把
-----BEGIN PRIVATE KEY-----到-----END PRIVATE KEY-----的内容复制到private.pem中;把-----BEGIN CERTIFICATE-----到-----END CERTIFICATE-----的内容复制到certificate.pem中。
- 如果本地没有安装 OpenSSL 或想要更简便的操作流程,官方提供了在线签名生成工具。该工具是一个基于 WebAssembly 编写的 Web 应用,可以在浏览器环境中直接生成 pem 格式的私钥和证书,无需将签名文件和密码上传到远程服务器。步骤:上传 p12 文件并输入对应的密码;点击"生成签名"按钮,等待签名生成成功弹窗;点击"下载签名"按钮,下载 pem 格式的私钥和证书。
- 快应用需要将生成的私钥
private.pem和证书certificate.pem放在快应用根目录/sign/debug和/sign/release下出包测试。 - 真机测试时建议先输入包名 uninstall 老包再安装新包,可以观察桌面图标卸载(卸载会删除应用图标)保证彻底替换。
官方参考附录:小米穿戴第三方 APP 能力开放接口文档、interconnect 开发测试 demo(见官方文档页下载链接)。
机型支持明细
| 设备产品 | 说明 |
|---|---|
| 小米 S1 Pro 运动健康手表 | 支持 |
| 小米手环 8 Pro | 支持 |
| 小米手环 9 / 9 Pro | 支持 |
| Xiaomi Watch S3 | 支持 |
| Redmi Watch 4 | 支持 |
| 小米腕部心电血压记录仪 | 支持 |
| 小米手环 10 | 支持 |
| 小米手环 10 Pro | 支持 |
| Xiaomi Watch S4 | 支持 |
| REDMI Watch 5 | 支持 |
| REDMI Watch 6 | 支持 |
| Xiaomi Watch S5 | 支持 |
源码
openvela 快应用代码仓库:openvela/frameworks/runtimes/feature/(JIDL 接口与 Native 实现)、openvela/packages/(使用示例);引擎内置 Feature 预编译于 libquickappfeatures。
参考来源
- Vela官方快应用开发文档
- 洛汐文档库
- openvela快应用代码仓库:
openvela/frameworks/、openvela/packages/