如何在Tauri应用中访问、控制本地打印机并追踪打印状态?
Tauri程序访问本地打印机的跨平台最优方案
针对你的需求,直接基于Rust封装跨平台打印逻辑是最优解——绕过功能受限的tauri-plugin-printer,直接调用各平台原生API实现完整的打印机管理、任务提交和状态追踪能力。以下是分平台的具体实现方案及Tauri整合方式:
核心能力实现
1. 获取打印机列表
Windows
使用windows crate调用Print Spooler API,示例代码片段:
use windows::Win32::Graphics::Printing::{EnumPrinters, PRINTER_ENUM_LOCAL, PRINTER_INFO_2W}; use windows::core::PCWSTR; fn get_local_printers() -> Vec<String> { let mut printers = Vec::new(); let mut buffer_size = 0; let mut printer_count = 0; // 先获取所需缓冲区大小 unsafe { EnumPrinters(PRINTER_ENUM_LOCAL, PCWSTR::null(), 2, None, 0, &mut buffer_size, &mut printer_count); } let mut buffer = vec![0u8; buffer_size as usize]; unsafe { EnumPrinters(PRINTER_ENUM_LOCAL, PCWSTR::null(), 2, Some(buffer.as_mut_ptr()), buffer_size, &mut buffer_size, &mut printer_count); } // 解析打印机信息 let printer_info_array = unsafe { std::slice::from_raw_parts(buffer.as_ptr() as *const PRINTER_INFO_2W, printer_count as usize) }; for info in printer_info_array { let name = unsafe { info.pPrinterName.to_string().unwrap() }; printers.push(name); } printers }
MacOS
基于CUPS底层机制,直接调用系统lpstat命令解析输出:
use std::process::Command; fn get_local_printers() -> Vec<String> { let output = Command::new("lpstat") .arg("-a") .output() .expect("Failed to execute lpstat"); let stdout = String::from_utf8(output.stdout).unwrap(); stdout.lines() .map(|line| line.split_whitespace().next().unwrap().to_string()) .collect() }
Linux
使用cups-rs crate(CUPS的高层Rust封装)快速获取列表:
use cups::http::HttpConnection; use cups::printer::Printer; fn get_local_printers() -> Vec<String> { let conn = HttpConnection::new("localhost:631").unwrap(); let printers = Printer::get_all(&conn).unwrap(); printers.iter().map(|p| p.name.clone()).collect() }
2. 提交PDF打印任务
Windows
调用系统默认打印接口快速实现,或用ghostscript做格式兼容处理:
use std::process::Command; fn print_pdf(pdf_path: &str, printer_name: &str) -> Result<(), Box<dyn std::error::Error>> { Command::new("rundll32.exe") .args(&["printui.dll,PrintUIEntry", "/k", "/n", printer_name, pdf_path]) .spawn()?; Ok(()) }
MacOS
通过lpr命令提交打印任务:
use std::process::Command; fn print_pdf(pdf_path: &str, printer_name: &str) -> Result<(), Box<dyn std::error::Error>> { Command::new("lpr") .arg("-P") .arg(printer_name) .arg(pdf_path) .status()?; Ok(()) }
Linux
通过cups-rs提交作业并返回作业ID用于后续追踪:
use cups::http::HttpConnection; use cups::job::Job; fn print_pdf(pdf_path: &str, printer_name: &str) -> Result<u32, Box<dyn std::error::Error>> { let conn = HttpConnection::new("localhost:631").unwrap(); let job_id = Job::print_file(&conn, printer_name, pdf_path, "Tauri Print Job", &[])?; Ok(job_id) }
3. 打印状态追踪
Windows
通过windows crate定期调用GetJob API查询指定作业状态,或监听Print Spooler的事件通知。
MacOS/Linux
借助CUPS API或系统命令查询作业状态:
// Linux示例,MacOS可通过`lpstat -j <job_id>`解析输出 use cups::http::HttpConnection; use cups::job::Job; fn get_job_status(job_id: u32) -> String { let conn = HttpConnection::new("localhost:631").unwrap(); let job = Job::get(&conn, job_id).unwrap(); job.state.to_string() }
Tauri整合方式
将Rust逻辑封装为Tauri命令,供前端调用:
#[tauri::command] fn get_printers() -> Vec<String> { #[cfg(target_os = "windows")] return get_local_printers(); #[cfg(target_os = "macos")] return get_local_printers(); #[cfg(target_os = "linux")] return get_local_printers(); } #[tauri::command] fn print_pdf_task(pdf_path: String, printer_name: String) -> Result<u32, String> { match print_pdf(&pdf_path, &printer_name) { Ok(job_id) => Ok(job_id), Err(e) => Err(e.to_string()), } } // 注册命令到Tauri应用 fn main() { tauri::Builder::default() .invoke_handler(tauri::generate_handler![get_printers, print_pdf_task]) .run(tauri::generate_context!()) .expect("error while running tauri application"); }
打印店场景适配建议
- 本地缓存已支付订单:避免网络波动导致重复打印,完成后同步状态到数据库
- 任务队列机制:多订单排队打印,避免打印机阻塞
- 失败重试:打印失败自动重试2-3次,仍失败则标记异常并通知店员
- 状态同步:定期查询作业状态,更新订单的打印进度(待打印/打印中/已完成/失败)
内容的提问来源于stack exchange,提问作者Patato




