uniapp实现小程序蓝牙开锁功能(第三方蓝牙设备)

前言:该项目流程是通过扫设备上的二维码(获取设备deviceId和蓝牙锁设备信息)建立蓝牙连接后再开锁(与设备通信)。注意:①与蓝牙的通信遵循第三方通信协议(数据写入和接受这块)②发送/接受的蓝牙数据需要进行加解密处理(aes-128加密和解密)③数据类型之间的转化

参考文章:uniapp微信小程序蓝牙连接与设备数据对接_uniapp小程序蓝牙配网-CSDN博客

一:蓝牙通信板块(首先通过扫码获取到信息,然后调用蓝牙相关api进行蓝牙的通信)

1:初始化蓝牙并连接

/**
             * 获取手机蓝牙是否打开(初始化蓝牙)
             */
            getBluetoothState() {
                let that = this
                // 主机模式
                return new Promise((resolve, reject) => {
                    uni.openBluetoothAdapter({
                        mode: 'central',
                        success: (r) => {
                            console.log("蓝牙初始化成功");
                            // 获取蓝牙的匹配状态
                            uni.getBluetoothAdapterState({
                                success: function(row) {
                                    console.log('蓝牙状态:', row.available);
                                    if (row.available) {
                                        that.bluetoothOpen = true;
                                        resolve();
                                    } else {
                                        // 请开启蓝牙
                                        that.bluetoothOpen = false;
                                        reject();
                                    }
                                },
                                fail: function(err) {
                                    // 请开启蓝牙
                                    that.bluetoothOpen = false;
                                    reject();
                                }
                            })
                        },
                        fail: (err) => {
                            // 请开启蓝牙
                            if (err.errCode === 10001) {
                                uni.showModal({
                                    title: '提示',
                                    content: '请先打开蓝牙',
                                    showCancel: false,
                                    success: function(res) {}
                                });
                                // 监听蓝牙适配器状态变化事件
                                uni.onBluetoothAdapterStateChange(res => {
                                    console.log('监听蓝牙适配器状态变化事件', res);
                                    if (res.available) {
                                        // 重新连接扫码的设备
                                        that.bluetoothOpen = true
                                        that.connectBluetooth()
                                    } else {
                                        that.bluetoothOpen = false;
                                    }
                                });
                            }
                            reject();
                        }
                    });
                });
            },

/**
             * 连接蓝牙
             * deviceId 蓝牙设备id
             */
            connectBluetooth() {
                uni.showLoading({
                    title: '正在连接蓝牙...'
                });
                let that = this
                return new Promise((resolve, reject) => {
                    uni.createBLEConnection({
                        deviceId: this.device_st_id, // 设备id
                        success() {
                            console.log("蓝牙连接成功");
                            that.bluetoothOpen = true
                            that.bluetoothConnect = true;
                            resolve();
                            // 获取服务id
                            that.getServiceId();
                        },
                        fail(err) {
                            that.bluetoothConnect = false;
                            console.log("蓝牙连接失败", err);
                            reject();
                        },
                        complete() {
                            uni.hideLoading()
                        }
                    });
                });
            }, 

2:获取蓝牙的serviceId后调用蓝牙监听和写入功能

    // 获取服务id
            getServiceId() {
                let that = this
                uni.getBLEDeviceServices({
                    deviceId: this.device_st_id,
                    success(res) {
                        console.log("获取服务Id", res)
                        let model = res.services[0];
                        that.serviceId = model.uuid;
                        // 调用蓝牙监听和写入功能
                        that.getCharacteId();
                    }
                })
            }, 

// 获取蓝牙低功耗设备某个服务中所有特征
            getCharacteId() {
                let that = this
                uni.getBLEDeviceCharacteristics({
                    deviceId: this.device_st_id, // 蓝牙设备id
                    serviceId: this.serviceId, // 蓝牙服务UUID
                    success(res) {
                        console.log('数据监听', res);
                        res.characteristics.forEach(item => {
                            // 003
                            if (item.properties.notify === true) {
                                // 监听
                                let notify = item.uuid;
                                that.startNotice(notify);
                            }
                            // 002
                            if (item.properties.write === true) {
                                // 写入
                                let writeId = item.uuid; 
                                uni.setStorageSync("writeId", item.uuid);
                            }
                        });
                    },
                    fail(err) {
                        console.log("数据监听失败", err)
                    }
                })
            },

// 启用低功耗蓝牙设备特征值变化时的notify功能
            startNotice(notify) {
                let that = this
                uni.notifyBLECharacteristicValueChange({
                    characteristicId: notify,
                    deviceId: this.device_st_id,
                    serviceId: this.serviceId,
                    state: true,
                    success(res) {
                        console.log("启用低功耗蓝牙设备特征值变化时的notify功能", res);
                        // 监听低功耗蓝牙设备的特征值变化
                        uni.onBLECharacteristicValueChange(result => {
                            console.log("监听低功耗蓝牙设备的特征值变化", result);
                            //返回的result.value为arrayBuffer格式
                            if (result.value) {                                
                                var arrint82 = new Int8Array(result.value); //将返回的结果转化为一个 8 位有符号整数的数组(int8数组)
                                var edata2 = bluetooth.aesDecrypt(arrint82); // 解密后的int8数组
                                // bluetooth.ab2hex()将数组转为16进制字符串
                                var ab2hexSubStr = bluetooth.ab2hex(edata2).substring(
                                    6, 12)
                                if (ab2hexSubStr == '000000') {
                                    uni.showToast({
                                        title: '成功',
                                        icon: 'success',
                                        duration: 2000
                                    });
                                    setTimeout(() => {
                                        uni.switchTab({
                                            url: "/pages/index/index"
                                        })
                                    }, 2000)
                                } else if (ab2hexSubStr == '100000') {
                                    uni.showToast({
                                        title: '开锁异常',
                                        icon: 'error',
                                        duration: 2000
                                    });
                                    setTimeout(() => {
                                        uni.navigateBack()
                                    }, 2000)
                                }
                                //unlockingKey为用于开蓝牙锁的通信帧(用于开蓝牙锁),结构如下   
                                //                                        固定  +   出厂默认密码   +     锁位     +   token   (058109 PWD[6] CHM[3] token[4])
                                var unlockingKey = '058109' + '0000000' + that.lockNum + bluetooth.ab2hex(edata2).substring(
                                    6, 14)

                                const buffer = bluetooth.processData(unlockingKey);

                                setTimeout(function() {
                                    uni.hideLoading();
                                }, 1000);
                                that.writeData(buffer) //开锁
                            }
                        })
                    }
                });
            },

// 向蓝牙发送数据
            writeData(buffer) {
                return new Promise((resolve, reject) => {
                    uni.writeBLECharacteristicValue({
                        characteristicId: uni.getStorageSync("writeId"),
                        deviceId: this.device_st_id,
                        serviceId: this.serviceId,
                        value: buffer, //蓝牙设备特征值对应的二进制值
                        success(res) {
                            console.log("writeBLECharacteristicValue success", res);
                            resolve();
                        },
                        fail(err) {
                            console.log("报错了", err);
                            reject();
                        }
                    });
                });
            }, 

    // 开锁
            writeBlueData() {
                if ((this.bluetoothOpen == false && this.bluetoothConnect == false) || this.bluetoothConnect == false) {
                    uni.showToast({
                        title: '开锁异常,请重新扫码',
                        icon: 'none'
                    });
                    setTimeout(() => {
                        uni.navigateBack()
                    }, 1500)
                    return
                } else {
                    uni.showLoading({
                        title: '加载中...'
                    });
                }
                bluetooth.setBleKeyVariables(this.aesKey);
                const buffer = bluetooth.processData(this.hexStr);
                this.writeData(buffer)
            },         

二:加解密处理板块aes-128 (aes.js)

可以参考该文章:uniappAES加密方法_uniapp aes解密-CSDN博客

三:数据类型转化以及加解密使用(封装好的js)

let fun_aes = require('../utils/aes.js');

let keyBv = null;
let keyWA = null;
// 加密后转换为二进制类型通信帧
const processData = (hexStr) => {
	var typedArray = hexStrToUint8Array(hexStr)
	var arrint8 = new Int8Array(typedArray.buffer);
	var edata = aesEncrypt(arrint8);
	// const buffer = Buffer.from(ab2hex(edata), 'hex').buffer;//小程序中不适用该方式获取buffer对象
	
	var hexString=ab2hex(edata)
	const buffer = hexStrToUint8Array(hexString).buffer
	
	return buffer;
};


// 加解密/数据处理 用到的相关函数start

// 将一个十六进制字符串 hexStr 转换为一个 Uint8Array(8 位无符号整数类型的数组)
const hexStrToUint8Array = (hexStr) => {
	var typedArray = new Uint8Array(hexStr.match(/[\da-f]{2}/gi).map(function(h) {
		return parseInt(h, 16);
	}))
	return typedArray
};
// 十六进制字符串转成十进制数组
const hexStringToDecimalArray = (hexString) => {
	return hexString.match(/.{2}/g).map(function(hexVal) {
		return parseInt(hexVal, 16);
	});
};
// buffer 数据转换为十六进制字符串。
const ab2hex = (buffer) => {
	const hexArr = Array.prototype.map.call(
		new Uint8Array(buffer),
		function(bit) {
			return ('00' + bit.toString(16)).slice(-2)
		}
	)
	return hexArr.join('')
};
// 设置加解密所需的keyWA值
const setBleKeyVariables = (akey) => {
	keyBv = new Int8Array(hexStringToDecimalArray(akey));
	keyWA = fun_aes.CryptoJS.enc.int8array.parse(keyBv);
};
// 解密
const aesDecrypt = function(array) {
	var that = this;

	var acontent = array;
	// 将密文转换成WordArray
	var contentWA = fun_aes.CryptoJS.enc.int8array.parse(acontent);
	// console.log('Decrypt contentWA is ' + contentWA);
	// 插件要求密文是base64格式
	var dcBase64String = contentWA.toString(fun_aes.CryptoJS.enc.Base64);
	// console.log('Decrypt dcBase64String is ' + dcBase64String);
	// 解密 选定mode是CFB类型,无偏移量
	var decrypted = fun_aes.CryptoJS.AES.decrypt(dcBase64String, keyWA, {
		iv: [],
		mode: fun_aes.CryptoJS.mode.ECB,
		padding: fun_aes.CryptoJS.pad.NoPadding
	});
	// console.log('Decrypt decrypted is ' + decrypted);
	// 将解密后的明文转回int8数组
	var bv = fun_aes.CryptoJS.enc.int8array.stringify(decrypted);
	return bv;
};

// 加密
const aesEncrypt = function(array) {

	var that = this;

	var acontent = array;
	// 将明文转换成WordArray
	var contentWA = fun_aes.CryptoJS.enc.int8array.parse(acontent);
	// console.log('Encrypt contentWA is ' + contentWA);
	// 插件要求明文是base64格式
	var dcBase64String = contentWA.toString(fun_aes.CryptoJS.enc.Base64);
	// console.log('Encrypt dcBase64String is ' + dcBase64String);
	// 加密 选定mode是ECB类型,无偏移量,还有其他的mode与pad类型
	var encrypted = fun_aes.CryptoJS.AES.encrypt(contentWA, keyWA, {
		iv: [],
		mode: fun_aes.CryptoJS.mode.ECB,
		padding: fun_aes.CryptoJS.pad.NoPadding
	});
	// console.log('Encrypt encrypted is ' + encrypted);
	// 将密文转回int8数组
	var bv = fun_aes.CryptoJS.enc.int8array.stringify(encrypted.ciphertext);
	return bv;
};
export default {
	processData,
	setBleKeyVariables,
	hexStrToUint8Array,
	hexStringToDecimalArray,
	ab2hex,
	aesDecrypt,
	aesEncrypt,
};

蓝牙连接注意事项:

        1、请确保你的小程序的蓝牙权限已开通

        2、若你的项目是通过搜索附近设备来匹配设备id,需要注意苹果和安卓系统的兼容处理(可以参考文章:解决uniapp微信小程序Android与iOS系统获取蓝牙广播包中deviceid不同的办法

     

       

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值