iOS App → **TCP Socket** → 局域網 POS 打印機 (IP:Port) → **ESC/POS 指令流** → 打印輸出。
// Swift - 使用 NWConnection (Network 框架, iOS 12+)
import Network
let host = NWEndpoint.Host("192.168.1.100")
let port = NWEndpoint.Port(9100) // 常見端口
let connection = NWConnection(host: host, port: port, using: .tcp)
connection.stateUpdateHandler = { state in
switch state {
case .ready: print("已連接"); sendPrintData(connection)
case .failed(let err): print("連接失敗: \(err)")
default: break
}
}
connection.start(queue: .global())
打印機不識別 HTML/CSS,**只識別 ESC/POS 二進制指令**。常用指令:
| 功能 | 指令 (十六進制) | 說明 |
|---|---|---|
| 初始化 | `1B 40` | ESC @ - 重置打印機 |
| 對齊 | `1B 61 n` | ESC a - n=0左,1中,2右 |
| 字體放大 | `1D 21 n` | GS ! - n=高4位寬放大,低4位高放大 (如 0x11=雙高雙寬) |
| 粗體 | `1B 45 1` / `1B 45 0` | ESC E - 開/關 |
| 換行 | `0A` | LF |
| 切紙 | `1D 56 00` / `1D 56 01` | GS V - 全切/半切 |
| 打印文本 | 文本內容字節 (UTF-8/GBK) | 需確認打印機編碼模式 |
| 打印圖片 | `1D 76 30 00` + 圖片數據 | GS v 0 - 光柵圖片打印 (較複雜) |
| 設置行間距 | `1B 33 n` | ESC 3 - n=點數 (默認30) |
func sendPrintData(_ connection: NWConnection) {
var commands = [UInt8]()
// 初始化
commands += [0x1B, 0x40]
// 標題:居中、雙高雙寬、粗體
commands += [0x1B, 0x61, 0x01] // 居中
commands += [0x1D, 0x21, 0x11] // 雙高雙寬
commands += [0x1B, 0x45, 0x01] // 粗體開
let title = "訂單詳情\n".data(using: .utf8)! // 或 GBK
commands += title
commands += [0x1B, 0x45, 0x00] // 粗體關
commands += [0x1D, 0x21, 0x00] // 恢復正常大小
commands += [0x0A] // 換行
// 內容:左對齊、正常字體
commands += [0x1B, 0x61, 0x00] // 左對齊
let items = "商品A x 1 ¥10.00\n商品B x 2 ¥20.00\n".data(using: .utf8)!
commands += items
commands += [0x0A]
// 總計:右對齊、加粗
commands += [0x1B, 0x61, 0x02] // 右對齊
commands += [0x1B, 0x45, 0x01]
let total = "總計: ¥50.00\n".data(using: .utf8)!
commands += total
commands += [0x1B, 0x45, 0x00]
// 切紙
commands += [0x1D, 0x56, 0x00]
// 發送
let data = Data(commands)
connection.send(content: data, completion: .contentProcessed { err in
if let err = err { print("發送失敗: \(err)") }
else { print("發送完成"); connection.cancel() }
})
}
connection.stateUpdateHandler = { state in
switch state {
case .waiting(let err):
// 等待網絡恢復,可延遲重試
DispatchQueue.global().asyncAfter(deadline: .now() + 5) {
connection.restart()
}
case .cancelled: break
default: break
}
}
class PrintManager {
static let shared = PrintManager()
private var connection: NWConnection?
func connect(ip: String, port: UInt16, completion: @escaping (Bool) -> Void) {
// ... 建立連接 ...
}
func printOrder(_ order: Order) {
// 構建 ESC/POS 數據 ...
send(data)
}
private func send(_ data: Data) {
connection?.send(content: data, completion: .contentProcessed { _ in })
}
}
**Socket 只是傳輸管道,格式自定義全靠 ESC/POS 指令**。掌握**「初始化 → 字體/對齊/屬性設置 → 發送文本/圖片數據 → 切紙」**指令流構建模式,配合**編碼轉換 (GBK/UTF-8)**、**斷線重連**、**封裝管理類**,即可實現靈活、穩定的 POS 打印功能。參考文檔:打印機廠商提供的《ESC/POS 指令編程手冊》。