近期正好业务涉及到星闪模块,就写个学习文档吧。

各位看官们点个赞,走过路过不要错过

本文档将详细描述了基于 OpenHarmony 的星闪(StarLink Express, SLE)设备发现、连接和交互的完整流程。

流程概览

检测星闪状态 → 请求权限 → 开始扫描 → 发现设备 → 连接设备 → 获取服务 → 数据交互

第一步:检测星闪是否打开

接口说明

项目

说明

方法

​manager.getState()​

所属模块

​@kit.NearLinkKit​​​ 中的 ​​manager​

返回类型

​manager.NearlinkState​

返回值说明

返回值

枚举名称

含义

0

​STATE_OFF​

已关闭

1

​STATE_TURNING_ON​

正在打开

2

​STATE_ON​

已打开

3

​STATE_TURNING_OFF​

正在关闭

代码示例
import { manager } from '@kit.NearLinkKit';

export function getSleState(): manager.NearlinkState {
  let sleState = manager.NearlinkState.STATE_OFF;
  try {
    sleState = manager.getState();
    console.debug(`当前星闪状态: ${sleState}`);
  } catch (err) {
    // 无权限或其他异常
    console.error(`getSleState errCode: ${err.code}, errMessage: ${err.message}`);
  }
  return sleState;
}
状态判断逻辑
const state = getSleState();
if (state === manager.NearlinkState.STATE_ON) {
  // 星闪已打开,可以进行下一步操作
} else if (state === manager.NearlinkState.STATE_TURNING_ON) {
  // 星闪正在打开,等待状态变化
} else {
  // 星闪未打开,需要引导用户开启
}

第二步:监听星闪状态变化

接口说明

项目

说明

方法

​manager.on('stateChange', callback)​

所属模块

​@kit.NearLinkKit​​​ 中的 ​​manager​

回调参数

​state: manager.NearlinkState​

取消监听

​manager.off('stateChange')​

代码示例
import { manager } from '@kit.NearLinkKit';

export async function enableSle(bleOnCallback: Function = null) {
  manager.on('stateChange', state => {
    if (state == manager.NearlinkState.STATE_ON) {
      manager.off('stateChange');  // 状态已开启,取消监听
      if (bleOnCallback) {
        bleOnCallback();
      }
    }
    console.debug(`星闪状态变化: ${state}`);
  });
}

第三步:请求星闪访问权限

接口说明

项目

说明

方法

​abilityAccessCtrl.createAtManager().requestPermissionsFromUser()​

所属模块

​@kit.AbilityKit​

所需权限

​ohos.permission.ACCESS_NEARLINK​

返回值

​Promise<PermissionRequestResult>​

权限结果说明

authResults值

含义

0

用户同意授权

-1

用户拒绝授权

代码示例
import { abilityAccessCtrl, common, Permissions } from '@kit.AbilityKit';
import { BusinessError } from '@kit.BasicServicesKit';

const permissions: Array<Permissions> = ['ohos.permission.ACCESS_NEARLINK'];

function reqPermissionsFromUser(permissions: Array<Permissions>, context: common.UIAbilityContext): void {
  let atManager: abilityAccessCtrl.AtManager = abilityAccessCtrl.createAtManager();
  
  atManager.requestPermissionsFromUser(context, permissions).then((data) => {
    let grantStatus: Array<number> = data.authResults;
    let length: number = grantStatus.length;
    for (let i = 0; i < length; i++) {
      if (grantStatus[i] === 0) {
        // 用户授权成功,可以继续访问星闪功能
        console.info('权限授权成功');
      } else {
        // 用户拒绝授权,需引导用户到系统设置开启权限
        console.warn('用户拒绝授权');
        return;
      }
    }
  }).catch((err: BusinessError) => {
    console.error(`请求权限失败. Code: ${err.code}, Message: ${err.message}`);
  });
}

第四步:开始扫描设备

接口说明

项目

说明

注册扫描回调

​scan.on('deviceFound', callback)​

开始扫描

​scan.startScan(filters, options)​

停止扫描

​scan.stopScan()​

取消回调

​scan.off('deviceFound')​

所属模块

​@kit.NearLinkKit​​​ 中的 ​​scan​

扫描过滤器 (ScanFilters)

字段

类型

说明

​deviceName​

string

按设备名称过滤

扫描选项 (ScanOptions)

字段

类型

说明

​scanMode​

number

扫描模式

扫描模式说明

枚举名称

说明

0

​SCAN_MODE_LOW_POWER​

低功耗模式

1

​SCAN_MODE_LOW_LATENCY​

低延迟模式

2

​SCAN_MODE_BALANCED​

平衡模式

扫描结果 (ScanResults)

字段

类型

说明

​deviceName​

string

设备名称

​address​

string

设备地址(MAC)

​rssi​

number

信号强度

​isConnectable​

boolean

是否可连接

代码示例
import { scan } from '@kit.NearLinkKit';
import { BusinessError } from '@kit.BasicServicesKit';

@State scanResults: Array<scan.ScanResults> = [];
@State isScanning: boolean = false;

startScan() {
  // 清空之前的扫描结果
  this.scanResults = [];
  this.isScanning = true;

  // 1. 注册扫描结果回调
  scan.on('deviceFound', (data: Array<scan.ScanResults>) => {
    for (let i = 0; i < data.length; i++) {
      let device = data[i];
      // 检查设备是否已存在(根据地址判断去重)
      let exists = this.scanResults.some(item => item.address === device.address);
      if (!exists) {
        this.scanResults.push(device);
        console.info(`发现设备: ${device.deviceName}, 地址: ${device.address}`);
      }
    }
  });

  // 2. 配置扫描过滤器(可选)
  let scanFilter: scan.ScanFilters = {};
  // scanFilter.deviceName = "设备名称";  // 可选:按名称过滤

  // 3. 配置扫描选项
  let scanOptions: scan.ScanOptions = {
    scanMode: 2  // SCAN_MODE_BALANCED
  };

  // 4. 开始扫描
  scan.startScan([scanFilter], scanOptions)
    .then(() => {
      console.info('扫描已开始');
    })
    .catch((err: BusinessError) => {
      console.error(`扫描启动失败. errCode: ${err.code}, errMessage: ${err.message}`);
      this.isScanning = false;
    });
}

stopScan() {
  scan.stopScan()
    .then(() => {
      console.info('扫描已停止');
      this.isScanning = false;
    })
    .catch((err: BusinessError) => {
      console.error(`停止扫描失败. errCode: ${err.code}, errMessage: ${err.message}`);
    });
  
  // 取消监听
  scan.off('deviceFound');
}

第五步:连接设备

接口说明

项目

说明

创建客户端

​ssap.createClient(address)​

连接设备

​client.connect()​

断开连接

​client.disconnect()​

关闭客户端

​client.close()​

所属模块

​@kit.NearLinkKit​​​ 中的 ​​ssap​

连接状态监听

项目

说明

注册回调

​client.on('connectionStateChange', callback)​

回调参数

​data: ssap.ConnectionChangeState​

取消监听

​client.off('connectionStateChange')​

连接状态说明

枚举名称

说明

0

​STATE_DISCONNECTED​

已断开

1

​STATE_CONNECTING​

正在连接

2

​STATE_CONNECTED​

已连接

3

​STATE_DISCONNECTING​

正在断开

代码示例
import { ssap, constant } from '@kit.NearLinkKit';
import { BusinessError } from '@kit.BasicServicesKit';

let client: ssap.Client | undefined = undefined;

async function connectDevice(address: string) {
  try {
    // 1. 创建客户端
    client = ssap.createClient(address);

    // 2. 注册连接状态变化回调
    client.on('connectionStateChange', (data: ssap.ConnectionChangeState) => {
      if (data.state === constant.ConnectionState.STATE_CONNECTED) {
        console.info('设备已连接');
        // 连接成功后获取服务
        getServices();
      } else if (data.state === constant.ConnectionState.STATE_DISCONNECTED) {
        console.info('设备已断开');
        client?.close();
        client = undefined;
      }
    });

    // 3. 发起连接
    await client.connect();
    console.info('连接请求已发送');

  } catch (err) {
    console.error(`连接失败. errCode: ${(err as BusinessError).code}, errMessage: ${(err as BusinessError).message}`);
  }
}

async function disconnectDevice() {
  try {
    await client?.disconnect();
    client?.off('connectionStateChange');
    client?.close();
    client = undefined;
  } catch (err) {
    console.error(`断开连接失败. errCode: ${(err as BusinessError).code}`);
  }
}

第六步:获取服务列表

接口说明

项目

说明

方法

​client.getServices()​

返回类型

​Promise<Array<ssap.Service>>​

服务结构 (Service)

字段

类型

说明

​serviceUuid​

string

服务UUID

​properties​

Array\<Property\>

属性列表

属性结构 (Property)

字段

类型

说明

​serviceUuid​

string

所属服务UUID

​propertyUuid​

string

属性UUID

​operation​

number

支持的操作

​value​

ArrayBuffer

属性值

​descriptors​

Array

描述符列表

代码示例
let services: Array<ssap.Service> = [];

async function getServices() {
  try {
    const result = await client?.getServices();
    if (result) {
      services = result;
      console.info('获取服务成功: ' + JSON.stringify(result));
      
      // 遍历服务和属性
      services.forEach(service => {
        console.info(`服务UUID: ${service.serviceUuid}`);
        service.properties.forEach(property => {
          console.info(`  属性UUID: ${property.propertyUuid}`);
        });
      });
    }
  } catch (err) {
    console.error(`获取服务失败. errCode: ${(err as BusinessError).code}`);
  }
}

第七步:数据交互

7.1 读取属性

项目

说明

方法

​client.readProperty(property)​

参数

​property: ssap.Property​

返回类型

​Promise<ssap.Property>​

async function readProperty(property: ssap.Property) {
  try {
    const result = await client?.readProperty(property);
    if (result && result.value) {
      const data = new Uint8Array(result.value);
      console.info(`读取结果: ${Array.from(data).join(',')}`);
    }
  } catch (err) {
    console.error(`读取属性失败. errCode: ${(err as BusinessError).code}`);
  }
}
7.2 写入属性

项目

说明

方法

​client.writeProperty(property, writeType)​

写入类型

​ssap.PropertyWriteType​

写入类型

说明

​WRITE​

写入并等待响应

​WRITE_NO_RESPONSE​

写入不等待响应

async function writeProperty(property: ssap.Property) {
  try {
    await client?.writeProperty(property, ssap.PropertyWriteType.WRITE_NO_RESPONSE);
    console.info('写入成功');
  } catch (err) {
    console.error(`写入属性失败. errCode: ${(err as BusinessError).code}`);
  }
}
7.3 订阅属性通知

项目

说明

设置通知

​client.setPropertyNotification(property, enable)​

监听变化

​client.on('propertyChange', callback)​

取消监听

​client.off('propertyChange')​

async function subscribeProperty(property: ssap.Property) {
  // 注册属性变化回调
  client?.on('propertyChange', (data: ssap.Property) => {
    console.info('属性变化: ' + JSON.stringify(data));
    if (data.value) {
      const value = new Uint8Array(data.value);
      console.info(`通知数据: ${Array.from(value).join(',')}`);
    }
  });

  // 开启通知
  try {
    await client?.setPropertyNotification(property, true);
    console.info('订阅通知成功');
  } catch (err) {
    console.error(`订阅通知失败. errCode: ${(err as BusinessError).code}`);
  }
}

完整流程时序图

┌──────────┐     ┌──────────┐     ┌──────────┐     ┌──────────┐
│   APP    │     │  manager │     │   scan   │     │   ssap   │
└────┬─────┘     └────┬─────┘     └────┬─────┘     └────┬─────┘
     │                │                │                │
     │  getState()    │                │                │
     │───────────────>│                │                │
     │  返回状态(0-3) │                │                │
     │<───────────────│                │                │
     │                │                │                │
     │  on('stateChange')              │                │
     │───────────────>│                │                │
     │                │                │                │
     │  requestPermissions             │                │
     │────────────────────────────────>│                │
     │  authResults                    │                │
     │<────────────────────────────────│                │
     │                │                │                │
     │  on('deviceFound')              │                │
     │────────────────────────────────>│                │
     │  startScan()   │                │                │
     │────────────────────────────────>│                │
     │  ScanResults[] │                │                │
     │<────────────────────────────────│                │
     │  stopScan()    │                │                │
     │────────────────────────────────>│                │
     │                │                │                │
     │  createClient(address)          │                │
     │─────────────────────────────────────────────────>│
     │  client        │                │                │
     │<─────────────────────────────────────────────────│
     │  connect()     │                │                │
     │─────────────────────────────────────────────────>│
     │  ConnectionState                │                │
     │<─────────────────────────────────────────────────│
     │  getServices() │                │                │
     │─────────────────────────────────────────────────>│
     │  Service[]     │                │                │
     │<─────────────────────────────────────────────────│
     │  read/write/subscribe           │                │
     │─────────────────────────────────────────────────>│
     │                │                │                │

关键模块依赖

import { manager, scan, ssap, constant } from '@kit.NearLinkKit';
import { abilityAccessCtrl, common, Permissions } from '@kit.AbilityKit';
import { BusinessError } from '@kit.BasicServicesKit';

错误处理建议

  1. 权限未授予: 引导用户到系统设置页面手动开启权限
  2. 星闪未开启: 提示用户开启星闪功能或监听状态变化
  3. 扫描超时: 建议设置扫描超时时间(如20秒),超时后自动停止扫描
  4. 连接失败: 检查设备是否在范围内,重试连接
  5. 服务获取失败: 确保连接成功后再获取服务,可适当延迟获取

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐