我在构建 ECR(电子收银机)和 Android POS 之间的集成时遇到问题。我正在研究 android POS,我想计算消息大小并将其添加到“2 字节,二进制”中。
我有这段代码来计算并生成完整的消息
fun generateMessage(message: String): String {
return buildString {
append(Constants.DIRECTION)
append(AppData.getProtocolVariant())
append(AppData.getProtocolVersion())
append(message)
val buffer = ByteBuffer.allocate(2)
buffer.putShort(message.length.toShort())
insert(0, buffer.array().decodeToString())
}
}
但是此代码仅适用于非常小的消息,因为在日志中我可以看到,对于较大的消息,此代码会添加 3 位数字并且通信失败。
完整消息的形式为
当我发送一条简单的消息“E/000”(十六进制转储 45 2f 30 30 30)时,代码起作用并且 ECR 接受它,并且在日志中我看到“��POS0110E/000”,当我看到更大的消息时像这样的“���POS0110R/S852484/RDLF****16/T93/M0/C00/DMastercard:00:0000***1234:200:200:0:0:0:1:80 3:2:133030119089:193439:497853:20230926115814:0”
其中消息大小为 3 位数字,但失败了。
那么我如何创建此消息并遵循协议
override fun sendMessage(message: String) {
val finalMessage = Utils.generateMessage(message)
server.sendMessage(finalMessage.encodeToByteArray()) }
`
将代码更改为
fun sendMessage(bytes: ByteArray) {
coroutineScope.launch(Dispatchers.IO) {
val outputStream = socket?.getOutputStream()
outputStream?.write(bytes)
outputStream?.flush()
}
}`
仍然不被接受
您需要将字节写入
OutputStream
,而不是String
。您应该更改 generateMessage()
方法以返回 ByteArray
而不是 String
,如下所示:
fun generateMessage(message: String): ByteArray {
val x = buildString {
append(Constants.DIRECTION)
append(AppData.getProtocolVariant())
append(AppData.getProtocolVersion())
append(message)
}
// Create byte array containing 2-byte message length (binary) followed
// by the actual message
val buffer = ByteBuffer.allocate(2 + x.length)
buffer.putShort(x.length.toShort())
buffer.put(x.getBytes())
return buffer
}
另请注意,消息长度(根据您粘贴的指南中的示例)是整个消息的长度(包括标头:方向、协议版本等)。在您的代码中,您仅使用了实际消息的长度(不包括标头数据)。
正如评论中所说,我们不能使用字符串来构造二进制消息。字符串用于文本,它们不能正确保存二进制数据。要处理二进制数据,我们必须使用
ByteArray
或其他类似的缓冲区。
我可能无法复制你的确切情况,但它应该是这样的:
@OptIn(ExperimentalStdlibApi::class)
fun main() {
val msg = generateMessage("Hello world!")
println(msg.decodeToString()) // ??POS0110Hello world!
println(msg.toHexString()) // 0013504f533031313048656c6c6f20776f726c6421
}
fun generateMessage(message: String): ByteArray {
val baos = ByteArrayOutputStream()
val out = DataOutputStream(baos)
val data = message.toByteArray(Charsets.US_ASCII)
out.writeShort(data.size + 7)
out.write(Constants.DIRECTION)
out.write(AppData.getProtocolVariant())
out.write(AppData.getProtocolVersion())
out.write(data)
return baos.toByteArray()
}
object Constants {
val DIRECTION = "POS".toByteArray(Charsets.US_ASCII)
}
object AppData {
fun getProtocolVariant() = "01".toByteArray(Charsets.US_ASCII)
fun getProtocolVersion() = "10".toByteArray(Charsets.US_ASCII)
}
大小标头为
0013
(十六进制),因此为 19。这是正确的,因为 POS0110Hello world!
是 19 个字节。
请注意,我们在这里使用大端。这与示例图像中提供的格式匹配。