uni-app 蓝牙连接API 流程解析

232 阅读7分钟

蓝牙主要功能

Uni-App 提供的蓝牙 API 允许我们开发时主要实现以下功能:

  • 扫描并连接到蓝牙设备
  • 发现已连接设备的服务和特征值
  • 向设备发送数据
  • 接收设备发送的数据

流程图:

关于开发时进行蓝牙连接的流程,总结如下:

  1. 初始化蓝牙适配器
  2. 开始搜索蓝牙设备
  3. 监听/获取已发现的设备
  4. 连接到蓝牙设备
  5. 获取设备服务
  6. 获取服务特征值uni-app 蓝牙连接全面指南
  7. 写入/读取数据
  8. 断开连接并关闭蓝牙模块

三、蓝牙核心 API 介绍

蓝牙 API 分为通用蓝牙 API 和低功耗蓝牙的 API

通用蓝牙 API

1. 初始化蓝牙模块

当开始使用蓝牙前,需要先初始化蓝牙模块,初始化蓝牙适配器成功后才可以继续使用其他的 API

uni.openBluetoothAdapter({
  success: function (res) {
    console.log('初始化蓝牙适配器成功', res)
  },
  fail: function (err) {
    console.error('初始化蓝牙适配器失败', err)
  }
})

2. 开始搜索蓝牙设备

初始化成功后,就可以通过调用 startBluetoothDevicesDiscovery 方法开始搜索附近的蓝牙设备:

注意:此操作比较耗费系统资源,请在搜索并连接到设备后调用 uni.stopBluetoothDevicesDiscovery 方法停止搜索。

uni.startBluetoothDevicesDiscovery({
  success: function (res) {
    console.log('开始搜索蓝牙设备', res)
  },
  fail: function (err) {
    console.error('开始搜索蓝牙设备失败', err)
  }
})

说明:App 端目前仅支持发现 BLE 低功耗蓝牙设备,其实我们也主要和低功耗蓝牙设备建立通信关系。一般为发送指令(开关机、蓝牙打印等),接收数据(蓝牙温度记录仪)

3. 停止搜索蓝牙设备

当不再需要继续搜索设备时,可以调用 stopBluetoothDevicesDiscovery 停止搜索:

uni.stopBluetoothDevicesDiscovery({
  success: function (res) {
    console.log('停止搜索蓝牙设备', res)
  },
  fail: function (err) {
    console.error('停止搜索蓝牙设备失败', err)
  }
})

4. 监听已发现的蓝牙设备

通过 onBluetoothDeviceFound 方法获取当前已发现的蓝牙设备列表,此方式是回调方法,只要发现了新的蓝牙设备,都会进入该回调:

uni.onBluetoothDeviceFound(function (devices) {
  console.log('new device list has founded')
  console.dir(devices)
})

5. 获取已发现的蓝牙设备列表

通过 getBluetoothDevices 方法获取在蓝牙模块生效期间所有已发现的蓝牙设备。包括已经和本机处于连接状态的设备。

uni.getBluetoothDevices({
  success: function (res) {
    console.log('已发现的蓝牙设备', res.devices)
  },
  fail: function (err) {
    console.error('获取已发现的蓝牙设备列表失败', err)
  }
})

6. 关闭蓝牙模块

通过调用 closeBluetoothAdapter 方法将关闭蓝牙模块,断开所有已建立的连接并释放系统资源。

调用该方法将断开所有已建立的连接并释放系统资源。一般在使用蓝牙流程完毕后,主动调用该方法,可在页面生命周期中使用。应与 uni.openBluetoothAdapter 成对调用。

uni.closeBluetoothAdapter({
  success(res) {
    console.log(res)
  }
})

低功耗蓝牙 API

1. 连接到蓝牙设备

选择一个设备后,可以通过设备 ID 调用 createBLEConnection 方法建立与该设备的连接:

uni.createBLEConnection({
  deviceId: '目标设备ID',
  success: function (res) {
    console.log('连接蓝牙设备成功', res)
  },
  fail: function (err) {
    console.error('连接蓝牙设备失败', err)
  }
})

2. 获取蓝牙设备的服务

连接成功后,可以通过设备 ID 调用 getBLEDeviceServices 方法获取该设备提供的服务:

uni.getBLEDeviceServices({
  deviceId: '目标设备ID',
  success: function (res) {
    console.log('获取蓝牙设备服务成功', res.services)
  },
  fail: function (err) {
    console.error('获取蓝牙设备服务失败', err)
  }
})

3. 获取服务中的特征值

获取服务成功后,可以通过设备 ID、服务 ID 调用 getBLEDeviceCharacteristics 方法获取特定服务下的特征值:

uni.getBLEDeviceCharacteristics({
  deviceId: '目标设备ID',
  serviceId: '服务ID',
  success: function (res) {
    console.log('获取蓝牙设备特征值成功', res.characteristics)
  },
  fail: function (err) {
    console.error('获取蓝牙设备特征值失败', err)
  }
})

4. 向蓝牙设备写入数据

确定了要使用的特征值后,可以使用 writeBLECharacteristicValue 方法向蓝牙设备写入数据:

注意:只有获取到支持读写的特征值后,才可以向蓝牙设备写入数据。

uni.writeBLECharacteristicValue({
  deviceId: '目标设备ID',
  serviceId: '服务ID',
  characteristicId: '特征值ID',
  value: new ArrayBuffer(2), // 示例数据
  success: function (res) {
    console.log('向蓝牙设备写入数据成功', res)
  },
  fail: function (err) {
    console.error('向蓝牙设备写入数据失败', err)
  }
})

说明:蓝牙打印机主要会使用该 API,将在下一文章中说明。

5. 监听来自蓝牙设备的数据

如果需要接收来自蓝牙设备的数据,可以监听 onBLECharacteristicValueChange 事件:

uni.onBLECharacteristicValueChange(function (res) {
  console.log('接收到蓝牙设备数据', res.value)
})

6. 断开蓝牙连接

通过调用 closeBLEConnection 断开与低功耗蓝牙设备的连接。

uni.closeBLEConnection({
  deviceId,
  success(res) {
    console.log(res)
  }
})

使用蓝牙 API 前的准备

Uni-App 中使用蓝牙功能时,尤其是真机(AndroidiOS),需要添加蓝牙打包模块;除此之外,还需要确保在 manifest.json 文件中正确声明所需的蓝牙权限,并在运行时请求这些权限。

1. 添加蓝牙模块

在 HBuilderX 中,需要在项目配置中勾选蓝牙模块。

2. Android 权限

处理 Android 蓝牙权限需要在 manifest.json 中声明权限,首先,打开你的 manifest.json 文件,并在 app-plus 节点下添加所需的蓝牙权限。

注意:根据不同的 Android 版本,你可能需要声明不同的权限。

基本权限

manifest.json 配置如下权限:

{
  "app-plus": {
    "distribute": {
      "android": {
        "permissions": [
          "android.permission.BLUETOOTH", 
          "android.permission.BLUETOOTH_ADMIN"
        ]
      }
    }
  }
}

高级权限(Android 12 及以上)

如果应用需要扫描附近的蓝牙设备,还需要声明 ACCESS_FINE_LOCATION 权限,从 Android 12 开始,还需要声明 BLUETOOTH_SCANBLUETOOTH_CONNECTBLUETOOTH_ADVERTISE 权限:

{
  "app-plus": {
    "distribute": {
      "android": {
        "permissions": [
          "android.permission.BLUETOOTH",
          "android.permission.BLUETOOTH_ADMIN",
          "android.permission.ACCESS_FINE_LOCATION",
          "android.permission.BLUETOOTH_SCAN",
          "android.permission.BLUETOOTH_CONNECT",
          "android.permission.BLUETOOTH_ADVERTISE"
        ]
      }
    }
  }
}

3. iOS 权限

对于 iOS 平台,和 Android 平台类似,同样需要在 manifest.json 文件,并在 app-plus 节点下添加所需的蓝牙权限。需要声明 NSBluetoothAlwaysUsageDescriptionNSBluetoothPeripheralUsageDescription,并在其中提供用途说明。

manifest.json 配置如下权限:

{
  "app-plus": {
    "distribute": {
      "ios": {
        "permissions": {
          "NSBluetoothAlwaysUsageDescription": "需要蓝牙权限以连接和控制外部设备",
          "NSBluetoothPeripheralUsageDescription": "需要蓝牙权限以连接和控制外部设备"
        }
      }
    }
  }
}

4. 运行时请求权限

Uni-App 中,你可以使用 uni.authorize 方法来请求运行时权限。以下示例代码,表示如何在应用启动时请求蓝牙相关权限:

export default {
  data() {
    return {}
  },
  onReady() {
    this.checkAndRequestPermissions()
  },
  methods: {
    checkAndRequestPermissions() {
      const permissions = ['scope.bluetooth', 'scope.location']

      // 检查权限
      uni.getSetting({
        success: res => {
          let authResult = true
          permissions.forEach(permission => {
            if (!res.authSetting[permission]) {
              authResult = false
              return
            }
          })

          if (!authResult) {
            // 请求权限
            this.requestPermissions()
          } else {
            // 已经有权限,可以进行蓝牙操作
            this.initBluetooth()
          }
        }
      })
    },

    requestPermissions() {
      const permissions = ['scope.bluetooth', 'scope.location']

      permissions.forEach(permission => {
        uni.authorize({
          scope: permission,
          success: () => {
            console.log(`权限 ${permission} 请求成功`)
          },
          fail: err => {
            console.error(`权限 ${permission} 请求失败`, err)
            uni.showModal({
              title: '提示',
              content: '请在设置中开启蓝牙和位置权限',
              showCancel: false
            })
          }
        })
      })
    },

    initBluetooth() {
      uni.openBluetoothAdapter({
        success: res => {
          console.log('初始化蓝牙适配器成功', res)
          // 继续进行蓝牙操作
        },
        fail: err => {
          console.error('初始化蓝牙适配器失败', err)
        }
      })
    }
  }
}

5. 处理用户拒绝权限的情况

如果用户拒绝了权限请求,可以通过 uni.showModal 方法提示用户在设置中手动开启权限。如下所示:

uni.showModal({
  title: '提示',
  content: '请在设置中开启蓝牙和位置权限',
  confirmText: '去设置',
  success: res => {
    if (res.confirm) {
      uni.openSetting({
        success: settingData => {
          console.log('用户设置结果', settingData)
        }
      })
    }
  }
})

注意事项

在使用蓝牙 API 时,请确保用户已经开启了手机的蓝牙功能和位置信息。

  1. 蓝牙 API 调用时机:蓝牙相关 API 的调用必须在 uni.openBluetoothAdapter 调用之后使用,否则 API 会返回错误(errCode=10000)。

  2. 在用户蓝牙开关未开启或者手机不支持蓝牙功能的情况下,调用 uni.openBluetoothAdapter 会返回错误(errCode=10001),表示手机蓝牙功能不可用。

  3. 版本兼容性:部分蓝牙 API 可能因操作系统版本不同而有所差异,具体请参考官方文档。

  4. 用户提示:确保在请求蓝牙权限时提供清晰的提示信息,告知用户为什么需要这些权限。

  5. 蓝牙状态检查:在初始化蓝牙适配器之前,应检查蓝牙是否已开启。可以使用 uni.getBluetoothAdapterState 方法来检查蓝牙状态,如下代码:

uni.getBluetoothAdapterState({
  success: res => {
    if (!res.discovering && !res.available) {
      uni.showModal({
        title: '提示',
        content: '请确保蓝牙已开启',
        showCancel: false
      })
    }
  },
  fail: err => {
    console.error('检查蓝牙适配器状态失败', err)
  }
})

参考文档