npm package: @leir0ng/uniapp-ble-sdk
Description: A comprehensive BLE (Bluetooth Low Energy) SDK for uniapp with connection management, device discovery, and data handling
Author: 2970665812@qq.com
Latest version: 1.0.4

# uniapp-ble-sdk

一个功能完整的 UniApp 蓝牙低功耗 (BLE) SDK，提供设备搜索、连接管理、数据传输等完整功能。
如果你想用测试可以参考https://gitee.com/lei_rong/uniapp-ble-sdk-test-v这里是uniapp测试工程[直接下载运行就行]

## 特性

- 🔄 **自动重连**: 支持连接断开后自动重连
- 🔍 **设备搜索**: 支持过滤条件的设备搜索
- 📡 **连接管理**: 完整的连接状态管理和监听
- 📊 **数据传输**: 支持特征值读写和通知
- 🛡️ **错误处理**: 完善的错误处理和事件回调
- 📱 **跨平台**: 支持 App、微信小程序等平台
- 🎯 **TypeScript**: 完整的 TypeScript 支持

## 安装

```bash
npm install uniapp-ble-sdk
```

## 快速开始

### 基础使用

```typescript
import { BLEManager, BLEEventType, ConnectionState } from 'uniapp-ble-sdk';

// 创建BLE管理器实例
const bleManager = new BLEManager({
  autoReconnect: true,
  reconnectInterval: 3000,
  maxReconnectAttempts: 5
});

// 初始化
await bleManager.initialize();

// 监听事件
bleManager.on(BLEEventType.DEVICE_FOUND, (device) => {
  console.log('发现设备:', device);
});

bleManager.on(BLEEventType.CONNECTION_STATE_CHANGE, (event) => {
  console.log('连接状态变化:', event);
});

// 开始搜索设备
await bleManager.startDeviceDiscovery({
  nameKeyword: 'MyDevice',
  minRSSI: -80
});

// 连接设备
await bleManager.connect('device-id');

// 获取服务和特征值
const services = await bleManager.getDeviceServices();
const characteristics = await bleManager.getDeviceCharacteristics(serviceId);

// 启用通知
await bleManager.notifyCharacteristicValueChange(serviceId, characteristicId);

// 监听数据
bleManager.on(BLEEventType.CHARACTERISTIC_VALUE_CHANGE, (data) => {
  console.log('收到数据:', data);
});

// 写入数据
const buffer = new ArrayBuffer(4);
await bleManager.writeCharacteristicValue(serviceId, characteristicId, buffer);

// 断开连接
await bleManager.disconnect();

// 销毁管理器
await bleManager.destroy();
```

## API 文档

### BLEManager

主要的 BLE 管理类。

#### 构造函数

```typescript
constructor(options?: BLEOptions)
```

**参数:**

- `options` - 可选配置项

```typescript
interface BLEOptions {
  allowDuplicatesKey?: boolean;     // 是否允许重复上报同一设备，默认 false
  interval?: number;                // 上报设备间隔(ms)，默认 0
  autoReconnect?: boolean;          // 是否启用自动重连，默认 true
  reconnectInterval?: number;       // 重连间隔(ms)，默认 3000
  maxReconnectAttempts?: number;    // 最大重连次数，默认 5
  connectionTimeout?: number;       // 连接超时时间(ms)，默认 10000
}
```

#### 方法

##### initialize(): Promise<void>

初始化蓝牙适配器。

```typescript
await bleManager.initialize();
```

##### destroy(): Promise<void>

销毁管理器，关闭所有连接和监听。

```typescript
await bleManager.destroy();
```

##### getAdapterState(): Promise<BluetoothAdapterState>

获取蓝牙适配器状态。

```typescript
const state = await bleManager.getAdapterState();
console.log('蓝牙可用:', state.available);
console.log('正在搜索:', state.discovering);
```

##### startDeviceDiscovery(filter?: DeviceFilter): Promise<void>

开始搜索蓝牙设备。

```typescript
// 搜索所有设备
await bleManager.startDeviceDiscovery();

// 使用过滤器搜索
await bleManager.startDeviceDiscovery({
  nameKeyword: 'sensor',
  minRSSI: -70,
  services: ['180F'] // 电池服务
});
```

##### stopDeviceDiscovery(): Promise<void>

停止搜索蓝牙设备。

```typescript
await bleManager.stopDeviceDiscovery();
```

##### getDiscoveredDevices(): BLEDevice[]

获取已发现的设备列表。

```typescript
const devices = bleManager.getDiscoveredDevices();
```

##### connect(deviceId: string): Promise<void>

连接到指定设备。

```typescript
await bleManager.connect('device-id-123');
```

##### disconnect(): Promise<void>

断开当前连接。

```typescript
await bleManager.disconnect();
```

##### getDeviceServices(deviceId?: string): Promise<BLEService[]>

获取设备服务列表。

```typescript
const services = await bleManager.getDeviceServices();
```

##### getDeviceCharacteristics(serviceId: string, deviceId?: string): Promise<BLECharacteristic[]>

获取设备特征值列表。

```typescript
const characteristics = await bleManager.getDeviceCharacteristics('180F');
```

##### getDeviceRSSI(deviceId?: string): Promise<number>

获取设备信号强度。

```typescript
const rssi = await bleManager.getDeviceRSSI();
```

##### notifyCharacteristicValueChange(serviceId: string, characteristicId: string, state?: boolean, deviceId?: string): Promise<void>

启用或禁用特征值变化通知。

```typescript
// 启用通知
await bleManager.notifyCharacteristicValueChange(serviceId, characteristicId, true);

// 禁用通知
await bleManager.notifyCharacteristicValueChange(serviceId, characteristicId, false);
```

##### readCharacteristicValue(serviceId: string, characteristicId: string, deviceId?: string): Promise<ArrayBuffer>

读取特征值。

```typescript
const data = await bleManager.readCharacteristicValue(serviceId, characteristicId);
```

##### writeCharacteristicValue(serviceId: string, characteristicId: string, value: ArrayBuffer, writeType?: WriteType, deviceId?: string): Promise<void>

写入特征值。

```typescript
const buffer = new ArrayBuffer(4);
const view = new DataView(buffer);
view.setUint32(0, 1234, true);

await bleManager.writeCharacteristicValue(
  serviceId, 
  characteristicId, 
  buffer, 
  WriteType.WRITE
);
```

##### setMTU(mtu: number, deviceId?: string): Promise<void>

设置最大传输单元 (22-512)。

```typescript
await bleManager.setMTU(247);
```

##### getConnectionState(): ConnectionState

获取当前连接状态。

```typescript
const state = bleManager.getConnectionState();
```

##### getConnectedDevice(): BLEDevice | null

获取当前连接的设备信息。

```typescript
const device = bleManager.getConnectedDevice();
```

#### 事件监听

##### on(event: string, callback: EventCallback): void

添加事件监听器。

```typescript
bleManager.on(BLEEventType.DEVICE_FOUND, (device) => {
  console.log('发现设备:', device);
});
```

##### off(event: string, callback?: EventCallback): void

移除事件监听器。

```typescript
bleManager.off(BLEEventType.DEVICE_FOUND, callback);
// 或移除所有监听器
bleManager.off(BLEEventType.DEVICE_FOUND);
```

### 事件类型

```typescript
enum BLEEventType {
  ADAPTER_STATE_CHANGE = 'adapterStateChange',           // 适配器状态变化
  DEVICE_FOUND = 'deviceFound',                          // 发现新设备
  CONNECTION_STATE_CHANGE = 'connectionStateChange',     // 连接状态变化
  CHARACTERISTIC_VALUE_CHANGE = 'characteristicValueChange', // 特征值变化
  ERROR = 'error'                                        // 错误事件
}
```

### 连接状态

```typescript
enum ConnectionState {
  DISCONNECTED = 'disconnected',       // 未连接
  CONNECTING = 'connecting',           // 连接中
  CONNECTED = 'connected',             // 已连接
  DISCONNECTING = 'disconnecting'      // 断开连接中
}
```

### 写入类型

```typescript
enum WriteType {
  WRITE = 'write',                     // 需要回复
  WRITE_NO_RESPONSE = 'writeNoResponse' // 不需要回复
}
```

## 完整示例

### Vue 3 组件示例

```vue
<template>
  <view class="ble-demo">
    <button @click="initBLE">初始化蓝牙</button>
    <button @click="startScan" :disabled="!isInitialized">开始扫描</button>
    <button @click="stopScan">停止扫描</button>
    
    <view class="device-list">
      <view 
        v-for="device in devices" 
        :key="device.deviceId"
        class="device-item"
        @click="connectDevice(device.deviceId)"
      >
        <text>{{ device.name || device.localName || '未知设备' }}</text>
        <text>{{ device.RSSI }}dBm</text>
      </view>
    </view>
    
    <view v-if="connectedDevice" class="connected-info">
      <text>已连接: {{ connectedDevice.name }}</text>
      <button @click="sendData">发送数据</button>
      <button @click="disconnect">断开连接</button>
    </view>
    
    <view class="logs">
      <text v-for="log in logs" :key="log.id">{{ log.message }}</text>
    </view>
  </view>
</template>

<script setup lang="ts">
import { ref, onUnmounted } from 'vue';
import { BLEManager, BLEEventType, ConnectionState, type BLEDevice } from 'uniapp-ble-sdk';

const bleManager = new BLEManager({
  autoReconnect: true,
  reconnectInterval: 3000,
  maxReconnectAttempts: 3
});

const isInitialized = ref(false);
const devices = ref<BLEDevice[]>([]);
const connectedDevice = ref<BLEDevice | null>(null);
const logs = ref<Array<{ id: number, message: string }>>([]);
let logId = 0;

// 添加日志
const addLog = (message: string) => {
  logs.value.push({
    id: logId++,
    message: `${new Date().toLocaleTimeString()}: ${message}`
  });
  if (logs.value.length > 100) {
    logs.value.shift();
  }
};

// 初始化蓝牙
const initBLE = async () => {
  try {
    await bleManager.initialize();
    isInitialized.value = true;
    addLog('蓝牙初始化成功');
    
    // 设置事件监听
    setupEventListeners();
  } catch (error) {
    addLog(`蓝牙初始化失败: ${error.message}`);
  }
};

// 设置事件监听
const setupEventListeners = () => {
  bleManager.on(BLEEventType.DEVICE_FOUND, (device: BLEDevice) => {
    const existingIndex = devices.value.findIndex(d => d.deviceId === device.deviceId);
    if (existingIndex >= 0) {
      devices.value[existingIndex] = device;
    } else {
      devices.value.push(device);
    }
    addLog(`发现设备: ${device.name || device.localName || device.deviceId}`);
  });
  
  bleManager.on(BLEEventType.CONNECTION_STATE_CHANGE, (event) => {
    addLog(`连接状态: ${event.deviceId} - ${event.state}`);
    if (event.state === ConnectionState.CONNECTED) {
      connectedDevice.value = bleManager.getConnectedDevice();
    } else if (event.state === ConnectionState.DISCONNECTED) {
      connectedDevice.value = null;
    }
  });
  
  bleManager.on(BLEEventType.CHARACTERISTIC_VALUE_CHANGE, (data) => {
    const view = new DataView(data.value);
    addLog(`收到数据: ${Array.from(new Uint8Array(data.value)).map(b => b.toString(16).padStart(2, '0')).join(' ')}`);
  });
  
  bleManager.on(BLEEventType.ERROR, (error) => {
    addLog(`错误: ${error.errMsg}`);
  });
};

// 开始扫描
const startScan = async () => {
  try {
    devices.value = [];
    await bleManager.startDeviceDiscovery({
      minRSSI: -80
    });
    addLog('开始扫描设备');
  } catch (error) {
    addLog(`开始扫描失败: ${error.message}`);
  }
};

// 停止扫描
const stopScan = async () => {
  try {
    await bleManager.stopDeviceDiscovery();
    addLog('停止扫描');
  } catch (error) {
    addLog(`停止扫描失败: ${error.message}`);
  }
};

// 连接设备
const connectDevice = async (deviceId: string) => {
  try {
    await bleManager.connect(deviceId);
    addLog(`连接设备: ${deviceId}`);
    
    // 获取服务和特征值
    const services = await bleManager.getDeviceServices();
    addLog(`发现 ${services.length} 个服务`);
    
    // 这里可以根据具体需求处理服务和特征值
    // 例如启用某个特征值的通知
    if (services.length > 0) {
      const characteristics = await bleManager.getDeviceCharacteristics(services[0].uuid);
      addLog(`服务 ${services[0].uuid} 有 ${characteristics.length} 个特征值`);
      
      // 查找可通知的特征值
      const notifyChar = characteristics.find(c => c.properties.notify);
      if (notifyChar) {
        await bleManager.notifyCharacteristicValueChange(services[0].uuid, notifyChar.uuid);
        addLog(`启用特征值通知: ${notifyChar.uuid}`);
      }
    }
  } catch (error) {
    addLog(`连接失败: ${error.message}`);
  }
};

// 发送数据
const sendData = async () => {
  try {
    const device = bleManager.getConnectedDevice();
    if (!device) return;
    
    const services = await bleManager.getDeviceServices();
    if (services.length === 0) return;
    
    const characteristics = await bleManager.getDeviceCharacteristics(services[0].uuid);
    const writeChar = characteristics.find(c => c.properties.write || c.properties.writeNoResponse);
    
    if (writeChar) {
      const buffer = new ArrayBuffer(4);
      const view = new DataView(buffer);
      view.setUint32(0, Date.now() % 10000, true);
      
      await bleManager.writeCharacteristicValue(services[0].uuid, writeChar.uuid, buffer);
      addLog('数据发送成功');
    } else {
      addLog('未找到可写特征值');
    }
  } catch (error) {
    addLog(`发送数据失败: ${error.message}`);
  }
};

// 断开连接
const disconnect = async () => {
  try {
    await bleManager.disconnect();
    addLog('主动断开连接');
  } catch (error) {
    addLog(`断开连接失败: ${error.message}`);
  }
};

// 组件销毁时清理
onUnmounted(async () => {
  await bleManager.destroy();
});
</script>

<style scoped>
.ble-demo {
  padding: 20px;
}

.device-list {
  margin: 20px 0;
}

.device-item {
  display: flex;
  justify-content: space-between;
  padding: 10px;
  border: 1px solid #eee;
  margin-bottom: 5px;
  border-radius: 5px;
}

.connected-info {
  background-color: #e8f5e8;
  padding: 10px;
  border-radius: 5px;
  margin: 10px 0;
}

.logs {
  max-height: 300px;
  overflow-y: auto;
  background-color: #f5f5f5;
  padding: 10px;
  border-radius: 5px;
  font-family: monospace;
  font-size: 12px;
}
</style>
```

## 注意事项

1. **权限配置**: 确保在 `manifest.json` 中配置了蓝牙权限：

```json
{
  "mp-weixin": {
    "permission": {
      "scope.bluetooth": {
        "desc": "用于连接蓝牙设备"
      }
    }
  },
  "app-plus": {
    "modules": {
      "Bluetooth": {}
    }
  }
}
```

2. **平台差异**: 不同平台对BLE支持可能有差异，建议在目标平台上充分测试。

3. **连接管理**: 建议在应用退出或页面销毁时主动断开连接和销毁管理器。

4. **错误处理**: 蓝牙操作可能因为各种原因失败，建议完善错误处理逻辑。

5. **性能优化**: 大量数据传输时注意控制频率，避免造成性能问题。

## 许可证

MIT License

## 贡献

欢迎提交 Issue 和 Pull Request！

## 更新日志

### 1.0.0
- 初始版本发布
- 支持基础的BLE功能
- 自动重连机制
- 完整的事件系统
- TypeScript 支持