我创建了一个Swift macOS应用程序,它使用SMJobBless
创建一个具有升级权限的帮助程序。这很好 - 帮助程序安装到/Library/Privileged Helper Tools
,并在/Library/LaunchDaemons
中创建随附的LaunchDaemon。但是,帮助程序无法成功启动。相反,它会以“非法指令:4”消息崩溃。
我已经准备好帮助程序,通过实现NSXPCListenerDelegate
协议来响应XML连接。这是我的助手main.swift
代码:
import Foundation
class HelperDelegate: NSObject, NSXPCListenerDelegate {
func listener(_ listener: NSXPCListener, shouldAcceptNewConnection newConnection: NSXPCConnection) -> Bool {
newConnection.exportedInterface = NSXPCInterface(with: HelperToolProtocol.self)
newConnection.exportedObject = HelperTool()
newConnection.resume()
return true
}
}
let delegate = HelperDelegate()
let listener = NSXPCListener.service()
listener.delegate = delegate
listener.resume()
崩溃发生在最后一行listener.resume()
。
我尝试从命令行手动启动帮助应用程序(这与LaunchDaemon的操作相同),并且再次崩溃时,上面的错误消息打印到stdout。我对如何根本原因进行测试没有任何想法。在Apple’s guidlines for implementing XM services之后,我的实施不仅仅是基本的。此外,SO上关于XML服务的各种帖子并没有帮助我解决这个问题。有没有人试图成功在Swift中创建特权助手?顺便说一句,该应用程序不是沙盒。
为了完整起见,以下是我HelperTool
课程中引用的HelperDelegate
类的代码:
import Foundation
class HelperTool: NSObject, HelperToolProtocol {
func getVersion(withReply reply: (NSData?) -> ()) {
let version = Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString" as String) as? String ?? "<unknown version>"
let build = Bundle.main.object(forInfoDictionaryKey: kCFBundleVersionKey as String) as? String ?? "<unknown build>"
if let d = "v\(version) (\(build))".data(using: .utf8, allowLossyConversion: false) {
reply(d as NSData)
}
}
}
最后是HelperToolProtocol
:
import Foundation
@objc(HelperToolProtocol) protocol HelperToolProtocol {
func getVersion(withReply: (NSData?) -> ())
}
感谢您的帮助!
答案 0 :(得分:0)
经过几天的测试后,我终于找到了一个解决方案,它使我的XPC助手正确启动并响应任何消息。问题在于当前读取的main.swift
模块的最后三行
let listener = NSXPCListener.service()
listener.delegate = delegate
listener.resume()
,正如问题所示,使助手在最后一行立即崩溃。
我直接从Apple’s Creating XPC Services documentation获取了这些行。以下是NSXPCListener
resume()
函数的文档:
如果在
service()
对象上调用,则此方法永远不会返回。因此,在设置任何所需的初始状态并配置监听器本身之后,应将其称为XPC服务主函数内的最后一步。
解决方法是不调用NSXPCListener.service()
单例对象,而是使用NSXPCListener
初始化程序实例化一个新的init(machServiceName:)
对象,传递相同的Mach服务名称正在主应用程序的XPC连接上使用。因为resume()
在这种情况下会立即恢复 - 从而终止帮助程序 - 你必须将它放在当前的运行循环上,让它不确定地运行。这是新的工作代码:
let listener = NSXPCListener(machServiceName: "Privilege-Escalation-Sample.Helper")
listener.delegate = delegate
listener.resume()
RunLoop.current.run()