如何以编程方式在 Mac OS X 上设置应用程序包以在用户登录时运行?
基本上,相当于HKCU\Software\Microsoft\Windows\CurrentVersion\Run
Windows 中的注册表项。
您可以将应用程序添加到用户的“登录项”(在 System Preferences=>Accounts=[user] 下),或者您可以将启动代理添加到用户的~/Library/LaunchAgents
文件夹(请参阅参考资料man launchd.plist
)。如果~/Library/LaunchDaemons/
您的应用没有面向用户的 UI,请使用此选项。正如其他人指出的那样,launchd 可以让您对应用程序何时启动、应用程序退出或崩溃等情况进行大量控制,并且最适合“守护进程”风格的应用程序(我们没有 UI)。
下面是一个工作示例。
创建文件
~/Library/LaunchAgents/my.everydaytasks.plist
有内容:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>my.everydaytasks</string>
<key>ProgramArguments</key>
<array>
<string>/Applications/EverydayTasks.app/Contents/MacOS/EverydayTasks</string>
</array>
<key>ProcessType</key>
<string>Interactive</string>
<key>RunAtLoad</key>
<true/>
<key>KeepAlive</key>
<false/>
</dict>
</plist>
请参阅帮助我制作此示例的原始帖子:
https://superuser.com/a/229792/43997
要测试您需要在终端中运行它
launchctl load -w ~/Library/LaunchAgents/my.everydaytasks.plist
卸载
launchctl unload -w ~/Library/LaunchAgents/my.everydaytasks.plist
也可以看看
这是使用“登录项”将应用程序添加到启动的另一种方式。请参阅此示例项目以了解如何实现它:
“正确”的方法是为您希望在登录时启动的进程创建一个 LaunchAgent,该进程可能具有 UI,而为那些应该是纯后台进程的 LaunchDaemon。在您的安装程序中,将您的 plist 放入正确的文件夹中,无论是用户、所有用户还是系统。这种方法优越的原因是因为您可以使用launchd 来控制您的进程的运行方式,包括确保它即使崩溃或被用户杀死也能继续运行的内置功能。
想在这里为任何使用 Qt / C++ 的人抛出这个。Qt 通过 QSettings 类使得使用 plist 变得超级容易。从示例虚拟应用程序中查看此代码片段。
void MainWindow::readPlist()
{
QSettings settings(appPlistPath, QSettings::NativeFormat);
QVariant value = settings.value("mykey");
QMessageBox::information(this, "Your Value", value.toString());
}
void MainWindow::addPlistEntry()
{
QSettings settings(appPlistPath, QSettings::NativeFormat);
settings.setValue("mykey", "myvalue");
}
void MainWindow::removePlistEntry()
{
QSettings settings(appPlistPath, QSettings::NativeFormat);
settings.remove("mykey");
}
您还可以通过调用系统事件来实现这一点osascript
。这应该可以解决问题:
struct LaunchAtStartupHelper {
static var isEnabled: Bool {
get {
shell(
"""
osascript -e 'tell application "System Events" to get the name of every login item'
""")
.contains("MyAppName")
}
set {
if newValue {
shell(
"""
osascript -e 'tell application "System Events" to make login item at end with properties {path:"/Applications/MyAppName.app", hidden:true}'
""")
} else {
shell(
"""
osascript -e 'tell application "System Events" to delete login item "MyAppName"'
""")
}
}
}
// from https://stackoverflow.com/a/50035059/1072846
@discardableResult
private static func shell(_ command: String) -> String {
let task = Process()
let pipe = Pipe()
task.standardOutput = pipe
task.standardError = pipe
task.arguments = ["-c", command]
task.launchPath = "/bin/zsh"
task.launch()
let data = pipe.fileHandleForReading.readDataToEndOfFile()
let output = String(data: data, encoding: .utf8)!
return output
}
}