如何在.NET MAUI中基于SPP和Protobuf实现蓝牙经典POS终端打印
解决方案
1. 序列化AcquireReceipt为Protobuf格式
首先完成Protobuf定义补全与C#类生成:
- 补全终端proto中缺失的
common.Money和Receipt定义(需匹配终端实际协议),完整proto示例:
syntax = "proto3"; package com.uaepay.pos.ecr.acquire; import "common/money.proto"; enum Receipt { CUSTOMER_RECEIPT = 0; MERCHANT_RECEIPT = 1; } message AcquireReceipt { common.Money amount = 1; optional string subject = 2; optional string paymentMethod = 3; optional string reserved = 4; } message ReceiptsRequest { string orderNo = 1; repeated Receipt receipts = 2; repeated AcquireReceipt acquireReceipts = 3; // 与终端协议匹配的字段,用于携带收据详情 }
- 安装依赖:通过NuGet安装
Google.Protobuf和Google.Protobuf.Tools。 - 生成C#类:使用
protoc命令或Visual Studio Protobuf工具链,将proto文件编译为C#实体类。
序列化代码示例:
// 实例化金额对象(需匹配终端金额格式,比如用整数表示分) var money = new Common.Money { Currency = "AED", Amount = 10000 // 代表100.00 AED }; // 实例化AcquireReceipt var acquireReceipt = new Com.Uaepay.Pos.Ecr.Acquire.AcquireReceipt { Amount = money, Subject = "Test Purchase", PaymentMethod = "CreditCard" };
2. 结合现有蓝牙代码发送序列化数据
修改现有代码,将AcquireReceipt整合到符合终端要求的ReceiptsRequest中,再序列化发送:
var bluetoothAdapter = BluetoothAdapter.DefaultAdapter; var device = bluetoothAdapter.BondedDevices.FirstOrDefault(pd => pd.Name == "Pos-terminal") ?? throw new InvalidOperationException("未找到绑定的POS终端"); using var socket = device.CreateRfcommSocketToServiceRecord(UUID.FromString("00001101-0000-1000-8000-00805f9b34fb"))!; socket.Connect(); // 构建符合终端要求的ReceiptsRequest var request = new Com.Uaepay.Pos.Ecr.Acquire.ReceiptsRequest { OrderNo = "1234", Receipts = { Com.Uaepay.Pos.Ecr.Acquire.Receipt.CustomerReceipt }, AcquireReceipts = { acquireReceipt } }; // 序列化为字节数组 var bytes = request.ToByteArray(); // 通过蓝牙发送数据 var outputStream = socket.OutputStream!; outputStream.Write(bytes, 0, bytes.Length); outputStream.Flush(); socket.Close();
注意:若终端对消息结构有特殊要求(比如嵌套方式不同),需根据实际proto定义调整对象构建逻辑,确保序列化后的字节完全匹配终端协议。
3. 触发POS终端打印收据
终端接收格式正确的Protobuf数据后,通常会自动触发打印逻辑,需注意以下细节:
- 确保发送的
ReceiptsRequest完全匹配/acquire/refund/receipts/print端点的字段要求,包括枚举值、字段顺序、可选字段的填充规则。 - 部分终端要求在Protobuf数据后发送结束标识(比如
\r\n),可在Flush()后添加:var endMarker = Encoding.ASCII.GetBytes("\r\n"); outputStream.Write(endMarker, 0, endMarker.Length); outputStream.Flush(); - 增加异常捕获与重试逻辑,避免蓝牙连接不稳定导致的发送失败:
try { // 蓝牙连接与发送代码 } catch (IOException ex) { // 处理连接异常,比如重试连接或提示用户 }
内容的提问来源于stack exchange,提问作者DPTP
相关产品推荐
相关产品推荐

