25_微信小程序蓝牙-蓝牙连接篇
·
25_微信小程序蓝牙-蓝牙连接篇
注: 示例代码使用uniapp编写,下面通过uni.调用的API侧重于微信侧,等同于wx.,
上一篇文章: 24_微信小程序蓝牙-设备搜寻篇 中已经完成了蓝牙设备的搜寻,并展示搜索结果。
本文续接上一篇文章,扩展BluetoothManagerInstance对蓝牙设备连接状态管理。并实现蓝牙的连接与断开连接
注: 在微信小程序的蓝牙连接api中,只支持连接低功耗蓝牙,选购设备的时候需要特别留意,否则设备买错了也是无法通过微信小程序建立蓝牙连接的
一.在BluetoothManager中管理蓝牙设备连接状态
-
首先需要申明一个数组
connectedDeviceIds存放已经连接的设备id,通过uni.onBLEConnectionStateChange监听设备的连接状态改变。 -
在
uni.onBLEConnectionStateChange的回调中,会返回连接状态,以及对应的设备id,如果是已连接,把设备id添加到connectedDeviceIds,如果是断开连接,把设备id从connectedDeviceIds中移除。 -
最后调用
uni.getBluetoothDevices,获取最新搜索到的设备列表,并根据connectedDeviceIds的结果判断设备是否被连接。 -
注:
uni.onBluetoothDeviceFound注册的回调中,获取到的的设备列表,也需要根据connectedDeviceIds的结果判断设备是否被连接... function getBluetoothDevices(): void { uni.getBluetoothDevices().then((res) => { let repeatDevices = (res || {}).devices || [] //去重 let devices = [] repeatDevices.forEach((item) => { let deviceId = item.deviceId let existsIndex = devices.findIndex((existsItem) => existsItem.deviceId == deviceId) if(existsIndex == -1) { devices.push(item) } }) //排序 devices.sort((item1, item2) => { let name1 = (item1.localName || item1.name).toLowerCase() let name2 = (item2.localName || item2.name).toLowerCase() return name1.localeCompare(name2) }) devices.forEach((item) => { let deviceId = item.deviceId let existsIndex = this.connectedDeviceIds.findIndex((connectedId) => connectedId == deviceId) item.connected = existsIndex != -1 }) dispatchDeviceFound.call(this, devices) }) } function initializeBluetooth(): Promise<any> { ... return uni.authorize({scope: scope}).catch((err) => { return getSetting() }).catch((err) => { this.status = BLUETOOTH_AUTHOR_REJECT dispatchBluetoothStatus.call(this, this.status) return Promise.reject() }).then((res) => { return uni.closeBluetoothAdapter().catch((err) => Promise.resolve()) }).then((res) => { return openBluetoothAdapter() }).then((res) => { return stopScanBluetoothDevice.call(this) }).then((res) => { return startScanBluetoothDevice.call(this) }).then((res) => { //关闭蓝牙连接状态监听 uni.offBLEConnectionStateChange(this.onBLEConnectionStateChange) //开启蓝牙连接状态监听 uni.onBLEConnectionStateChange(this.onBLEConnectionStateChange) }) } class BluetoothManagerInstance implements BluetoothManager { ... private onBluetoothDeviceFound: (result: any) => void = (result) => { getBluetoothDevices.call(this) } private connectedDeviceIds: Array<string> = []; private onBLEConnectionStateChange: (result: any) => void = (result) => { let connected = result.connected || false let deviceId = result.deviceId || "" let existsIndex = this.connectedDeviceIds.findIndex((item) => item == deviceId) if(connected) { if(existsIndex == -1) { this.connectedDeviceIds.push(deviceId) } } else { if(existsIndex != -1) { this.connectedDeviceIds.splice(existsIndex, 1) } } getBluetoothDevices.call(this) } ... destroy(): void { this.status = BLUETOOTH_AUTHOR_PENDING //关闭蓝牙连接状态监听 uni.offBLEConnectionStateChange(this.onBLEConnectionStateChange) stopScanBluetoothDevice.call(this) //关闭蓝牙适配器状态监听 uni.offBluetoothAdapterStateChange(this.adapterStateChange) uni.closeBluetoothAdapter().catch(() => undefined) this.statusCallbacks = [] this.devicesCallbacks = [] this.connectedDeviceIds = [] uni.offAppShow(this.onAppShow) } }
二.连接蓝牙设备与断开蓝牙设备连接
-
连接蓝牙设备,只需要调用
uni.createBLEConnection,传入对应的设备id即可。 -
断开蓝牙设备连接,只需要调用
uni.closeBLEConnection,传入对应的设备id即可。<!-- index.vue --> <template> <view class="index-page"> <view class="bluetooth-status">蓝牙状态: {{bluetoothStatus}}</view> <scroll-view scroll-y class="device-list"> <view v-for="(item, index) in devices" class="device-item"> <view class="device-info-box"> <view class="device-info">设备名称: {{item.localName || item.name || item.deviceId}}</view> <view class="device-info">设备ID: {{item.deviceId}}</view> </view> <view class="btn-change-connect" @click="toChangeConnect($event, index)">{{item.connected ? "断开连接":"连接"}}</view> </view> </scroll-view> </view> </template> <script> export default { data() { return { bluetoothStatus: "BLUETOOTH_AUTHOR_PENDING", devices: [] } }, onLoad() { getApp().globalData.bluetoothManager.on("statusChange", this.onBluetoothStatusChanged) getApp().globalData.bluetoothManager.on("deviceFound", this.onDeviceFound) }, onUnload() { getApp().globalData.bluetoothManager.off("statusChange", this.onBluetoothStatusChanged) getApp().globalData.bluetoothManager.off("deviceFound", this.onDeviceFound) }, methods: { onBluetoothStatusChanged: function(status) { this.bluetoothStatus = status }, onDeviceFound: function(devices) { this.devices = devices }, toChangeConnect: function(event, index) { //只管连接和断开连接,状态交给BluetoothManager let item = this.devices[index] uni.showLoading() let changeTask = undefined if(!item.connected) { changeTask = uni.createBLEConnection({ deviceId: item.deviceId }) } else { changeTask = uni.closeBLEConnection({ deviceId: item.deviceId }) } changeTask.finally(() => { uni.hideLoading() }) } } } </script> <style scoped> .index-page { width: 100%; height: 100%; display: flex; flex-direction: column; align-items: stretch; justify-content: center; } .bluetooth-status { font-size: 24rpx; padding: 20rpx 0; margin: 0 20rpx; box-sizing: border-box; flex-shrink: 0; border-bottom: thin solid #f2f2f2; } .device-list { flex: 1; overflow: hidden; } .device-item { padding: 20rpx 0; margin: 0 20rpx; box-sizing: border-box; background: white; border-bottom: thin solid #f2f2f2; display: flex; flex-direction: row; align-items: center; justify-content: center; } .device-info { font-size: 28rpx; margin-top: 20rpx; } .device-info:first-child { margin-top: 0; } .device-info-box { flex: 1; overflow: hidden; display: flex; flex-direction: column; align-items: stretch; justify-content: center; } .btn-change-connect { padding: 20rpx 60rpx; box-sizing: border-box; background: #2BA3FF; color: white; font-size: 28rpx; border-radius: 10rpx; } </style>
三.BluetoothManager完整代码
/**
* 蓝牙权限待申请
*/
const BLUETOOTH_AUTHOR_PENDING:string = "BLUETOOTH_AUTHOR_PENDING"
/**
* 蓝牙权限被拒绝
*/
const BLUETOOTH_AUTHOR_REJECT:string = "BLUETOOTH_AUTHOR_REJECT"
/**
* BluetoothAdapter不可用
*/
const BLUETOOTH_ADAPTER_UNAVAILABLE:string = "BLUETOOTH_ADAPTER_UNAVAILABLE"
/**
* 蓝牙适配器可用
*/
const BLUETOOTH_ADAPTER_AVAILABLE:string = "BLUETOOTH_ADAPTER_AVAILABLE"
export interface BluetoothManager {
on(type: string, callback: (status: string) => void): void;
off(type: string, callback: (status: string) => void): void;
destroy(): void;
}
function dispatchDeviceFound(devices: Array<any>) {
this.devicesCallbacks.forEach((func) => {
func && func(devices)
})
}
function dispatchBluetoothStatus(status: string): void {
this.statusCallbacks.forEach((func) => {
func && func(status)
})
}
function startScanBluetoothDevice(): Promise<any> {
return uni.startBluetoothDevicesDiscovery({
allowDuplicatesKey: false,
interval: 1000
}).catch((err) => {
return Promise.reject()
}).then(() => {
//添加搜索到新设备的事件的监听函数
uni.offBluetoothDeviceFound(this.onBluetoothDeviceFound)
uni.onBluetoothDeviceFound(this.onBluetoothDeviceFound)
return Promise.resolve()
})
}
function stopScanBluetoothDevice():Promise<any> {
//移除搜索到新设备的事件的监听函数
uni.offBluetoothDeviceFound(this.onBluetoothDeviceFound)
return uni.stopBluetoothDevicesDiscovery().catch(() => undefined)
}
function getBluetoothDevices(): void {
uni.getBluetoothDevices().then((res) => {
let repeatDevices = (res || {}).devices || []
//去重
let devices = []
repeatDevices.forEach((item) => {
let deviceId = item.deviceId
let existsIndex = devices.findIndex((existsItem) => existsItem.deviceId == deviceId)
if(existsIndex == -1) {
devices.push(item)
}
})
//排序
devices.sort((item1, item2) => {
let name1 = (item1.localName || item1.name).toLowerCase()
let name2 = (item2.localName || item2.name).toLowerCase()
return name1.localeCompare(name2)
})
devices.forEach((item) => {
let deviceId = item.deviceId
let existsIndex = this.connectedDeviceIds.findIndex((connectedId) => connectedId == deviceId)
item.connected = existsIndex != -1
})
dispatchDeviceFound.call(this, devices)
})
}
function initializeBluetooth(): Promise<any> {
this.status = BLUETOOTH_AUTHOR_PENDING
dispatchBluetoothStatus.call(this, this.status)
const scope:string = "scope.bluetooth"
const openBluetoothAdapter = ():Promise<any> => {
return uni.openBluetoothAdapter().catch((err) => {
this.status = BLUETOOTH_ADAPTER_UNAVAILABLE
dispatchBluetoothStatus.call(this, this.status)
return Promise.reject()
}).then((res) => {
this.status = BLUETOOTH_ADAPTER_AVAILABLE
dispatchBluetoothStatus.call(this, this.status)
return Promise.resolve()
}).finally(() => {
//关闭蓝牙适配器状态监听
uni.offBluetoothAdapterStateChange(this.adapterStateChange)
//开启蓝牙适配器状态监听
uni.onBluetoothAdapterStateChange(this.adapterStateChange)
})
}
const openSetting = () => {
return uni.showModal({
content: "您需要在设置中开启\"蓝牙\"选项,才可以使用蓝牙哦!",
cancelText: "任性不去",
confirmText: "去设置",
}).then((res) => {
if (res.confirm) {
return new Promise((resolve, reject) => {
this.openSettingResolves.push(resolve)
uni.openSetting().catch((error) => {
reject({
"errMsg": "openSetting:fail system error",
"errno": -2
})
})
}).then((res) => {
let authSetting = res.authSetting || {}
if (authSetting[scope]) {
return Promise.resolve()
} else {
return openSetting()
}
})
} else {
return Promise.reject({
"errMsg": "authorize:fail auth deny",
"errno": 103
})
}
})
}
const getSetting = () => {
return uni.getSetting().catch((error) => {
return Promise.reject({
"errMsg": "authorize:fail system error",
"errno": -2
})
}).then((res) => {
let authSetting = res.authSetting || {}
let keys = Object.keys(authSetting)
if (keys.indexOf(scope) != -1) {
if(!authSetting[scope]) {
return openSetting()
} else {
return Promise.resolve()
}
} else {
return Promise.reject({
"errMsg": "authorize:fail auth canceled",
"errno": -3
})
}
})
}
return uni.authorize({scope: scope}).catch((err) => {
return getSetting()
}).catch((err) => {
this.status = BLUETOOTH_AUTHOR_REJECT
dispatchBluetoothStatus.call(this, this.status)
return Promise.reject()
}).then((res) => {
return uni.closeBluetoothAdapter().catch((err) => Promise.resolve())
}).then((res) => {
return openBluetoothAdapter()
}).then((res) => {
return stopScanBluetoothDevice.call(this)
}).then((res) => {
return startScanBluetoothDevice.call(this)
}).then((res) => {
//关闭蓝牙连接状态监听
uni.offBLEConnectionStateChange(this.onBLEConnectionStateChange)
//开启蓝牙连接状态监听
uni.onBLEConnectionStateChange(this.onBLEConnectionStateChange)
})
}
class BluetoothManagerInstance implements BluetoothManager {
private status:string;
private statusCallbacks: Array<(status: string) => void> = [];
private openSettingResolves: Array<(result:any) => void> = [];
private devicesCallbacks: Array<(devices: Array<any>) => void> = [];
private onAppShow: (options: any) => void = (options): void => {
uni.getSetting().then((res) => {
if(this.openSettingResolves.length > 0) {
this.openSettingResolves.forEach((resolveFunc) => resolveFunc(res))
this.openSettingResolves = []
} else {
let authSetting = res.authSetting || {}
let keys = Object.keys(authSetting)
if(keys.indexOf("scope.bluetooth") != -1) {
if (!authSetting["scope.bluetooth"]) {
if(this.status != BLUETOOTH_AUTHOR_PENDING) {
this.status = BLUETOOTH_AUTHOR_REJECT
dispatchBluetoothStatus.call(this, this.status)
}
} else {
if(this.status == BLUETOOTH_AUTHOR_REJECT) {
initializeBluetooth.call(this);
}
}
}
}
return Promise.resolve()
}).catch((err) => {
return Promise.resolve()
})
}
private adapterStateChange: (result: any) => void = (res) => {
let available = (res || {}).available || false
let discovering = (res || {}).discovering || false
let bluetoothStatus = BLUETOOTH_ADAPTER_UNAVAILABLE
if(available) {
bluetoothStatus = BLUETOOTH_ADAPTER_AVAILABLE
}
if(this.status != bluetoothStatus) {
//蓝牙开关状态改变
if(bluetoothStatus == BLUETOOTH_ADAPTER_AVAILABLE) {
//搜索设备
startScanBluetoothDevice.call(this)
} else {
//停止搜索设备
stopScanBluetoothDevice.call(this)
}
}
this.status = bluetoothStatus
}
private onBluetoothDeviceFound: (result: any) => void = (result) => {
getBluetoothDevices.call(this)
}
private connectedDeviceIds: Array<string> = [];
private onBLEConnectionStateChange: (result: any) => void = (result) => {
let connected = result.connected || false
let deviceId = result.deviceId || ""
let existsIndex = this.connectedDeviceIds.findIndex((connectedId) => connectedId == deviceId)
if(connected) {
if(existsIndex == -1) {
this.connectedDeviceIds.push(deviceId)
}
} else {
if(existsIndex != -1) {
this.connectedDeviceIds.splice(existsIndex, 1)
}
}
getBluetoothDevices.call(this)
}
constructor() {
uni.onAppShow(this.onAppShow);
initializeBluetooth.call(this);
}
on(type: string, callback: (result: any) => void): void {
if(type == "statusChange") {
this.statusCallbacks.push(callback)
} else if(type == "deviceFound") {
this.devicesCallbacks.push(callback)
}
}
off(type: string, callback: (result: any) => void): void {
if(type == "statusChange") {
let callbackIndex = this.statusCallbacks.findIndex((item) => item == callback)
if(callbackIndex == -1) {
return
}
this.statusCallbacks.splice(callbackIndex, 1)
} else if(type == "deviceFound") {
let callbackIndex = this.devicesCallbacks.findIndex((item) => item == callback)
if(callbackIndex == -1) {
return
}
this.devicesCallbacks.splice(callbackIndex, 1)
}
}
destroy(): void {
this.status = BLUETOOTH_AUTHOR_PENDING
//关闭蓝牙连接状态监听
uni.offBLEConnectionStateChange(this.onBLEConnectionStateChange)
stopScanBluetoothDevice.call(this)
//关闭蓝牙适配器状态监听
uni.offBluetoothAdapterStateChange(this.adapterStateChange)
uni.closeBluetoothAdapter().catch(() => undefined)
this.statusCallbacks = []
this.devicesCallbacks = []
this.connectedDeviceIds = []
uni.offAppShow(this.onAppShow)
}
}
export const createBluetoothManager = ():BluetoothManager => {
return new BluetoothManagerInstance();
}
更多推荐


所有评论(0)