feat: 向导内置 HiTi Mac 驱动一键安装(补齐计划 §3.2"驱动 dmg 放包内"设计)

- setup/driver_install.dart:检测已装(/Library/Printers/HiTi)+ 内置 dmg 定位
  (从 resolvedExecutable 反推 flutter_assets/assets/drivers/,缺失降级官网链接)
  + 静默安装(hdiutil 挂载→定位 pkg→osascript 提权 installer→finally detach;
  挂载点名带随机序号必须从 attach 输出解析)
- 向导第 2 步重做状态机:驱动未装 → "一键安装驱动(内置安装包)"按钮
  (安装中提示输管理员密码,失败显示原因);驱动已装但无队列 → 连接/添加队列
  引导;无内置 dmg 的构建回退官网链接
- assets/drivers/ 收驱动 dmg(.gitignore 不入库,打包脚本检查缺失并警告,
  当前从 card-printer-agent/dist 拷入 2.4.2 版,25MB)
- 实测:挂载/pkg 定位/detach 免密链路全通过;打包 47MB dmg 内含驱动,
  冒烟启动正常(服务已占主端口 38200);一键安装的提权弹窗待用户实测
This commit is contained in:
dzc committed 2026-09-21 14:04:55 +08:00
1 parent 3ecac9a302
commit d475cac6ab
5 files changed
+173 -4

No files matched your search

+84 -4
View File
@@ -6,6 +6,7 @@ import 'package:url_launcher/url_launcher.dart';
import '../agent.dart';
import '../server/protocol.dart';
import '../setup/autostart.dart';
import '../setup/driver_install.dart';
import '../setup/first_run.dart';
import '../setup/url_scheme.dart';
@@ -42,6 +43,8 @@ class _SetupWizardState extends State<SetupWizard> {
bool _autostart = true;
bool _autostartBusy = false;
bool _printerChecking = false;
bool _driverInstalling = false;
String? _driverInstallError;
PrinterStatus? _printerStatus;
Agent get _agent => widget.agent;
@@ -173,9 +176,29 @@ class _SetupWizardState extends State<SetupWizard> {
// ---------------- Step 1:打印机检测 ----------------
/// 一键安装内置驱动(mac):装完自动重检(队列要等打印机连上/系统识别后才出现)。
Future<void> _installDriver() async {
final dmg = DriverInstall.bundledDmgPath();
if (dmg == null) return;
setState(() {
_driverInstalling = true;
_driverInstallError = null;
});
try {
await DriverInstall.installFromDmg(dmg, onLog: _agent.log.write);
await _checkPrinter();
} catch (e) {
if (mounted) setState(() => _driverInstallError = '$e');
} finally {
if (mounted) setState(() => _driverInstalling = false);
}
}
Widget _stepPrinter(ColorScheme scheme) {
final s = _printerStatus;
final ready = s != null && s.online;
final driverMissing = Platform.isMacOS && !DriverInstall.isInstalled();
final bundledDmg = Platform.isMacOS ? DriverInstall.bundledDmgPath() : null;
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
@@ -186,11 +209,69 @@ class _SetupWizardState extends State<SetupWizard> {
okText: '打印机就绪${s != null && s.model.isNotEmpty ? "(${s.model})" : ""}',
badText: s == null ? '未检测到打印队列' : (s.statusText.isEmpty ? '打印机未就绪' : s.statusText),
),
if (!ready) ...[
const SizedBox(height: 12),
const SizedBox(height: 12),
// mac:驱动未装 → 首选一键安装内置驱动,其次官网链接
if (driverMissing) ...[
Text(
'本机尚未安装 HiTi 打印机驱动(mac 打印必需的系统组件)。',
style: Theme.of(context).textTheme.bodySmall?.copyWith(height: 1.6),
),
const SizedBox(height: 8),
Row(
children: [
FilledButton.tonalIcon(
onPressed: _driverInstalling || bundledDmg == null ? null : _installDriver,
icon: _driverInstalling
? const SizedBox(
width: 14,
height: 14,
child: CircularProgressIndicator(strokeWidth: 2),
)
: const Icon(Icons.download, size: 16),
label: Text(_driverInstalling
? '正在安装…(弹窗中输入管理员密码)'
: '一键安装驱动(内置安装包)'),
),
const SizedBox(width: 8),
TextButton.icon(
onPressed: () => launchUrl(Uri.parse(_driverUrl)),
icon: const Icon(Icons.open_in_new, size: 14),
label: const Text('改为手动下载'),
),
],
),
if (bundledDmg == null)
Padding(
padding: const EdgeInsets.only(top: 4),
child: Text(
'(当前构建未内置驱动安装包,请用官网链接手动安装)',
style: Theme.of(context).textTheme.bodySmall,
),
),
if (_driverInstallError != null)
Padding(
padding: const EdgeInsets.only(top: 6),
child: Text(
'安装失败:$_driverInstallError',
style: Theme.of(context)
.textTheme
.bodySmall
?.copyWith(color: scheme.error),
),
),
const SizedBox(height: 8),
Text(
'安装完成后:USB 连接打印机并开机,系统识别出现打印队列即完成。',
style: Theme.of(context).textTheme.bodySmall,
),
]
// 驱动已装但打印机未就绪 → 引导连接/添加队列
else if (!ready) ...[
Text(
Platform.isMacOS
? '安装步骤:① 打开 HiTi 官网下载 macOS 驱动(HiTiCardTypeMacDrivers dmg),双击安装里面的 pkg;② USB 连接打印机并开机;③ 系统设置 → 打印机与扫描仪 确认出现 HiTi 打印机;④ 回到这里点「重新检测」。'
? '驱动已安装。请确认:① 打印机 USB 已连接并开机;② 系统设置 → 打印机与扫描仪 里出现 HiTi 打印机(没有的话点下方「+」添加,选 HiTi CS-200e);③ 回到这里重新检测。'
: 'Windows 打印站:打开 HiTi 官网下载 CS-2xx Windows 驱动并安装,USB 连接打印机;本应用也支持免驱动的 SDK 直连模式,装完驱动或接好打印机后点「重新检测」。',
style: Theme.of(context).textTheme.bodySmall?.copyWith(height: 1.6),
),
@@ -210,7 +291,6 @@ class _SetupWizardState extends State<SetupWizard> {
label: const Text('重新检测'),
),
] else ...[
const SizedBox(height: 12),
Text('打印机已连接,可以正常接收管理端提交的卡面打印。',
style: Theme.of(context).textTheme.bodySmall),
],