Files
desktop-plugin/README.md
T
dzc 689a07ca44 feat: 饭卡打印助手 Flutter 版(Phase 1/2:协议服务器 + macOS CUPS 真机打印)
- 协议与 C# 版 card-printer-agent 逐字段对齐(38200-38202 顺延、CORS *、串行任务队列、30 分钟保留)
- macOS CUPS 后端:lpoptions 队列发现 + lp 参数列表提交(LC_ALL=C 防本地化粘连坑)
- --mock 模拟模式 + bin/agent.dart headless 入口 + 测试卡生成工具
- 真机验收:HiTi CS-200e status 就绪 + 真实出卡;macOS 通用二进制构建通过
- App Sandbox 已关闭(服务需绑回环端口并调用 lp 子进程);zaxprint URL scheme 已注册
2026-09-21 12:03:27 +08:00

4.5 KiB
Raw Blame History

desktop-plugin(饭卡打印站客户端 · Flutter 版)

用 Flutter 重写打印站客户端,替代 C# 版 card-printer-agent。HTTP 协议完全不变,前端(biz-pc-cloud-zax/src/api/plugin/cardPrinter.ts)零改动,两版助手可并存灰度替换。

  • 目录名 desktop-plugin,Dart 包名 desktop_plugin(Dart 标识符不允许连字符)
  • macOS bundle id:com.zax.desktop-plugin(macos/Runner/Configs/AppInfo.xcconfig)
  • 总体计划见 ../card-printer-agent/flutter-client-plan.md

协议(与 C# 版逐字段对齐)

监听 127.0.0.1:38200,被占用顺延 38201/38202;CORS *(含 OPTIONS 预检);响应统一 {code, msg, data},code=0 成功;JSON 字段一律驼峰。

端点 说明
GET /manifest {plugins:[…], agent:"desktop-plugin", backend:"pavo|cups", mock}
GET /api/card-printer/status PrinterStatus(online/model/firmware/connection/ribbon/cardLow/cardLeft/status/statusText)
POST /api/card-printer/print {copies, front:{color,k?}, back:{color,k?}} → {taskId}
GET /api/card-printer/task/{taskId} {taskId, state:printing|done|error, status, statusText}

任务串行执行(打印机物理一次一张),完成后保留 30 分钟。

目录结构

lib/
├── main.dart              # Flutter 窗口入口(服务状态 + 打印机状态 + 运行日志)
├── agent.dart             # 核心组合:参数解析 + 日志缓冲 + 后端/队列/服务装配(纯 Dart,无 Flutter 依赖)
├── server/
│   ├── protocol.dart      # 协议 DTO(toJson 手写驼峰,对齐 C# ApiModels.cs)
│   ├── http_server.dart   # shelf 服务:端口顺延、CORS、四端点
│   └── print_queue.dart   # 串行任务队列 + 30 分钟清理
├── print/
│   ├── backend.dart       # PrintBackend 抽象 + OS 工厂
│   ├── mock_backend.dart  # --mock 模拟(打印 2.5s 完成)
│   └── cups_backend.dart  # macOS:lpoptions 发现队列 + lp 提交(参数列表传参防注入)
├── utils/
│   └── command_runner.dart # 外部命令执行(LC_ALL=C、超时杀进程、参数列表)
bin/agent.dart              # headless 入口(开发联调,行为对齐 C# 控制台助手)
tool/make_test_card.dart    # 生成 1014×642 测试卡(真实打印验收用)

常用命令

flutter pub get
flutter analyze
flutter test

# headless 联调(不需要窗口/真机)
dart run bin/agent.dart --mock              # mock 模式,端口 38200-38202 顺延
dart run bin/agent.dart --port 38203        # 指定端口(本机 C# 助手占用时的开发姿势)
dart run bin/agent.dart                     # 真实模式(macOS 走 CUPS 队列)

# 测试卡 + 真实打印
dart run tool/make_test_card.dart
# 生成 data URL 后 POST /api/card-printer/print,观察 lpoptions 的 printer-state 4→3

# 构建
flutter build macos --release

本机开发注意(血泪坑,勿再踩)

  • 同机 C# 助手占端口:测试前 launchctl unload ~/Library/LaunchAgents/com.zax.cardprinteragent.plist,测完 launchctl load 恢复;两个版本的 manifest.agent 字段可区分(card-printer-agent / desktop-plugin)
  • AMFI 卡死进程:早前测试遗留的 CardPrinterAgent 进程 STAT=UE/UNE,kill -9 无效,占用 38201 直到重启;Flutter 版会自动落到其他候选端口,前端自适应
  • macOS 必须关 App Sandbox(macos/Runner/*.entitlements 已置空):沙箱拦截 127.0.0.1 端口绑定与 lp/lpoptions 子进程访问 CUPS
  • macos 平台目录生成前提:本机 flutter config 曾禁用 enable-macos-desktop 且缺 CocoaPods,均已修复(brew install cocoapods;注意 brew 装 ca-certificates 链接冲突时先 brew unlink 再重装)
  • windows/ 目录无法在 Mac 生成:需在 Windows 实机上 flutter create --platforms windows . 补齐(Phase 3)

进度(2026-09-21)

  • Phase 1:协议服务器 + mock + 任务队列 + 端口顺延(单测 5 个全过,接口自测全过)
  • Phase 2:macOS CUPS 后端(真机 status HiTi CS-200e, 2.4.2 就绪;真实出卡一张,printer-state 4→3 约 24s)
  • Phase 3:Windows PavoApi ffi 后端(需 Windows 实机 + windows/ 目录)
  • Phase 4:托盘/首次引导/URL scheme 唤起(zaxprint scheme 已写入 Info.plist)/开机自启
  • Phase 5:打包签名分发(mac ad-hoc 就地签名;参考 C# 版签名铁律)