更新记录

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();                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        ·

隐私、权限声明

1. 本插件需要申请的系统权限列表:

<uses-permission android:name="android.permission.BLUETOOTH" android:maxSdkVersion="30" /> <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" android:maxSdkVersion="30" /> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <uses-permission android:name="android.permission.BLUETOOTH_SCAN" android:usesPermissionFlags="neverForLocation" /> <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" /> NSBluetoothPeripheralUsageDescription NSBluetoothAlwaysUsageDescription UIBackgroundModes(bluetooth-central、bluetooth-peripheral、fetch)

2. 本插件采集的数据、发送的服务器地址、以及数据用途说明:

3. 本插件是否包含广告,如包含需详细说明广告表达方式、展示频率:

暂无用户评论。

使用中有什么不明白的地方,就向插件作者提问吧~ 我要提问