|
|
// import './encoding.js'; // 如需要 中文乱码问题 new TextEncoder
|
|
|
const printInteraction = {
|
|
|
device_id: null,// 打印设备id
|
|
|
service_id: '',
|
|
|
write_id: '',
|
|
|
notify_id: '',
|
|
|
connFlag: false,
|
|
|
services: [],
|
|
|
stringData: [],
|
|
|
callback: function () {},
|
|
|
ab2hex: (buffer) => {//ArrayBuffer转16进度字符串示例
|
|
|
const hexArr = Array.prototype.map.call(
|
|
|
new Uint8Array(buffer),
|
|
|
function (bit) {
|
|
|
return ('00' + bit.toString(16)).slice(-2)
|
|
|
}
|
|
|
)
|
|
|
return hexArr.join('')
|
|
|
},
|
|
|
// 获取蓝牙状态是否开启 准备
|
|
|
getBluetooth: (callback) => {
|
|
|
const _this = printInteraction;
|
|
|
uni.getBluetoothAdapterState({
|
|
|
success(res) {
|
|
|
if (res.available) { // 蓝牙适配器是否可用
|
|
|
callback && _this.startSearch(callback)
|
|
|
} else {
|
|
|
uni.showToast({
|
|
|
title: '本机蓝牙不可用',
|
|
|
duration: 2000,
|
|
|
icon: 'none'
|
|
|
});
|
|
|
}
|
|
|
},
|
|
|
fail(err) {
|
|
|
uni.showToast({
|
|
|
title: '本机蓝牙不可用',
|
|
|
duration: 2000,
|
|
|
icon: 'none'
|
|
|
});
|
|
|
}
|
|
|
});
|
|
|
},
|
|
|
// 初始化蓝牙
|
|
|
init: () => {
|
|
|
const _this = printInteraction;
|
|
|
uni.openBluetoothAdapter({
|
|
|
success(res) {
|
|
|
uni.getBluetoothAdapterState({
|
|
|
success(res) {
|
|
|
if (res.available) { // 蓝牙适配器是否可用
|
|
|
if (res.discovering) { // 蓝牙适配器是否处于搜索状态
|
|
|
// 立即停止搜索 节约电
|
|
|
_this.stopSearch();
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
});
|
|
|
},
|
|
|
fail(err) {
|
|
|
setTimeout(function () {
|
|
|
uni.showToast({
|
|
|
title: '蓝牙打开失败,请打开蓝牙',
|
|
|
duration: 2000,
|
|
|
icon: 'none'
|
|
|
});
|
|
|
}, 200)
|
|
|
}
|
|
|
})
|
|
|
},
|
|
|
// 搜索附近蓝牙,并获取蓝牙列表
|
|
|
startSearch: (callback) => {
|
|
|
const _this = printInteraction;
|
|
|
uni.showLoading({
|
|
|
title: '正在搜索...'
|
|
|
});
|
|
|
uni.startBluetoothDevicesDiscovery({ // 开始搜索蓝牙设备
|
|
|
allowDuplicatesKey: true,
|
|
|
powerLevel: 'high',
|
|
|
success(res) {
|
|
|
setTimeout(function () {
|
|
|
uni.getBluetoothDevices({ // 获取蓝牙列表
|
|
|
success(re) {
|
|
|
callback(re)
|
|
|
},
|
|
|
fail(err) {
|
|
|
uni.showToast({
|
|
|
title: '获取设备失败',
|
|
|
duration: 2000,
|
|
|
icon: 'error'
|
|
|
});
|
|
|
}
|
|
|
});
|
|
|
_this.stopSearch();
|
|
|
uni.hideLoading();
|
|
|
}, 5000);
|
|
|
},
|
|
|
fail(err) {
|
|
|
uni.showToast({
|
|
|
title: '搜索失败',
|
|
|
duration: 2000,
|
|
|
icon: 'error'
|
|
|
});
|
|
|
}
|
|
|
})
|
|
|
},
|
|
|
// 连接蓝牙设备
|
|
|
connectDevice: (device_id) => {
|
|
|
const _this = printInteraction;
|
|
|
if (_this.device_id) {
|
|
|
// 对刚才的连接设备进行断开
|
|
|
_this.breakConnction();
|
|
|
}
|
|
|
if (device_id) {
|
|
|
uni.showLoading({
|
|
|
title: '正在连接'
|
|
|
});
|
|
|
uni.createBLEConnection({
|
|
|
// 这里的 deviceId 需要已经通过 createBLEConnection 与对应设备建立链接
|
|
|
deviceId:device_id,
|
|
|
success(res) {
|
|
|
_this.device_id = device_id;
|
|
|
uni.showToast({
|
|
|
title: '连接成功',
|
|
|
duration: 2000,
|
|
|
icon: 'error'
|
|
|
});
|
|
|
// 安卓设备 需要等待1.5秒之后
|
|
|
_this.getDeviceService();
|
|
|
},
|
|
|
fail(err) {
|
|
|
uni.showToast({
|
|
|
title: `连接失败!${err.code}`,
|
|
|
duration: 2000,
|
|
|
icon: 'none'
|
|
|
});
|
|
|
},
|
|
|
complete() {
|
|
|
uni.hideLoading();
|
|
|
}
|
|
|
});
|
|
|
} else {
|
|
|
uni.showToast({
|
|
|
title: '请选择蓝牙设备',
|
|
|
duration: 2000,
|
|
|
icon: 'error'
|
|
|
});
|
|
|
}
|
|
|
},
|
|
|
// 获取蓝牙设备所有服务
|
|
|
getDeviceService: () => {
|
|
|
const _this = printInteraction;
|
|
|
uni.getBLEDeviceServices({
|
|
|
deviceId: _this.device_id,
|
|
|
success(res) {
|
|
|
_this.services = res.services;
|
|
|
res.services.some(item => {
|
|
|
if (item.isPrimary) {
|
|
|
_this.service_id = item.uuid;
|
|
|
return true;
|
|
|
}
|
|
|
});
|
|
|
_this.getDeviceCharacter();
|
|
|
}
|
|
|
})
|
|
|
},
|
|
|
// 获取连接设备服务的所有特征值
|
|
|
getDeviceCharacter: () => {
|
|
|
const _this = printInteraction;
|
|
|
uni.getBLEDeviceCharacteristics({
|
|
|
deviceId: _this.device_id,
|
|
|
serviceId: _this.service_id,
|
|
|
success(res) {
|
|
|
let notify_id, write_id, read_id;
|
|
|
res.characteristics.forEach(item => {
|
|
|
if (item.properties.notify) {
|
|
|
notify_id = item.uuid;
|
|
|
}
|
|
|
if (item.properties.write) {
|
|
|
write_id = item.uuid;
|
|
|
}
|
|
|
if (item.properties.read) {
|
|
|
read_id = item.uuid;
|
|
|
}
|
|
|
});
|
|
|
if (notify_id != null && write_id != null) {
|
|
|
_this.notify_id = notify_id;
|
|
|
_this.write_id = write_id;
|
|
|
_this.read_id = read_id;
|
|
|
if (_this.connFlag) { // 发送失败进来自动再次点击 | 或手动点击按钮重新打印
|
|
|
_this.printer(_this.stringData, _this.callback);
|
|
|
}
|
|
|
}
|
|
|
},
|
|
|
fail(err) {
|
|
|
// _this.getDeviceService(); // 再次获取服务uuid(可能导致死循环 需要进行判断)
|
|
|
uni.showToast({
|
|
|
title: err.code || '没有找到特征值',
|
|
|
duration: 2000,
|
|
|
icon: 'error'
|
|
|
});
|
|
|
}
|
|
|
})
|
|
|
},
|
|
|
// 字符串转为ArrayBuffer
|
|
|
stringToArrayBuffer: (str) => {
|
|
|
const len = str.length * 2; // 一个中文占 二个字节, 其它字母 占二个字节
|
|
|
const buf = new ArrayBuffer(len);
|
|
|
const bufView = new Uint8Array(buf);
|
|
|
for (let i = 0, strLen = str.length; i < strLen; i++) {
|
|
|
// console.log('1',str.charCodeAt(i)); // 对特殊字符不支持 如:表情emoji,麻将图案等
|
|
|
// console.log('2',str.codePointAt(i)); // 对特殊字符可以支持
|
|
|
bufView[i] = str.charCodeAt(i);
|
|
|
}
|
|
|
return buf;
|
|
|
},
|
|
|
// 开始打印
|
|
|
printer: (stringData, callback) => {
|
|
|
const _this = printInteraction;
|
|
|
if (!_this.device_id) {
|
|
|
uni.showToast({
|
|
|
title: "请选择蓝牙设备",
|
|
|
duration: 2000,
|
|
|
icon: 'error'
|
|
|
});
|
|
|
return;
|
|
|
}
|
|
|
uni.showLoading({
|
|
|
title: '正在打印'
|
|
|
});
|
|
|
_this.connFlag = true;
|
|
|
_this.stringData = stringData;
|
|
|
_this.callback = callback;
|
|
|
let buffer = null;
|
|
|
stringData.forEach(item => {
|
|
|
_this._writeBLECharacteristicValue(_this.stringToArrayBuffer(item));
|
|
|
});
|
|
|
},
|
|
|
_writeBLECharacteristicValue: (buffer) => {
|
|
|
const _this = printInteraction;
|
|
|
// 字节长度小于等于20 只调用一次
|
|
|
if (buffer.byteLength <= 20) {
|
|
|
uni.writeBLECharacteristicValue({
|
|
|
deviceId: _this.device_id,
|
|
|
serviceId: _this.service_id,
|
|
|
characteristicId: _this.notify_id,
|
|
|
value: buffer,
|
|
|
writeType: "write", //iOS 优先 write,安卓优先 writeNoResponse
|
|
|
success(res) {
|
|
|
_this.connFlag = false;
|
|
|
_this.callback();
|
|
|
},
|
|
|
fail(err) {
|
|
|
// 换一个uuid获取特征值重新写入 (或者 手动去点击打印,可能需要连续点击多次)
|
|
|
if (_this.services.length) {
|
|
|
_this.services.splice(0, 1);
|
|
|
_this.services.some(item => {
|
|
|
if (item.isPrimary) {
|
|
|
_this.service_id = item.uuid;
|
|
|
return true;
|
|
|
}
|
|
|
});
|
|
|
_this.getDeviceCharacter();
|
|
|
}
|
|
|
},
|
|
|
complete() {
|
|
|
uni.hideLoading();
|
|
|
}
|
|
|
})
|
|
|
} else {
|
|
|
// 进行分包 最大20字节长度
|
|
|
const newBuffer = buffer.slice(20);
|
|
|
const writeBuffer = buffer.slice(0, 20);
|
|
|
uni.writeBLECharacteristicValue({
|
|
|
deviceId: _this.device_id,
|
|
|
serviceId: _this.service_id,
|
|
|
characteristicId: _this.notify_id,
|
|
|
value: writeBuffer,
|
|
|
writeType: "write", //iOS 优先 write,安卓优先 writeNoResponse
|
|
|
success(res) {
|
|
|
// console.log('递归发送成功 继续发送');
|
|
|
_this._writeBLECharacteristicValue(newBuffer);
|
|
|
},
|
|
|
fail(err) {
|
|
|
// console.log('递归发送失败', err.code);
|
|
|
// 一旦发生失败,就要重新发送一遍,(另有需求断点发送 可保存newBuffer变量)
|
|
|
uni.hideLoading();
|
|
|
if (_this.services.length) {
|
|
|
_this.services.splice(0, 1);
|
|
|
_this.services.some(item => {
|
|
|
if (item.isPrimary) {
|
|
|
_this.service_id = item.uuid;
|
|
|
return true;
|
|
|
}
|
|
|
});
|
|
|
_this.getDeviceCharacter();
|
|
|
}
|
|
|
}
|
|
|
})
|
|
|
}
|
|
|
},
|
|
|
// 停止搜索
|
|
|
stopSearch: () => {
|
|
|
uni.stopBluetoothDevicesDiscovery({
|
|
|
success(res) {}
|
|
|
})
|
|
|
},
|
|
|
// 关闭蓝牙适配器
|
|
|
closeBluetoothAdapter: () => {
|
|
|
uni.closeBluetoothAdapter({
|
|
|
success(res) {
|
|
|
console.log('关闭蓝牙适配器')
|
|
|
}
|
|
|
})
|
|
|
},
|
|
|
// 断开连接
|
|
|
breakConnction: () => {
|
|
|
const _this = printInteraction;
|
|
|
if (_this.device_id) {
|
|
|
uni.closeBLEConnection({
|
|
|
deviceId: _this.device_id,
|
|
|
success() {
|
|
|
_this.connFlag = false;
|
|
|
}
|
|
|
});
|
|
|
}
|
|
|
},
|
|
|
}
|
|
|
|
|
|
export default printInteraction; |