macOS下Swift基于XPC实现IPC的极简客户端服务端开发方法
Swift XPC 简易IPC实现方案
前置说明
XPC通信要求服务端和客户端共享相同的通信协议定义,服务端需要注册一个全局唯一的Mach服务名用于客户端寻址。非沙盒命令行工具在同一用户下可直接使用,沙盒应用需要额外配置entitlements权限。
步骤1:定义公共通信协议
服务端和客户端都需要引入相同的协议定义:
import Foundation @objc protocol XPCServiceProtocol { func sendMessage(_ message: String, reply: @escaping (String) -> Void) }
步骤2:服务端实现(对应server_process.swift)
import Foundation // 消息处理类,实现通信协议,对应你的on_message逻辑 class XPCServiceHandler: NSObject, XPCServiceProtocol { func sendMessage(_ message: String, reply: @escaping (String) -> Void) { print("服务端收到消息: \(message)") if message == "ping" { reply("pong") } else { reply("command not supported") } } } // 对应你的run_server_loop函数 func runServerLoop() { // 替换为你自定义的全局唯一Mach服务名,推荐使用反转域名格式 let listener = NSXPCListener(machServiceName: "com.demo.xpc.server") listener.delegate = XPCListenerDelegate() listener.resume() // 启动运行循环保持进程不退出 RunLoop.current.run() } // XPC连接监听代理 class XPCListenerDelegate: NSObject, NSXPCListenerDelegate { func listener(_ listener: NSXPCListener, shouldAcceptNewConnection newConnection: NSXPCConnection) -> Bool { newConnection.exportedInterface = NSXPCInterface(with: XPCServiceProtocol.self) newConnection.exportedObject = XPCServiceHandler() newConnection.resume() return true } } // 启动服务 runServerLoop()
步骤3:客户端实现(对应client_process.swift)
import Foundation // 对应你的some_way_to_connect函数 func connectToServer() -> NSXPCConnection? { // 和服务端使用完全相同的Mach服务名,普通用户服务无需加options参数 let connection = NSXPCConnection(machServiceName: "com.demo.xpc.server") connection.remoteObjectInterface = NSXPCInterface(with: XPCServiceProtocol.self) connection.resume() // 可选:配置连接中断回调 connection.interruptionHandler = { print("与服务端连接中断") } return connection } // 建立连接 guard let clientConnection = connectToServer() else { fatalError("无法连接到服务端") } // 获取远程服务代理 guard let xpcService = clientConnection.remoteObjectProxyWithErrorHandler({ error in print("调用XPC服务出错: \(error)") }) as? XPCServiceProtocol else { fatalError("获取远程服务代理失败") } // 对应你的client.send("ping")逻辑 xpcService.sendMessage("ping") { reply in print("客户端收到回复: \(reply)") // 收到回复后关闭连接 clientConnection.invalidate() exit(0) } // 保持客户端运行等待异步回复 RunLoop.current.run(until: Date().addingTimeInterval(5))
运行注意事项
- Mach服务名必须服务端和客户端完全一致,避免和系统或其他应用的服务名冲突
- 沙盒应用需要在entitlements文件中添加
com.apple.security.temporary-exception.mach-lookup.global-name权限,值为你定义的Mach服务名 - 运行时先启动服务端进程,再启动客户端进程即可看到对应输出
- 如果需要传输复杂自定义类型,需要提前在
NSXPCInterface中声明对应类型的编码规则
内容的提问来源于stack exchange,提问作者Alok
相关产品推荐
相关产品推荐

