在Mac OS X上如何编程实现开机自启动?

24

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

基本上,这相当于Windows中的HKCU\Software\Microsoft\Windows\CurrentVersion\Run注册表键。

5个回答

18
你可以将应用程序添加到用户的“登录项”中(在“系统偏好设置=》帐户=[user]”下),或者将launchd代理添加到用户的〜/ Library / LaunchAgents 文件夹中(请参见 man launchd.plist )。如果您的应用程序没有面向用户的UI,请使用〜/ Library / LaunchDaemons / 。正如其他人指出的那样,launchd让您对应用程序启动的时间、应用程序退出或崩溃时发生的情况等有很多控制权,并且最适合“守护进程”样式的应用程序(具有或不具有UI)。
第一种选择(登录项)可以通过Gordon提供的链接进行编程操作。

5
苹果公司的开发文档描述了添加登录项的三种方法,其中包括一个代码片段和另一个示例代码的链接。 - Gordon Davisson
一个plist文件的示例以及如何添加它将非常有帮助。 - Dmitriy
@geotavros,请查看man launchd.plist以获取plist格式的官方(并且最新)文档。 - Barry Wark
3
@BarryWark的链接已经失效。 - ahmet alp balkan
@BarryWark 看起来登录项 API 已经被弃用了,你能否更新一下你的答案? - Dima Deplov
显示剩余2条评论

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


假设我有一个参数是.list文件,它是在应用程序安装时生成的动态值。我该如何传递/发送它? - Marcelo

6

“正确”的方法是针对您想要在登录时启动的具有用户界面的进程创建LaunchAgent,并为那些应该是纯后台进程的进程创建LaunchDaemon。 在您的安装程序中,将您的plist文件放入正确的文件夹中,可以是针对用户、所有用户或系统。 这种方法优越的原因在于您可以使用launchd控制您的进程运行方式,包括内置功能,确保即使进程崩溃或被用户终止,它也会继续运行。


这不是必须保持运行的关键应用程序,只是首选项对话框中的一种方便选项。您是说如果用户退出应用程序,它会继续运行吗?我不希望发生这种情况。 - Jake Petroules
不,我是说当你使用LaunchDaemons时,这是一个选项。你可以选择系统运行应用程序的方式。 - Jeremy

4

如果您使用Qt / C ++,想要使用plist文件,那么可以通过QSettings类轻松实现。以下是一个示例虚拟应用程序的代码片段。

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");
}

1
你也可以通过调用System Events来实现这一点,例如: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://dev59.com/TV8d5IYBdhLWcg3wTQwn#50035059
    @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
    }
}


这对我来说很有效。虽然我们的应用程序已经需要系统事件权限了。 - Lucas van Dongen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接