封装设备属性和方法
const devicesConfig ={
config:{
// 存储节点变量名
deviceUseScanGun: "device_use_scan_gun",//是否使用扫码枪
deviceScanGun : 'device_scan_gun',//扫码枪设备
devicePrint : 'device_print',//打印机设备
},
initDevice: function(type) {
console.log('初始化蓝牙..............')
return new Promise((resolve, reject) => {
uni.openBluetoothAdapter({
success(res) {
let device = uni.getStorageSync(type)
if(!device || !device.connected){
uni.showToast({
title: '请链接蓝牙设备',
icon: 'error'
})
return
}
console.log('初始化蓝牙成功..............')
resolve(device)
},
fail(err) {
uni.showToast({
title: '初始化蓝牙失败',
icon: 'error'
})
reject("初始化蓝牙失败")
}
})
})
},
// 开启监听扫码枪
onSacnGunValue: function(backFunc){
devicesConfig.initDevice(devicesConfig.config.deviceScanGun).then(scanGun => {
console.log("开启监听----设备id:" + scanGun.deviceId + ",服务id:" + scanGun.serviceId +
",特征值id:" + scanGun.characteristicId)
uni.notifyBLECharacteristicValueChange({
deviceId: scanGun.deviceId, // 设备id
serviceId: scanGun.serviceId, // 监听指定的服务
characteristicId: scanGun.characteristicId, // 监听对应的特征值
success(res) {
uni.onBLECharacteristicValueChange(res => {
let resHex = devicesConfig.ab2hex(res.value)
let result = devicesConfig.hexCharCodeToStr(resHex)
console.log(result)
backFunc(result)
})
},
fail(err) {
console.error(err)
uni.showToast({
title: '请配置扫码枪',
icon: 'error'
})
}
})
})
},
// ArrayBuffer转16进度字符串示例
ab2hex: function(buffer){
const hexArr = Array.prototype.map.call(
new Uint8Array(buffer),
function(bit) {
return ('00' + bit.toString(16)).slice(-2)
}
)
return hexArr.join('')
},
// 将16进制的内容转成我们看得懂的字符串内容
hexCharCodeToStr: function(hexCharCodeStr) {
let trimedStr = hexCharCodeStr.trim()
let rawStr = trimedStr.substr(0, 2).toLowerCase() === "0x" ? trimedStr.substr(2) : trimedStr
let len = rawStr.length
if (len % 2 !== 0) {
alert("存在非法字符!")
return ""
}
let curCharCode
let resultStr = []
for (let i = 0; i < len; i = i + 2) {
curCharCode = parseInt(rawStr.substr(i, 2), 16)
resultStr.push(String.fromCharCode(curCharCode))
}
return resultStr.join("").replace("\r",'')
},
//发送数据打印
senBlData(deviceId, serviceId, characteristicId,uint8Array) {
console.log('************deviceId = [' + deviceId + '] serviceId = [' + serviceId + '] characteristics=[' +characteristicId+ "]")
var uint8Buf = Array.from(uint8Array);
function split_array(datas,size){
var result = {};
var j = 0
for (var i = 0; i < datas.length; i += size) {
result[j] = datas.slice(i, i + size)
j++
}
console.log(result)
return result
}
var sendloop = split_array(uint8Buf, 20);
// console.log(sendloop.length)
function realWriteData(sendloop, i) {
var data = sendloop[i]
if(typeof(data) == "undefined"){
return
}
console.log("第【" + i + "】次写数据"+data)
var buffer = new ArrayBuffer(data.length)
var dataView = new DataView(buffer)
for (var j = 0; j < data.length; j++) {
dataView.setUint8(j, data[j]);
}
uni.writeBLECharacteristicValue({
deviceId,
serviceId,
characteristicId,
value: buffer,
success(res) {
realWriteData(sendloop, i + 1);
}
})
}
var i = 0;
realWriteData(sendloop, i);
},
}
export default devicesConfig
设备链接
<template>
<view class="help-container" style="height: 100%">
<view title="蓝牙链接说明" class="list-title" style="height: 35%;">
<view class="text-title">
<view class="iconfont icon-help">扫码枪蓝牙链接说明</view>
<button v-if="scanSetting.useScanGun" style="float:right;top:-10px;" class="mini-btn" type="primary" size="mini" @click="setScan">关闭扫码枪</button>
<button v-if="!scanSetting.useScanGun" style="float:right;top:-10px;" class="mini-btn" type="default" size="mini" @click="setScan">启用扫码枪</button>
</view>
<view class="childList">
<view class="question" hover-class="hover">
<view class="text-item">1:手机开启蓝牙</view>
<view class="line" ></view>
</view>
<view class="question" hover-class="hover">
<view class="text-item">2:点击下方“搜索蓝牙设备”按钮搜索设备</view>
<view class="line" ></view>
</view>
<view class="question" hover-class="hover">
<view class="text-item">3:如果没有搜索到您需要的设备,请将您的设备调至蓝牙BLE模式</view>
<view >
<image src="@/static/images/scan_ble.png" style="height: 100px;" />
</view>
<view class="line" ></view>
</view>
<view class="question" hover-class="hover">
<view class="text-item">4:点击搜索到的蓝牙设备进行链接</view>
<view class="line" ></view>
</view>
</view>
</view>
<view title="搜索蓝牙设备" class="list-title" style="height: 30%;">
<view class="text-title">
<button type="primary" :disabled="searchDisabled" @click="initBlue" size="mini">
<uni-icons type="search" size="10" color="F000" style="margin-right: 5px;"></uni-icons>
搜索设备
</button>
<button type="primary" :disabled="!searchDisabled" @click="stopDiscovery()" size="mini" style="margin-left: 5px;">
<uni-icons custom-prefix="iconfont" type="icon-stop" size="10" color="F000" style="margin-right: 5px;"></uni-icons>
停止搜索
</button>
<button type="primary" :disabled="searchDisabled" @click="toDeviceTest" size="mini" style="margin-left: 5px;">
<uni-icons type="checkbox" size="10" color="F000" style="margin-right: 5px;"></uni-icons>
蓝牙测试
</button>
</view>
<scroll-view scroll-y="true" class="scroll-Y childList" style="height: 150px;">
<view v-for="(item,zindex) in blueDeviceList" @click="connect(item)" :key="zindex" class="question" hover-class="hover">
<view class="text-item">{{ item.name }}</view>
<view class="line" v-if="zindex !== blueDeviceList.length - 1"></view>
</view>
</scroll-view>
</view>
<view title="已链接设备" class="list-title" style="height: 30%;">
<view class="text-title">
<view class="iconfont icon-list"></view>已链接设备
</view>
<scroll-view scroll-y="true" class="scroll-Y childList" style="height: 150px;">
<view v-for="(item,zindex) in connectedBlueDeviceList" @click="cancelConnect(item)" :key="zindex" class="question" hover-class="hover">
<view class="text-item">{{ item.name }}</view>
<view class="line" v-if="zindex !== connectedBlueDeviceList.length - 1"></view>
</view>
</scroll-view>
</view>
</view>
</template>
<script>
import devicesConfig from '@/utils/devicesConfig'
export default {
data() {
return {
searchDisabled: false,
// 搜索到的蓝牙设备列表
blueDeviceList: [],
// 搜索到的蓝牙设备列表
connectedBlueDeviceList: [],
// 蓝牙设备的id
deviceId : "",
// 硬件提供的服务id,开发中需要问硬件佬获取该id
serviceId : '0000FFF0-0000-1000-8000-00805F9B34FB',
characteristicId : '0000FFF1-0000-1000-8000-00805F9B34FB',
// 监听到的内容
message : '',
messageHex : '', // 十六进制
scanSetting:{
useScanGun: uni.getStorageSync(devicesConfig.config.deviceUseScanGun)?uni.getStorageSync(devicesConfig.config.deviceUseScanGun):false,
},
testScanRes : "111",
deviceType: ["扫码枪","打印机"],
connectDeviceTypeIndex:0
}
},
onLoad(option){
this.getBlue()
},
onBackPress(){
if(this.searchDisabled){
this.stopDiscovery()
}
},
methods: {
toDeviceTest(){
this.$tab.navigateTo("/pages/deviceTest")
},
setScan(event) {
this.scanSetting.useScanGun = !this.scanSetting.useScanGun
uni.setStorageSync(devicesConfig.config.deviceUseScanGun, this.scanSetting.useScanGun)
uni.showToast({
title: '已'+(this.scanSetting.useScanGun?"启用":"关闭")+'扫码枪',
icon: 'error'
})
},
// 【1】初始化蓝牙
initBlue() {
let that = this
that.searchDisabled = true
console.log('初始化蓝牙..............')
uni.openBluetoothAdapter({
success(res) {
console.log('初始化蓝牙成功')
console.log(res)
uni.onBLEConnectionStateChange(function (res) {
// 该方法回调中可以用于处理连接意外断开等异常情况
if(!res.connected){
let scan_d = uni.getStorageSync(devicesConfig.config.deviceScanGun)
let print_d = uni.getStorageSync(devicesConfig.config.devicePrint)
if(scan_d && res.deviceId == scan_d.deviceId){
scan_d.connected = false
uni.setStorageSync(devicesConfig.config.deviceScanGun,scan_d)
}
if(print_d && res.deviceId == print_d.deviceId){
print_d.connected = false
uni.setStorageSync(devicesConfig.config.devicePrint,print_d)
}
}
})
that.startFoundBluetooth()
},
fail(err) {
that.searchDisabled = false
console.log('初始化蓝牙失败')
console.error(err)
uni.showToast({
title: '初始化蓝牙失败,请确保蓝牙已开启',
icon: 'error'
})
}
})
},
// 【2】开始搜寻附近设备
startFoundBluetooth() {
console.log('开始搜索蓝牙设备..............')
let that = this
that.blueDeviceList = []
uni.startBluetoothDevicesDiscovery({
success(res) {
// 开启监听回调
uni.onBluetoothDeviceFound(function(devices){
that.found(devices)
})
},
fail(err) {
that.searchDisabled = false
uni.showToast({
title: '搜索蓝牙失败,请确保蓝牙已开启',
icon: 'error'
})
console.error(err)
}
})
},
// 【3】找到新设备就触发该方法
found(res) {
console.log('搜索到蓝牙设备..............')
console.log(res)
if(res.devices[0].name){
this.blueDeviceList.push(res.devices[0])
}
},
// 【4】连接设备
connect(data) {
let that = this
uni.showActionSheet({
title: "设备类型",
itemList:that.deviceType,
success(res) {
that.connectDeviceTypeIndex = res.tapIndex
console.log('开始链接蓝牙设备..............'+data.name)
this.deviceId = data.deviceId // 将获取到的设备ID存起来
uni.createBLEConnection({
deviceId: data.deviceId,
success(res) {
console.log('连接成功')
console.log(res)
that.connectedBlueDeviceList.push(data)
// 停止搜索
that.stopDiscovery()
that.getServices(data.deviceId)
uni.showToast({
title: '连接成功'
})
},
fail(err) {
that.searchDisabled = false
console.log('连接失败')
console.error(err)
uni.showToast({
title: '蓝牙设备连接失败',
icon: 'error'
})
}
})
}
})
},
cancelConnect(data) {
console.log('断开蓝牙设备..............'+data.name)
let that = this
uni.closeBLEConnection({
deviceId: data.deviceId,
success(res) {
that.getBlue()
uni.showToast({
title: '断开成功'
})
},
fail(err) {
console.log('断开失败')
console.error(err)
uni.showToast({
title: '蓝牙设备断开失败',
icon: 'error'
})
}
})
},
// 【5】停止搜索
stopDiscovery() {
this.searchDisabled = false
console.log('停止搜索中。。。。。。。。。。')
uni.stopBluetoothDevicesDiscovery({
success(res) {
console.log('停止搜索成功')
console.log(res)
},
fail(err) {
console.log('停止搜索失败')
console.error(err)
uni.showToast({
title: '蓝牙设备连接失败',
icon: 'error'
})
}
})
},
// 【6】获取服务
getServices(deviceId) {
console.log("获取服务-------设备id:"+deviceId+"。。。。。。。。。。")
let that = this
// 如果是自动链接的话,uni.getBLEDeviceServices方法建议使用setTimeout延迟1秒后再执行
setTimeout(function(){
uni.getBLEDeviceServices({
deviceId: deviceId,
success(res) {
console.log(res) // 可以在res里判断有没有硬件佬给你的服务
for(let i=0;i<res.services.length;i++){
that.getCharacteristics(deviceId,res.services[i].uuid)
}
},
fail(err) {
console.error(err)
uni.showToast({
title: '获取服务失败',
icon: 'error'
})
}
})
},1000)
},
// 【7】获取特征值
getCharacteristics(deviceId,serviceId) {
let that = this
console.log("获取特征值-----设备id:"+deviceId+",服务id:"+serviceId+"。。。。。。。。。。")
// 如果是自动链接的话,uni.getBLEDeviceCharacteristics方法建议使用setTimeout延迟1秒后再执行
uni.getBLEDeviceCharacteristics({
deviceId: deviceId,
serviceId: serviceId,
success(res) {
console.log(res) // 可以在此判断特征值是否支持读写等操作,特征值其实也需要提前向硬件佬索取的
for(let i=0;i<res.characteristics.length;i++){
let characteristics = res.characteristics[i]
if(that.connectDeviceTypeIndex == 0 && characteristics.properties.notify){
//扫码枪
uni.setStorageSync(devicesConfig.config.deviceUseScanGun, true)
that.scanSetting.useScanGun = true
let d = {
"connected": true,
"deviceId":deviceId,
"serviceId":serviceId,
"characteristicId":characteristics.uuid
}
uni.setStorageSync(devicesConfig.config.deviceScanGun, d)
//that.notify(deviceId,serviceId,characteristics.uuid)
break
}
if(that.connectDeviceTypeIndex == 1 &&characteristics.properties.write){
//打印机
let d = {
"connected": true,
"deviceId":deviceId,
"serviceId":serviceId,
"characteristicId":characteristics.uuid
}
uni.setStorageSync(devicesConfig.config.devicePrint, d)
break
}
}
//that.notify()
},
fail(err) {
console.error(err)
uni.showToast({
title: '获取特征值失败',
icon: 'error'
})
}
})
},
// 【8】开启消息监听
notify(deviceId,serviceId,characteristicId) {
let that = this
console.log("开启监听----设备id:"+deviceId+",服务id:"+serviceId+",特征值id:"+characteristicId)
uni.notifyBLECharacteristicValueChange({
deviceId: deviceId, // 设备id
serviceId: serviceId, // 监听指定的服务
characteristicId: characteristicId, // 监听对应的特征值
success(res) {
console.log(res)
//that.listenValueChange()
// uni.showToast({
// title: '已开启监听'
// })
},
fail(err) {
console.error(err)
uni.showToast({
title: '监听失败',
icon: 'error'
})
}
})
},
// 【9】监听消息变化
listenValueChange() {
let that = this
console.log("监听到---设备id:"+that.deviceId+",服务id:"+that.serviceId+",特征值id:"+that.characteristicId+"----消息变化")
uni.onBLECharacteristicValueChange(res => {
console.log(res)
let resHex = that.ab2hex(res.value)
console.log(resHex)
that.messageHex = resHex
let result = that.hexCharCodeToStr(resHex)
console.log(String(result))
that.message = String(result)
})
},
// ArrayBuffer转16进度字符串示例
ab2hex(buffer){
const hexArr = Array.prototype.map.call(
new Uint8Array(buffer),
function(bit) {
return ('00' + bit.toString(16)).slice(-2)
}
)
return hexArr.join('')
},
// 将16进制的内容转成我们看得懂的字符串内容
hexCharCodeToStr(hexCharCodeStr) {
let trimedStr = hexCharCodeStr.trim()
let rawStr = trimedStr.substr(0, 2).toLowerCase() === "0x" ? trimedStr.substr(2) : trimedStr
let len = rawStr.length
if (len % 2 !== 0) {
alert("存在非法字符!")
return ""
}
let curCharCode
let resultStr = []
for (let i = 0; i < len; i = i + 2) {
curCharCode = parseInt(rawStr.substr(i, 2), 16)
resultStr.push(String.fromCharCode(curCharCode))
}
return resultStr.join("").replace("\r",'')
},
getBlue(){
let that = this
uni.getConnectedBluetoothDevices({
success(res) {
console.log(res)
that.connectedBlueDeviceList=res.devices
},
err(res){
}
})
},
}
}
</script>
<style lang="scss" scoped>
page {
background-color: #f8f8f8;
}
.help-container {
margin-bottom: 100rpx;
padding: 30rpx;
}
.list-title {
margin-bottom: 30rpx;
}
.childList {
background: #ffffff;
box-shadow: 0px 0px 10rpx rgba(193, 193, 193, 0.2);
border-radius: 16rpx;
margin-top: 10rpx;
}
.line {
width: 100%;
height: 1rpx;
background-color: #F5F5F5;
}
.text-title {
color: #303133;
font-size: 32rpx;
font-weight: bold;
margin-left: 10rpx;
.iconfont {
font-size: 16px;
margin-right: 10rpx;
}
}
.text-item {
font-size: 28rpx;
padding: 10rpx;
}
.question {
color: #606266;
font-size: 28rpx;
}
</style>
使用测试
<template>
<view class="help-container" style="height: 100%">
<view class="text-title">
<button type="primary" @click="scanTest">
<uni-icons type="checkbox" size="20" color="F000" style="margin-right: 5px;"></uni-icons>
扫码测试
</button>
</view>
<view title="扫码测试结果" class="list-title" style="height: 30%;">
<view class="childList" scroll-y style="height: 200px;">
<view >
<view class="text-item">{{ message }}</view>
</view>
</view>
</view>
<view class="text-title">
<button type="primary" @click="printTest">
<uni-icons type="checkbox" size="20" color="F000" style="margin-right: 5px;"></uni-icons>
打印测试
</button>
</view>
</view>
</template>
<script>
import devicesConfig from '@/utils/devicesConfig'
let tsc = require('@/utils/print/tsc.js')
export default {
data() {
return {
// 监听到的内容
message : '',
messageHex : '', // 十六进制
}
},
methods: {
scanTest(){
let that = this
uni.showToast({
title: '请扫码',
icon: 'success'
})
devicesConfig.onSacnGunValue(function(res){
that.message = res
})
},
printTest(){
this.initBlue()
let device = uni.getStorageSync(devicesConfig.config.devicePrint)
if(!device){
uni.showToast({
title: '请链接打印设备',
icon: 'error'
})
return
}
//标签模式
let deviceId = device.deviceId;
let serviceId = device.serviceId;
let characteristicId = device.characteristicId;
var command = tsc.jpPrinter.createNew()
// console.log(command)
command.setSize(40, 30)
command.setGap(2)
command.setCls()
command.setText(100, 10, "TSS24.BF2", 2, 2, "Aromas")
command.setText(40, 70, "TSS24.BF2", 1, 1, "测试打印")
command.setText(230,120,"TSS24.BF2", 4, 4, "65")
//command.setQR(50, 50, "L", 5, "A", "977767937@qq.com")
command.setBar(20, 110,"128", 100, 1, 2,0, "977767937239")
command.setPagePrint()
devicesConfig.senBlData(deviceId, serviceId, characteristicId,command.getData())
},
}
}
</script>
<style lang="scss" scoped>
page {
background-color: #f8f8f8;
}
.help-container {
margin-bottom: 100rpx;
padding: 30rpx;
}
.list-title {
margin-bottom: 30rpx;
}
.childList {
background: #ffffff;
box-shadow: 0px 0px 10rpx rgba(193, 193, 193, 0.2);
border-radius: 16rpx;
margin-top: 10rpx;
}
.line {
width: 100%;
height: 1rpx;
background-color: #F5F5F5;
}
.text-title {
color: #303133;
font-size: 32rpx;
font-weight: bold;
margin-left: 10rpx;
.iconfont {
font-size: 16px;
margin-right: 10rpx;
}
}
.text-item {
font-size: 28rpx;
padding: 24rpx;
}
.question {
color: #606266;
font-size: 28rpx;
}
</style>