更新记录
1.0.0(2025-03-22)
经过大量用户数月使用,根据反馈完成全面测试和优化,发布初始版本。
平台兼容性
Vue2 | Vue3 |
---|---|
× | √ |
App | 快应用 | 微信小程序 | 支付宝小程序 | 百度小程序 | 字节小程序 | QQ小程序 |
---|---|---|---|---|---|---|
HBuilderX 4.56,Android:8.0,iOS:12,HarmonyNext:不支持 | × | × | × | × | × | × |
钉钉小程序 | 快手小程序 | 飞书小程序 | 京东小程序 | 鸿蒙元服务 |
---|---|---|---|---|
× | × | × | × | × |
H5-Safari | Android Browser | 微信浏览器(Android) | QQ浏览器(Android) | Chrome | IE | Edge | Firefox | PC-Safari |
---|---|---|---|---|---|---|---|---|
× | × | × | × | × | × | × | × | × |
dry-bluetooth
- 实现 iOS 和 Android 低功耗蓝牙功能: 扫描、连接、订阅特征、收发数据,本插件是中心设备(Central)
- 插件内部提供了 iOS 和 Android 蓝牙权限检查接口,使用方便快捷
- 在商业项目中经过数月使用,通过大量用户的真实数据反馈,进行不间断的优化后,可靠实用
权限描述配置
- Android 权限已在 AndroidManifest.xml 中配置好,无需更改
- iOS 更具实际需要在 uni_modules -> dry-bluetooth -> utssdk -> app-ios -> Info.plist 中,将申请权限描述改为实际内容:
- iOS 如不需要后台使用蓝牙功能,可将 UIBackgroundModes 包含的内容删除
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>NSBluetoothPeripheralUsageDescription</key> <string>应用程序需要通过蓝牙xxx,是否允许访问蓝牙?</string> <key>NSBluetoothAlwaysUsageDescription</key> <string>应用程序需要通过蓝牙xxx,是否允许访问蓝牙?</string> <key>UIBackgroundModes</key> <array> <string>bluetooth-central</string> <string>bluetooth-peripheral</string> <string>fetch</string> </array> </dict> </plist>
返回码 / type / 回调
[1] 返回码
// 返回码
export type DryBleCode =
| '-1' // 其他异常
| '0' // 成功
| '10001' // 未初始化蓝牙适配器
| '10002' // 设备不支持蓝牙
| '10003' // 手机蓝牙未打开(iOS 系统自动弹窗提示跳转,android 需要自定义提示)
| '20001' // (iOS)未授权(可调用 uni.openAppAuthorizeSetting({}); 进入 App 权限页面)
| '20002' // (iOS)与系统服务的连接暂时丢失,即将更新
| '20003' // (iOS)状态未知,即将更新
| '30001' // 正在扫描外设中
| '40001' // 没有找到设备
| '40002' // 设备未连接(已断开)
| '40003' // 设备正在连接中
| '40004' // 设备已连接
| '40005' // 设备正在断开连接中
| '40006' // 设备连接失败
| '40007' // 设备断开连接失败
| '50001' // 超时
| '60001' // 未发现服务
| '70001' // 未发现特征
| '70002' // 特征不可订阅
| '70003' // 特征不可读
| '70004' // 特征不可写
[2] type
// 蓝牙外设
export type DryBleDevice = {
deviceId : string, // 设备id
name : string, // 设备名称
rssi : number, // 信号强度
advertisData : number[] | null, // 广播数据段中的 ManufacturerData 数据段
advertisServiceUUIDs : string[], // 广播数据段中的 ServiceUUIDs 数据段
localName : string, // 广播数据段中的 LocalName 数据段
serviceData : any | null // 广播数据段中的 ServiceData 数据段
};
// 服务
export type DryBleService = {
uuid : string, // 服务 uuid
isPrimary : boolean // 是否为主服务
};
export type DryBleServiceArray = {
services : DryBleService[]
};
// 特征
export type DryBleCharacter = {
uuid : string, // 征值 uuid
read : boolean, // 特征是否支持 read 操作
write : boolean, // 特征是否支持 write 操作
notify : boolean, // 特征是否支持 notify 操作
indicate : boolean // 特征是否支持 indicate 操作
};
export type DryBleCharacterArray = {
characters : DryBleCharacter[]
};
[3] 回调
// 回调(返回码)
export type DryBleCodeCallback = (code : DryBleCode) => void;
// 回调(设备)
export type DryBleDeviceCallback = (device : DryBleDevice) => void;
// 回调(设备id,连接状态[true:连接;false:断开])
export type DryBleConnectStateCallback = (deviceId : string, state : boolean) => void;
// 回调(服务)
export type DryBleServiceCallback = (code : DryBleCode, services : DryBleServiceArray) => void;
// 回调(特征)
export type DryBleCharacterCallback = (code : DryBleCode, characters : DryBleCharacterArray) => void;
// 回调(特征值变化[设备id,服务id,特征id,特征值])
export type DryBleCharacterValueChangeCallback = (deviceId : string, serviceId : string, characterId : string, value : number[]) => void;
接口
/**
* 请求权限(仅 Android)
* - Android 11及以下权限: ACCESS_FINE_LOCATION
* - Android 12及以上权限: BLUETOOTH_SCAN,BLUETOOTH_CONNECT
* @param {Function} callback 回调
* 0: 成功
* -1: 未能获取到 API Level 版本
* -2: 权限被拒绝
* -3: 权限被拒绝,且被禁止再次询问,需要引导用户手动打开权限设置页面
*/
dry_ble_request_android_permission(callback : (code : number) => void);
/**
* 请求权限(仅 iOS)
* - NSBluetoothPeripheralUsageDescription,NSBluetoothAlwaysUsageDescription
* @param {Function} callback 回调
* 0: 成功
* -1: 尚未申请权限
* -2: 没有配置蓝牙权限描述
* -3: 权限已被拒绝,无法再次申请,需要引导用户手动打开权限设置页面
*/
dry_ble_request_ios_permission(callback : (code : number) => void);
/**
* 适配器状态
* @returns {DryBleCode} 适配器当前状态
* - 正常: '0'
* - 异常: '-1' | '10001' | '10002' | '10003' | '20001' | '20002' | '20003'
*/
dry_ble_adapter_state() : DryBleCode;
/**
* 打开适配器(必须先获取蓝牙权限)
* @param {DryBleCodeCallback} callback 回调(适配器当前状态,仅回调一次)
* - 正常: '0'
* - 异常: '-1' | '10001' | '10002' | '10003' | '20001' | '20002' | '20003'
*/
dry_ble_open_adapter(callback : DryBleCodeCallback) : void;
/**
* 关闭适配器
*/
dry_ble_close_adapter() : void;
/**
* 监听适配器状态
* - 注意: 不用时,一定要使用 dry_ble_off_adapter_state_change 释放
* @param {DryBleCodeCallback} callback 回调(适配器当前状态,持续监听)
* - 正常: '0'
* - 异常: '-1' | '10001' | '10002' | '10003' | '20001' | '20002' | '20003'
*/
dry_ble_on_adapter_state_change(callback : DryBleCodeCallback) : void;
/**
* 注销监听适配器状态
*/
dry_ble_off_adapter_state_change() : void;
/**
* 是否正在扫描
* @returns {boolean} 是否正在扫描
*/
dry_ble_is_scanning() : boolean;
/**
* 启动扫描(必须先获取蓝牙权限,并成功打开蓝牙适配器)
* - 接口调用成功后,在 dry_ble_on_device_found 监听设备回调
* @param {string[]} services 要搜索设备的服务 uuid
* @param {boolean} repeats 是否重复上报相同设备
* @param {DryBleCodeCallback} callback 回调(启动扫描是否成功)
* - 正常: '0'
* - 异常: '-1' | '10001' | '10002' | '10003' | '20001' | '20002' | '20003' | '30001'
*/
dry_ble_start_scan_devices(services : string[], repeats : boolean, callback : DryBleCodeCallback) : void ;
/**
* 停止扫描
*/
dry_ble_stop_scan_devices() : void;
/**
* 监听扫描设备事件
* - 注意: 不用时,一定要使用 dry_ble_off_device_found 释放
* @param {DryBleDeviceCallback} callback 回调(设备)
*/
dry_ble_on_device_found(callback : DryBleDeviceCallback) : void;
/**
* 注销监听扫描设备事件
*/
dry_ble_off_device_found() : void;
/**
* 连接(必须先获取蓝牙权限,并成功打开蓝牙适配器)
* @param {string} deviceId 设备id
* @param {number} timeout 连接超时时间(毫秒,0代表不超时)
* @param {DryBleCodeCallback} callback 回调(连接是否成功)
* - 正常: '0'
* - 异常: '-1' | '10001' | '10002' | '10003' | '40001' | '40003' | '40004' | '40005' | '40006' | '50001'
*/
dry_ble_connect_device(deviceId : string, timeout : number, callback : DryBleCodeCallback) : void;
/**
* 断开连接
* @param {string} deviceId 设备id
* @param {number} timeout 连接超时时间(毫秒,0代表不超时)
* @param {DryBleCodeCallback} callback 回调(断开连接是否成功)
* - 正常: '0'
* - 异常: '-1' | '10001' | '10002' | '10003' | '20001' | '20002' | '20003' | '40001' | '40002' | '40003' | '40005' | '40007' | '50001'
*/
dry_ble_disconnect_device(deviceId : string, timeout : number, callback : DryBleCodeCallback) : void;
/**
* 监听连接状态
* - 注意: 不用时,一定要使用 dry_ble_off_connect_state_change 释放
* @param {DryBleConnectStateCallback} callback 回调(设备id,连接状态[true:连接;false:断开])
*/
dry_ble_on_connect_state_change(callback : DryBleConnectStateCallback) : void;
/**
* 注销监听连接状态
*/
dry_ble_off_connect_state_change() : void;
/**
* 获取服务(调用顺序: 连接 -> 获取服务)
* @param {string} deviceId 设备id
* @param {DryBleServiceCallback} callback 回调(服务)
* - 正常: '0'
* - 异常: '-1' | '10001' | '10002' | '10003' | '20001' | '20002' | '20003' | '40002'
*/
dry_ble_discover_services(deviceId : string, callback : DryBleServiceCallback);
/**
* 获取特征(调用顺序: 连接 -> 获取服务 -> 获取特征)
* @param {string} deviceId 设备id
* @param {string} serviceId 服务id
* @param {DryBleCharacterCallback} callback 回调(特征)
* - 正常: '0'
* - 异常: '-1' | '10001' | '10002' | '10003' | '20001' | '20002' | '20003' | '40002' | '60001'
*/
dry_ble_discover_characters(deviceId : string, serviceId : string, callback : DryBleCharacterCallback);
/**
* 订阅特征(调用顺序: 连接 -> 获取服务 -> 获取特征 -> 订阅特征)
* @param {string} deviceId 设备id
* @param {string} serviceId 服务id
* @param {string} characterId 特征id
* @param {DryBleCodeCallback} callback 回调(订阅特征是否成功)
* - 正常: '0'
* - 异常: '-1' | '10001' | '10002' | '10003' | '20001' | '20002' | '20003' | '40002' | '60001' | '70001' | '70002'
*/
dry_ble_notify_character(deviceId : string, serviceId : string, characterId : string, callback : DryBleCodeCallback);
/**
* 监听特征值变化
* @param {DryBleCharacterValueChangeCallback} callback 回调(特征值变化[设备id,服务id,特征id,特征值])
*/
dry_ble_on_character_value_change(callback : DryBleCharacterValueChangeCallback) : void;
/**
* 注销监听特征值变化
*/
dry_ble_off_character_value_change() : void;
/**
* 读特征值的二进制数据值(调用顺序: 连接 -> 获取服务 -> 获取特征 -> 读特征值的二进制数据值)
* @param {string} deviceId 设备id
* @param {string} serviceId 服务id
* @param {string} characterId 特征id
* @param {DryBleCodeCallback} callback 回调(接口是否调用成功)
* - 正常: '0'
* - 异常: '-1' | '10001' | '10002' | '10003' | '20001' | '20002' | '20003' | '40002' | '60001' | '70001' | '70003'
*/
dry_ble_read_character_value(deviceId : string,
serviceId : string,
characterId : string,
callback : DryBleCodeCallback) : void;
/**
* 向特征值中写入二进制数据(调用顺序: 连接 -> 获取服务 -> 获取特征 -> 订阅特征[可选] -> 读特征值的二进制数据值)
* @param {string} deviceId 设备id
* @param {string} serviceId 服务id
* @param {string} characterId 特征id
* @param {string} writeType 蓝牙特征值的写模式设置(write:强制回复写,writeNoResponse:强制无回复写)
* @param {number[]} value 二进制数据
* @param {DryBleCodeCallback} callback 回调
* - 正常: '0'
* - 异常: '-1' | '10001' | '10002' | '10003' | '20001' | '20002' | '20003' | '40002' | '60001' | '70001' | '70004'
*/
dry_ble_write_character_value(deviceId : string,
serviceId : string,
characterId : string,
writeType : 'write' | 'writeNoResponse',
value : number[],
callback : DryBleCodeCallback) : void;
引入 (type / 回调 / 接口) 到 uvue 和 uts 文件中,此处列出了所有,实际可按需引入
import {
// Type
DryBleCode, // 返回码
DryBleDevice, // 蓝牙外设
DryBleService, // 服务
DryBleServiceArray, // 服务集合
DryBleCharacter, // 特征
DryBleCharacterArray, // 特征集合
// 回调
DryBleCodeCallback,
DryBleDeviceCallback,
DryBleConnectStateCallback,
DryBleServiceCallback,
DryBleCharacterCallback,
DryBleCharacterValueChangeCallback,
// 接口
dry_ble_request_ios_permission, // iOS 请求(校验)权限
dry_ble_request_android_permission, // Android 请求(校验)权限
dry_ble_adapter_state, // 适配器状态
dry_ble_open_adapter, // 打开适配器
dry_ble_close_adapter, // 关闭适配器
dry_ble_on_adapter_state_change, // 监听适配器状态
dry_ble_off_adapter_state_change, // 注销监听适配器状态
dry_ble_is_scanning, // 是否正在扫描
dry_ble_start_scan_devices, // 启动扫描
dry_ble_stop_scan_devices, // 停止扫描
dry_ble_on_device_found, // 监听扫描设备事件
dry_ble_off_device_found, // 注销监听扫描设备事件
dry_ble_connect_device, // 连接
dry_ble_disconnect_device, // 断开连接
dry_ble_on_connect_state_change, // 监听连接状态
dry_ble_off_connect_state_change, // 注销监听连接状态
dry_ble_discover_services, // 获取服务
dry_ble_discover_characters, // 获取特征
dry_ble_notify_character, // 订阅特征
dry_ble_on_character_value_change, // 监听特征值变化
dry_ble_off_character_value_change, // 注销监听特征值变化
dry_ble_read_character_value, // 读特征值的二进制数据值
dry_ble_write_character_value // 向特征值中写入二进制数据
} from '@/uni_modules/dry-bluetooth';
接口使用示例
权限检查(用户可选择自行实现)
- iOS 权限: NSBluetoothPeripheralUsageDescription,NSBluetoothAlwaysUsageDescription
- Android 11及以下权限: ACCESS_FINE_LOCATION
- Android 12及以上权限: BLUETOOTH_SCAN,BLUETOOTH_CONNECT
// #ifdef APP-IOS dry_ble_request_ios_permission((code : number) => { if (code == 0) { console.log('已获取申请权限,可打开蓝牙适配器'); } else if (code == -1) { console.log('尚未申请权限,可打开蓝牙适配器'); } else if (code == -2) { console.log('没有配置蓝牙权限描述'); } else if (code == -3) { console.log('权限已被拒绝,无法再次申请,需要引导用户手动打开权限设置页面'); } }); // #endif // #ifdef APP-ANDROID dry_ble_request_android_permission((code : number) => { if (code == 0) { console.log('已获取申请权限,可打开蓝牙适配器'); } else if (code == -1) { console.log('未能获取到 API Level 版本'); } else if (code == -2) { console.log('权限被拒绝'); } else if (code == -3) { console.log('权限被拒绝,且被禁止再次询问,需要引导用户手动打开权限设置页面'); } }); // #endif
蓝牙适配器
1、监听蓝牙适配器状态
dry_ble_on_adapter_state_change((code : DryBleCode) => {
if (code == '0') {
console.log('蓝牙适配器状态: 有效');
} else {
console.log('蓝牙适配器状态: 无效');
}
});
2、注销监听蓝牙适配器状态
dry_ble_off_adapter_state_change();
3、打开蓝牙适配器(需先获取蓝牙权限)
dry_ble_open_adapter((code : DryBleCode) => {
if (code == '0') {
console.log('打开蓝牙适配器成功');
} else if (code == '10002') {
console.log('手机不支持蓝牙');
} else if (code == '10003') {
// iOS 系统自动弹窗提示跳转,android 需要自定义提示
console.log('手机蓝牙未打开');
} else {
console.log('打开蓝牙适配器成功');
}
});
4、关闭蓝牙适配器
dry_ble_close_adapter();
扫描蓝牙外设
1、监听蓝牙外设回调
dry_ble_on_device_found((device : DryBleDevice) => {
console.log('蓝牙外设的设备id', device,deviceId);
console.log('蓝牙外设的名称', device,name);
console.log('蓝牙外设的信号值', device,rssi);
});
2、注销监听蓝牙外设回调
dry_ble_off_device_found();
3、启动扫描
let services : string[] = []; // 要搜索设备的服务 uuid,默认为 [] 即不设置
let repeats : boolean = false; // 是否重复上报相同设备
dry_ble_start_scan_devices(services, repeats, (code : DryBleCode) => {
if (code == '0') {
console.log('扫描接口调用成功,在 dry_ble_off_device_found 中监听蓝牙外设回调');
} else {
console.log('扫描接口调用失败:', code);
}
});
4、停止扫描
dry_ble_stop_scan_devices();
5、扫描状态
if (dry_ble_is_scanning()) {
console.log('正在扫描中');
}
连接蓝牙外设
1、连接
const deviceId : string = ''; // 蓝牙外设的设备id
const timeout : number = 15000; // 超时时间(毫秒)
dry_ble_connect_device(deviceId, timeout, (code : DryBleCode) => {
if (code == '0') {
console.log('蓝牙外设已连接');
} else {
console.log('蓝牙外设连接失败:', code);
}
});
2、断开连接
const deviceId : string = ''; // 蓝牙外设的设备id
const timeout : number = 15000; // 超时时间(毫秒)
dry_ble_disconnect_device(deviceId, timeout, (code : DryBleCode) => {
if (code == '0') {
console.log('蓝牙外设已断开');
} else {
console.log('蓝牙外设断开失败:', code);
}
});
3、注册连接状态回调
dry_ble_on_connect_state_change((deviceId : string, state : boolean) => {
if (state) {
console.log('设备已连接:', deviceId);
} else {
console.log('设备已断开:', deviceId);
}
});
4、注销连接状态回调
dry_ble_off_connect_state_change();
查找服务
const deviceId : string = ''; // 蓝牙外设的设备id
dry_ble_discover_services(deviceId, (code : DryBleCode, arr : DryBleServiceArray) => {
if (code != '0') {
console.log('查找服务失败:', code);
} else {
const services : DryBleService[] = arr.services;
for (let i = 0; i < services.length; i++) {
const service : DryBleService = services[i];
console.log('服务id:', service.uuid);
}
}
});
查找特征
const deviceId : string = ''; // 蓝牙外设的设备id
const serviceId : string = ''; // 服务id
dry_ble_discover_characters(deviceId, serviceId, (code : DryBleCode, arr : DryBleCharacterArray) => {
if (code != '0') {
console.log('查找特征失败:', code);
} else {
const characters : DryBleCharacter[] = arr.characters;
for (let i = 0; i < characters.length; i++) {
const character : DryBleCharacter = characters[i];
console.log('特征id:', character.uuid);
}
}
});
订阅特征
const deviceId : string = ''; // 蓝牙外设的设备id
const serviceId : string = ''; // 服务id
const characterId : string = ''; // 特征id
dry_ble_notify_character(deviceId, serviceId, characterId, (code : DryBleCode) => {
if (code != '0') {
console.log('订阅特征失败:', code);
} else {
console.log('订阅特征成功,请在 dry_ble_on_character_value_change 中获取特征值回调');
}
});
读特征值
const deviceId : string = ''; // 设备id
const serviceId : string = ''; // 服务id
const characterId : string = ''; // 特征id
dry_ble_read_character_value(deviceId, serviceId, characterId, (code : DryBleCode) => {
if (code != '0') {
console.log('读特征失败失败:', code);
} else {
console.log('读特征值成功,请在 dry_ble_on_character_value_change 中获取特征值回调');
}
});
写特征值
const deviceId : string = ''; // 设备id
const serviceId : string = ''; // 服务id
const characterId : string = ''; // 特征id
const values : number[] = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xab]; // 特征值
dry_ble_write_character_value(deviceId, serviceId, characterId, 'writeNoResponse', values, (code : DryBleCode) => {
if (code != '0') {
console.log('写特征失败失败:', code);
} else {
console.log('写特征值成功,请在 dry_ble_on_character_value_change 中获取特征值回调');
}
});
监听特征值变化
1、注册特征值变化回调
dry_ble_on_character_value_change((deviceId : string, serviceId : string, characterId : string, value : number[]) => {
console.log('特征值变化回调 - 设备id:', deviceId);
console.log('特征值变化回调 - 服务id:', serviceId);
console.log('特征值变化回调 - 特征id:', characterId);
console.log('特征值变化回调 - 特征值:', value);
});
2、注销特征值变化回调
dry_ble_off_character_value_change(); ·