23

如何以编程方式在 Mac OS X 上设置应用程序包以在用户登录时运行?

基本上,相当于HKCU\Software\Microsoft\Windows\CurrentVersion\RunWindows 中的注册表项。

4

5 回答 5

18

您可以将应用程序添加到用户的“登录项”(在 System Preferences=>Accounts=[user] 下),或者您可以将启动代理添加到用户的~/Library/LaunchAgents文件夹(请参阅参考资料man launchd.plist)。如果~/Library/LaunchDaemons/您的应用没有面向用户的 UI,请使用此选项。正如其他人指出的那样,launchd 可以让您对应用程序何时启动、应用程序退出或崩溃等情况进行大量控制,并且最适合“守护进程”风格的应用程序(我们没有 UI)。

第一个选项(登录项)可以通过编程方式进行操作(来自Gordon的链接)。

于 2010-07-28T23:52:23.060 回答
10

下面是一个工作示例。

创建文件

~/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

也可以看看

https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man5/launchd.plist.5.html

这是使用“登录项”将应用程序添加到启动的另一种方式。请参阅此示例项目以了解如何实现它:

https://github.com/justin/Shared-File-List-Example

于 2014-02-10T15:00:47.270 回答
6

“正确”的方法是为您希望在登录时启动的进程创建一个 LaunchAgent,该进程可能具有 UI,而为那些应该是纯后台进程的 LaunchDaemon。在您的安装程序中,将您的 plist 放入正确的文件夹中,无论是用户、所有用户还是系统。这种方法优越的原因是因为您可以使用launchd 来控制您的进程的运行方式,包括确保它即使崩溃或被用户杀死也能继续运行的内置功能。

于 2010-07-29T19:26:00.610 回答
4

想在这里为任何使用 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");
}
于 2010-10-28T00:10:19.583 回答
0

您还可以通过调用系统事件来实现这一点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
    }
}

于 2021-10-01T10:49:52.983 回答