uni-app(android、ios) 使用蓝牙便携式打印机(热敏打印机)

这篇具有很好参考价值的文章主要介绍了uni-app(android、ios) 使用蓝牙便携式打印机(热敏打印机)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

机型等参数

  • HSPOS
  • 点密度:576点/行(8dots/mm,203dpi)
  • 接口类型: 蓝牙(Bluetooth2.0,4.0双模,支持Android,IOS)
  • 打印方式:图形打印(位图)
  • 打印指令集: ESC/POS

基本思路

1、 实现蓝牙连接

**B12.js方法封装

class BluetoothTools {
	constructor() { 
		this.decimalData = []; //获取buffer之前的二进制数据集合;
		this.deviceId = null;
		this.initStatus = 0; //蓝牙初始化结果;0:初始化中,1-成功;2-失败;
		this.linked = false; //蓝牙是否为连接状态;
		this.connectChangeHandler = null;
	}
	
	// 初始化;
	init(connectChangeHandler) {
		this.connectChangeHandler = connectChangeHandler;
		return new Promise((resolve, reject) => {
			uni.openBluetoothAdapter({
				success: res => {
					this.initStatus = 1;
					this.onConnectChange(connectChangeHandler)
					resolve(res)
				},
				fail: err => {
					this.initStatus = 2;
					console.log('蓝牙初始化失败:', err);
					this.toast('蓝牙不可用!')
					reject(err)
				}
			})
		})
	}
	// 获取蓝牙状态,是否可用
	checkCanUse() {
		return new Promise((resolve, reject) => {
			uni.getBluetoothAdapterState({
				success: res => {
					// console.log(res);
					resolve(res)
				},
				fail: err => {
					// console.log(err);
					reject(err)
				}
			})
		})
	} 
	// 开始搜索蓝牙
	startSearch(cb) {
		return new Promise(async (resolve, reject) => {
			// if (this.initStatus === 2) {
			// 	this.toast('蓝牙初始化失败!');
			// 	reject();
			// 	return false;
			// } else if (this.initStatus === 0) {
			// 	this.toast('蓝牙未初始化!');
			// 	reject();
			// 	return false;
			// }
			if (this.initStatus !== 1) {
				await this.init(this.connectChangeHandler);
			}

			this.onFound(cb);
			uni.startBluetoothDevicesDiscovery({
				allowDuplicatesKey: false,
				services: [],
				success: (res) => {
					// console.log('开始搜索蓝牙设备!', res);
					resolve(res)
				},
				fail: err => {
					// console.log('开启搜索失败:', err);
					this.toast('开始搜索失败!')
					reject(err)
				}
			})
		})
	}
	// 监听单一设备搜索结果
	onFound(cb) {
		uni.onBluetoothDeviceFound(res => {
			// console.log('蓝牙设备:', res.devices);
			cb(res.devices) 
		})
	}
	
	// 停止搜索;
	stopSearch() {
		return new Promise((resolve, reject) => {
			uni.stopBluetoothDevicesDiscovery({
				success: (res) => {
					resolve(res)
				},
				fail: (err) => {
					// this.toast('蓝牙停止搜索失败,请重试!');
					console.log('蓝牙停止搜索失败:', err);
					reject(err)
				}
			})
		})
	}
	// 关闭蓝牙模块(打印完后调用)
	closeAdapter() {
		return new Promise((resolve, reject) => {
			uni.closeBluetoothAdapter({
				success: res => {
					resolve(res);
				},
				fail: (err) => {
					console.log('关闭失败:', err);
					// this.toast('蓝牙模块关闭失败!')
					reject(err);
				}
			})
		})
	}
	toast(msg) {
		uni.showToast({
			title: msg,
			icon: 'none',
			duration: 2200
		})
	}
	// 根据deviceId连接蓝牙;
	connectBLE(deviceId) {
		return new Promise(async (resolve, reject) => {
			if (this.initStatus !== 1) {
				await this.init(this.connectChangeHandler).catch(err => {
					reject(err)
				});
			}
			this.checkCanUse().then(async data => {
				// console.log(data);
				if (data.available) {
					uni.createBLEConnection({
						deviceId: deviceId,
						success: (res) => {
							resolve(res)
						},
						fail: err => {
							console.log('蓝牙连接失败!', err);
							this.toast('蓝牙连接失败,请重试!')
							reject(err)
						}
					})
				} else {
					this.toast('蓝牙不可用')
					reject()
				}
			}).catch(err => {
				this.toast('蓝牙不可用!!')
				reject()
			})
		})
	}

	//  根据deviceId断开蓝牙链接;
	closeBLE(deviceId) {
		return new Promise((resolve, reject) => {
			if (!deviceId) {
				resolve();
				return;
			}
			uni.closeBLEConnection({
				deviceId: deviceId,
				success: (res) => {
					// console.log('蓝牙已断开!', res);
					resolve(res)
				},
				fail: err => {
					console.log('蓝牙断开失败!', err);
					// this.toast('蓝牙断开失败, 请重试!')
					reject(err)
				}
			})
		})
	}
	// 监听蓝牙连接状态;
	onConnectChange(cb) {
		uni.onBLEConnectionStateChange(res => {
			console.log('监听蓝牙连接状态:', res);
			if (res.connected) {
				this.linked = true;
				this.deviceId = res.deviceId;
			} else {
				this.linked = false;
				this.deviceId = null;
			}
			cb(res);
		})
	}
}

export default BluetoothTools;

*** vue文件中内容

<template>
	<view class="">
		<view class="bluetooth_container">
			<view class="title">
				已配对设备
			</view>
			<view class="matched_list" v-if="matchedList && matchedList.length">
				<view class="flex" v-for="(item, index) in matchedList" :key="item.deviceId" @longpress="showModal2(item.deviceId)">
					<image class="img" src="/static/print.png" mode=""></image>
					<text class="name">{{item.localName ? item.localName : item.name ? item.name : '--'}}</text>
					<text class="link linked" @click="showModal" v-if="linkedDeviceId === item.deviceId">已连接</text>
					<block v-else>
						<image v-if="selectedDeviceId==item.deviceId && isConnectting" class="load_img" src="/static/loadding.gif" mode=""></image>
						<text v-else class="link unlink" @click="connectHandler(item)">未连接</text>
					</block>
				</view>
			</view>
			<view class="empty_box" v-else>
				<u-empty mode="search" text="暂无配对设备,快快添加吧~"></u-empty>
			</view>
			<view class="block"></view>
			<view class="title search_title">
				<text>扫描可用设备</text>
				<view class="stop" v-if="isSearching" @click="stopSearch">
					<text>停止</text>
				</view>
				<view class="img_box" v-else @click="startSearch">
					<image class="img img1" src="/static/refresh.png" mode=""></image>
				</view>
				<view class="load_box" v-if="isSearching">
					<image class="load_img" src="/static/loadding.gif" mode=""></image>
				</view>
			</view>
			<view class="list">
				<view class="flex" v-for="(item, index) in deviceList" :key="index">
					<image class="img img2" src="/static/print.png" mode=""></image>
					<text class="name">{{item.localName ? item.localName : item.name ? item.name : '--'}}</text>
					<image v-if="selectedDeviceId==item.deviceId && isConnectting" class="load_img" src="/static/loadding.gif" mode=""></image>
					<text v-else class="link" @click="connectHandler(item,index)">连接</text>
				</view>
			</view>
		</view>
		
		<u-modal v-model="modalShow" show-cancel-button content="是否断开连接?" @confirm="closeConnect"></u-modal>
		<u-modal v-model="modalShow2" show-cancel-button content="是否忽略此设备?" @confirm="deleteDevice"></u-modal>

	</view>
</template>

<script>
	import B12s from '@/common/b12s.js';
	const b12s = new B12s();
	export default {
		data() {
			return {
				// 蓝牙相关;
				matchedList: [], //已配对的列表;
				deviceList: [], //搜索到的设备列表;
				initCode: 0, //蓝牙初始化结果;0:初始化中,1-成功;2-失败;
				selectedDeviceId: '', //当前操作的蓝牙设备id; 
				isConnectting: false, //蓝牙正在连接中;
				linkedDeviceId: '', //已连接的蓝牙mac地址;
				isSearching: false, //是否正在搜索蓝牙设备;

				b12s: null, //蓝牙工具;
			}
		},
		async onLoad(options) {
			this.initBluetooth();
		},
		async onUnload() {
			this.stopSearch();
			b12s.closeBLE(this.linkedDeviceId);
			b12s.closeAdapter();
		},
		methods: {
			// 初始化蓝牙;
			async initBluetooth() {
				this.getMatchedList();
				await b12s.init(this.onConnectChange);
				this.autoConnect();
			},
			// 如果有配对历史,自动连接最后一个;
			autoConnect() {
				let length = this.matchedList.length
				if (length <= 0) return;
				let item = this.matchedList[length - 1];
				this.connectHandler(item);
			},
			// 开始搜索蓝牙;
			async startSearch() {
				await b12s.startSearch(this.getDeviceList);
				this.isSearching = true;
			},
			// 停止搜索
			async stopSearch() {
				await b12s.stopSearch();
				this.isSearching = false;
			},
			// 获取历史配对列表;
			getMatchedList() {
				let list = uni.getStorageSync('__bluetooth_list_');
				if (list) {
					this.matchedList = list;
				}
				console.log(this.matchedList);
			},
			// 获取可用设备列表;
			getDeviceList(devices) {
				for (let i = 0; i < devices.length; i++) {
					let name = devices[i].name || devices[i].localName;
					if (name) {
						let dLIndex = this.deviceList.findIndex(item => item.deviceId === devices[i].deviceId);
						let mLIndex = this.matchedList.findIndex(item => item.deviceId === devices[i].deviceId);
						if (dLIndex < 0 && mLIndex < 0) {
							this.deviceList.push({
								name: name,
								deviceId: devices[i].deviceId
							})
						}
					}
				}
			},
			// 点击连接;
			async connectHandler(item, index = -1) {
				this.stopSearch();
				await b12s.closeBLE(this.linkedDeviceId)
				this.selectedDeviceId = item.deviceId;
				this.isConnectting = true;
				await b12s.connectBLE(item.deviceId).catch(err => {
					this.isConnectting = false;
				});
				// this.linkedDeviceId = item.deviceId;
				this.isConnectting = false;
				let indexRes = this.matchedList.findIndex(itm => itm.deviceId === item.deviceId);
				if (indexRes < 0) {
					this.matchedList.push(item);
					index !== -1 && this.deviceList.splice(index, 1);
					this.saveStorage()
				}
			},
			// 断开连接
			closeConnect() {
				b12s.closeBLE(this.linkedDeviceId);
				this.modalShow = false;
			},
			// 监听蓝牙连接状态;
			onConnectChange(res) {
				if (res.connected) {
					// this.$u.toast('蓝牙已连接');
					this.linkedDeviceId = res.deviceId;
				} else {
					// this.$u.toast('蓝牙已断开');
					this.linkedDeviceId = '';
				}
			},
			// 删除已缓存设备;
			deleteDevice() {
				this.matchedList = this.matchedList.filter(item => item.deviceId !== this.selectedDeviceId);
				this.saveStorage()
			},
			// 缓存已配对蓝牙;
			saveStorage() {
				uni.setStorageSync('__bluetooth_list_', this.matchedList)
			}
		}
	}
</script>

<style lang="scss" scoped>

	.bluetooth_container {
		padding: 30rpx;

		.load_img {
			width: 40rpx;
			height: 40rpx;
		}

		.title {
			font-size: 34rpx;
			font-weight: bold;

			.img {
				margin-left: 20rpx;
				vertical-align: middle;
				width: 36rpx;
				height: 36rpx;
			}
		}

		.search_title {
			display: flex;
			justify-content: space-between;
			margin-top: 60rpx;

			.img_box {
				flex: 1;
			}

			.load_img {
				width: 40rpx;
				height: 40rpx;
			}

			.stop {
				flex: 1;
				margin-left: 30rpx;

				text {
					font-size: 24rpx;
					font-weight: normal;
					background-color: #fa3534;
					color: #ffffff;
					padding: 10rpx 20rpx;
					border-radius: 30rpx;
				}
			}
		}

		.matched_list {
			// padding: 30rpx 0;

			.flex {
				display: flex;
				margin: 30rpx 0;
				justify-content: space-between;
				align-items: center;

				.img {
					width: 40rpx;
					height: 40rpx;
				}

				.name {
					flex: 1;
					margin-left: 40rpx;
				}

				.link {
					padding: 10rpx 40rpx;
					background-color: #F2F2F2;
					border-radius: 40rpx;
					font-size: 28rpx;
				}

				.unlink {
					color: #606266;
				}

				.linked {
					color: #19be6b;
				}
			}
		}

		.empty_box {
			padding: 90rpx 0;
		}

		.list {
			.flex {
				display: flex;
				margin: 30rpx 0;
				justify-content: space-between;
				align-items: center;

				.img {
					width: 40rpx;
					height: 40rpx;
				}

				.name {
					flex: 1;
					margin-left: 40rpx;
				}

				.link {
					padding: 10rpx 40rpx;
					background-color: #F2F2F2;
					border-radius: 40rpx;
					color: #2979ff;
					font-size: 28rpx;
				}
			}
		}

		.btns {
			display: flex;
			justify-content: space-around;
			margin-top: 200rpx;

			.btn {
				margin: 0;
				width: 40%;
			}
		}
	}

</style>

2、获取位图信息

vue页面中拿到像素(位图)信息;

<template>
	<view class="">
		<canvas id="canvas" canvas-id="canvas" class="canvas"></canvas>
	</view>
</template>

<script>
	import B12s from '@/common/b12s.js';
	const b12s = new B12s();
	export default {
		methods: {
			//画图;
			drawImage() {
				const ctx = uni.createCanvasContext('canvas');
				uni.chooseImage({
				  success: res => {
					ctx.drawImage(res.tempFilePaths[0], 0, 0, 150, 100)
					ctx.draw()
				  }
				})
			},
			// 获取canvas的像素信息;
			getImageInfo() {
				return new Promise((resolve, reject) => {
					uni.canvasGetImageData({
						canvasId: 'canvas',
						x: 0,
						y: 0,
						width: _this.canvas2ImgWidth, 
						height: _this.canvas2ImgHeight,
						success(res) {
							resolve(res)
						},
						fail: err => {
							this.$u.toast('获取图片数据失败')
							reject(err)
						}
					})
				})
			},
			async printHandler() {
				uni.hideLoading();
				uni.showLoading({
					title: '打印中',
					mask: true
				})
				const res = await this.getImgInfo();
				b12s.printImage(res)
			}
		}
	}
</script>

3、开始打印;

b12s.js

class BluetoothTools {
	constructor() {
		this.commands = {
			init: [0x1b, 0x40], // 清理buffer数据,重置模式;ASC2: ESC @
			print: [0x0a], //开始打印;
			printL5: [0x1b, 0x64, 0x05],
			printL6: [0x1b, 0x64, 0x06],
			printL8: [0x1b, 0x64, 0x08],
			printL10: [0x1b, 0x64, 0x10],
		}
		this.decimalData = []; //获取buffer之前的二进制数据集合;
		this.deviceId = null;
		this.initStatus = 0; //蓝牙初始化结果;0:初始化中,1-成功;2-失败;
		this.linked = false; //蓝牙是否为连接状态;
		this.timer = null;
		this.writeTime = 0;
		this.byteLength = this.isAndroid() ? 200 : 500;
		this.connectChangeHandler = null;
	}
	/**
	 * 低功耗蓝牙API
	 */
	// 根据deviceId 设置传输字节最大值;
	setMTU(deviceId) {
		return new Promise((resolve, reject) => {
			uni.setBLEMTU({
				deviceId: deviceId,
				mtu: 512,
				success: (res) => {
					console.log('设置MTu成功', res);
					resolve(res)
				},
				fail: (err) => {
					console.log('设置mtu失败', err);
					this.toaset('设置mtu失败!')
					reject(err)
				}
			})
		})
	}
	// 根据deviceId/mac地址 查询serviceId列表;
	getServiceId(deviceId) {
		return new Promise((resolve, reject) => {
			uni.getBLEDeviceServices({
				deviceId: deviceId,
				success: res => {
					resolve(res)
				},
				fail: err => {
					console.log('获取serviceId失败', err);
					reject(err)
				}
			})
		})
	}
	// 根据deviceId 和 serviceId 获取特征Id;
	getCharId(deviceId, serviceId) {
		return new Promise((resolve, reject) => {
			uni.getBLEDeviceCharacteristics({
				deviceId: deviceId,
				serviceId: serviceId,
				success: res => {
					resolve(res)
				},
				fail: err => {
					console.log('获取特征id失败', err);
					reject(err)
				}
			})
		})
	}

	// 写入数据;
	writeBLE(deviceId, serviceId, charId, buffer) {
		// console.log(deviceId, serviceId, charId, buffer.byteLength);
		// return;
		let _this = this;
		return new Promise((resolve, reject) => {
			uni.writeBLECharacteristicValue({
				deviceId: deviceId, //设备Id、mac地址;
				serviceId: serviceId, //服务id;
				characteristicId: charId, //特征id;
				value: buffer, //指令buffer数据;
				writeType: 'write', //'writeNoResponse',
				success: res => {
					// console.log('数据写入成功', res);
					_this.writeTime = 0;
					resolve(res)
				},
				fail: err => {
					console.log('写入失败:', Date.now());
					reject(err);
				}
			})
		})
	}
	

	/**
	 * 具体功能实现
	 */
	// 打印传入的位图信息
	async printImage(res) {
		if (!this.deviceId) {
			this.toast('未检测到蓝牙设备id');
			this.hideLoading()
			return;
		}
		this.isAndroid() && await this.setMTU(this.deviceId);
		const imgArr = this.getImgArray(res);
		// return;
		const { serviceId, charId } = await this.getWriteIds(this.deviceId);
		this.startPrint(this.deviceId, serviceId, charId, imgArr);
	}
	// 开始打印;
	async startPrint(deviceId, serviceId, charId, cmd) {
		// 初始化;
		let initArr = Array.from(this.commands.init).concat(Array.from(this.commands.print));
		let initBuffer = new Uint8Array(initArr).buffer;
		await this.writeMidWare(deviceId, serviceId, charId, initBuffer)
		// let cmds = Array.from(this.commands.init).concat(Array.from(cmd)).concat(Array.from(this.commands.printL10));
		// 分别传输指令;
		let cmds = Array.from(cmd);
		console.log(cmds.length);
		if (cmds.length > this.byteLength) {
			let cmdArrs = [];
			let newCmds = Array.from(cmds);
			let length = Math.ceil(cmds.length / this.byteLength);
			for (let i = 0; i < length; i++) {
				cmdArrs.push(newCmds.slice(this.byteLength * i, this.byteLength * (i + 1)));
			}
			for (let i = 0; i < cmdArrs.length; i++) {
				console.log(i, cmdArrs.length);
				let buffer = new Uint8Array(cmdArrs[i]).buffer;
				await this.writeMidWare(deviceId, serviceId, charId, buffer)
			}
		} else {
			let buffer = new Uint8Array(cmds).buffer;
			cmds.length && await this.writeMidWare(deviceId, serviceId, charId, buffer)
		}
		// 打印空行;
		let printLCmd = Array.from(this.commands.printL5);
		let printLBuffer = new Uint8Array(printLCmd).buffer;
		await this.writeMidWare(deviceId, serviceId, charId, printLBuffer);
	}
	// 处理安卓写入失败的问题;
	writeMidWare(deviceId, serviceId, charId, buffer) {
		let _this = this;
		return new Promise((resolve, reject) => {
			this.writeBLE(deviceId, serviceId, charId, buffer).then(res => {
				resolve(res)
			}).catch(err => {
				// console.log(111111, _this.writeTime);
				if (_this.writeTime < 50) {
					_this.writeTime++;
					return new Promise((reso, reje) => {
						clearTimeout(this.timer)
						this.timer = setTimeout(() => {
							reso(this.writeMidWare(deviceId, serviceId, charId, buffer))
						}, 100)
					})
				} else {
					_this.writeTime = 0;
					_this.hideLoading();
					_this.toast('数据写入失败,请走纸后重试!');
					reject(err);
				}
			}).then(res => {
				resolve(res)
			})
		})
	}
	// 位图信息转换为打印指令;
	getImgArray(res) {
		var w = res.width;
		var width = parseInt((res.width + 7) / 8 * 8 / 8);
		var height = res.height;
		let data = [29, 118, 48, 0];
		// let data = [0x1d, 0x76, 0x30, 0];
		data.push(parseInt(width % 256));
		data.push(parseInt(width / 256));
		data.push(parseInt(res.height % 256));
		data.push(parseInt(res.height / 256));
		var bits = new Uint8Array(height * width);
		for (let y = 0; y < height; y++) {
			for (let x = 0; x < w; x++) {
				var color = res.data[(y * w + x) * 4 + 1];
				if (color > 128) {
					bits[parseInt(y * width + x / 8)] |= (0x80 >> (x % 8));
				}
			}
		}

		for (let i = 0; i < bits.length; i++) {
			data.push((~bits[i]) & 0xFF)
		}
		return data;
	}
	// 获取写入数据需要的ids;
	async getWriteIds(deviceId) {
		return new Promise(async (resolve, reject) => {
			let serviceIdData = await this.getServiceId(deviceId);
			let services = serviceIdData.services;
			// console.log(services);
			let charId,
				serviceId;
			for (let i = 0; i < services.length; i++) {
				const chars = await this.getCharId(deviceId, services[i].uuid);
				// console.log(services[i].uuid, chars);
				const charItem = chars.characteristics.filter(item => item.properties.write)[0];
				if (charItem) {
					charId = charItem.uuid;
					serviceId = services[i].uuid;
					// break;
					// console.log(charId, serviceId);
				}
			}
			resolve({ charId: charId, serviceId: serviceId })
		})
	}
	isAndroid() {
		return uni.getSystemInfoSync().osName === 'android'
	}
}

export default BluetoothTools;

1、安卓设备有数据限制,如果传输数据过多。虽然writeBLE回调成功,但是会丢数据。可能会导致打印错乱、打印乱码。有些机型会直接不打印。

2、安卓设备必须要用到 writeMidware中的循环写入数据方式。将初始化,写入数据、打印空行这三个步骤分开。

所有的安卓设备都可能会在写入数据的时候,写入失败。一般过200ms后重新写入可能会成功,本方法中,是按照正常方式循环写入数据。一旦失败后会延迟100ms写入数据,不断尝试最多50次。

关于文中栅格位图涉及到的进制转换;

十六进制有两个字节组成,每个字节八位。每个字节有2的8次方=256种;256*256=65536;所以是从0-65535;而65536转为16进制是0x10000;所以这里两个字节的十六进制最大是0xffff;
高位字节0xff;低位字节也是0xff;
576转为十六进制是0x240;高位是0x02;低位是0x40;
576 % 256 = 64;//低位; Math.floor(576 / 256) = 2;//高位;
而64转为十六进制就是 0x40; 2转为十六进制0x02;
所以位图的长度表达方式为:L + H * 256 ; 64 + 2 * 256 = 576;

打印txt文本

图片打印,数据太大容易导致打印乱码。而且ios报错机制不完善,采用node包"text-encoding-gbk”进行编码打印文字又快又不容易出错文章来源地址https://www.toymoban.com/news/detail-618649.html

// 字符串转buffer;
	const Encoder = require('text-encoding-gbk');
	textEncode(text = "") {
		var uint8array = new Encoder.TextEncoder(
			'gb18030', { NONSTANDARD_allowLegacyEncoding: true }).encode(text); 
		return uint8array;
	}
	//

到了这里,关于uni-app(android、ios) 使用蓝牙便携式打印机(热敏打印机)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 『uni-app、小程序』蓝牙连接、读写数据全过程

    点赞 + 关注 + 收藏 = 学会了 这是一次真实的 蓝牙收发数据 的全过程讲解。 本文使用 uni-app + Vue3 的方式进行开发,以手机app的方式运行(微信小程序同样可行)。 uni-app 提供了 蓝牙 和 低功耗蓝牙 的 api ,和微信小程序提供的 api 是一样的,所以本文的讲解也 适用于微信小程序

    2024年02月09日
    浏览(61)
  • 记录--『uni-app、小程序』蓝牙连接、读写数据全过程

    这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助 这是一次真实的 蓝牙收发数据 的全过程讲解。 本文使用 uni-app + Vue3 的方式进行开发,以手机app的方式运行(微信小程序同样可行)。 uni-app 提供了 蓝牙 和 低功耗蓝牙 的 api ,和微信小程序提供的 api 是一样

    2024年01月21日
    浏览(15)
  • 网安工具 | Windows便携式渗透测试环境PentestBox入门到进阶使用指南

    [ 点击 👉 关注「 全栈工程师修炼指南」公众号 ] 微信改版了,现在看到我们全凭缘分,为了不错过【全栈工程师修炼指南】重要内容及福利,大家记得按照上方步骤设置「接收文章推送」哦~ 希望各位看友多多支持【关注、点赞、评论、收藏、投币】,助力每一个梦想。 【

    2024年02月08日
    浏览(12)
  • uni-app实现跨端开发手机蓝牙接收和发送数据

    最近接触uni-app夸终端开发手机蓝牙模块的接收和发送数据功能, 手机蓝牙模块接发收数据主要流程步骤如下: 1、初始化手机蓝牙 2、根据设备id获取蓝牙服务, 3、根据蓝牙服务获取对应的蓝牙特征值 4、监听蓝牙特征值数值变化,发送对应数据到蓝牙特征值 具体

    2024年02月12日
    浏览(15)
  • uni-app 微信小程序蓝牙模块的解耦封装-持续更新

    core.js tool.js util.js main.js

    2024年03月27日
    浏览(53)
  • uni-app打包ios的步骤

    注意:下面的操作必须同时满足三个条件,且这三个条件都是必须得: 1.有一个苹果开发者账号(要收费) 2.有一台苹果笔记本(在笔记本上生成证书和文件) 3.有一部苹果手机(用于测试app的功能) 使用uniapp发布ios的应用的步骤如下: 点击发行——原生app——云打包 出现页面如下

    2024年02月09日
    浏览(24)
  • uni-app 打包 ios 测试包,通过 testFlight 分发测试

    如果觉得麻烦的,可以使用替代品,使用蒲公英进行测试版本发布,效果是一样的,还没有 testFlight 复杂 1、申请 ios 证书 (私钥证书)和描述文件(证书profile) 申请方式通过uni-app介绍进行申请,地址:https://ask.dcloud.net.cn/article/152 2、申请证书时,请牢记相关的账号密码,以及相

    2023年04月20日
    浏览(13)
  • 《详细》使用ventoy制作linux to go和win to go放在u盘中《即走即用的便携式系统》,自带系统引导

    高效,很多同学打造了自己的专属系统和浏览器后!如果需要去实验室学习来回携带电脑!十分不便!你是否想在别人的计算机上使用自己的系统呢? 部署docker!docker的重要性不言而喻,很多大佬有趣的项目都是支持docker的! 遇到系统损坏蓝屏死机,进入u盘系统,从而实现

    2024年02月03日
    浏览(66)
  • uni-app 获取android相册

    在uni-app中提供的封装好的api中没有提供获取手机相册的能力,只能打开相册后由用户选择其中的照片,而插件库中提供的获取相册的插件都是收费的,这里为大家分享一个可以自己获取android相册的代码段:

    2024年02月11日
    浏览(17)
  • uni-app之android原生插件开发

    一 插件简介 1.1 当HBuilderX中提供的能力无法满足App功能需求,需要通过使用Andorid/iOS原生开发实现时,可使用App离线SDK开发原生插件来扩展原生能力。 1.2 插件类型有两种,Module模式和Component模式 Module模式:能力扩展,无嵌入窗体的UI控件。大部分插件都是属于此类,比如调

    2024年02月07日
    浏览(15)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包