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

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

本文档将详细描述了基于 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

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐