首页 > 解决方案 > 在启动 C# .Net 5 MacOS 时启动程序

问题描述

我正在尝试添加一个程序以在启动时启动,并且我一直在广泛搜索,无法找到解决方案。

我已经很接近了,我设法生成了一个 .plist 文件并将其添加到 ~/Library/LaunchAgents,但是我似乎无法加载它。我没有收到以下代码的错误。

这是到目前为止的代码:

public static void AddApplicationToStartup()
    {
        try
        {
            var filePath = Environment.GetEnvironmentVariable("HOME") + "/Library/LaunchAgents/teststart.plist";
            CreatePlistFile(filePath);

            //string test = $" -c \"osascript -e \' tell application \\\"Terminal\\\" to do script \\\"echo hello\\\" \' \"";
            var arguments = $" -c \"osascript -e \' do shell script \\\"sudo launchctl load -w {filePath}\\\" with administrator privileges\' \"";
            var command = "/bin/bash";

            Console.WriteLine($"Performing: {command} {arguments}");
            ProcessStartInfo procStartInfo = new ProcessStartInfo
            {
                FileName = command,
                Arguments = arguments
            };
            procStartInfo.RedirectStandardOutput = true;
            procStartInfo.UseShellExecute = false;
            procStartInfo.RedirectStandardError = true;
            procStartInfo.CreateNoWindow = true;

            // start process
            Process proc = new Process();
            proc.StartInfo = procStartInfo;
            proc.Start();
            proc.WaitForExit();


            // read process output
            string cmdError = proc.StandardError.ReadToEnd();
            Console.WriteLine($"cmdError: {cmdError}");
            string cmdOutput = proc.StandardOutput.ReadToEnd();
            Console.WriteLine($"cmdOutput: {cmdOutput}");
        }
        catch (Exception e)
        {
            Console.WriteLine(e.Message);
        }
    }

private static void CreatePlistFile(string filePath)
    {
        try
        {
            if (!File.Exists(filePath))
            {
                PListWriter writer = new PListWriter(filePath, null);
                writer.WriteProcessingInstruction("xml", "version='1.0' encoding='UTF-8'");
                writer.WriteDocType();
                writer.WriteStartElement("plist");
                writer.WriteAttributeString("version", "1.0");
                writer.WriteStartElement("dict");
                writer.WriteElementString("key", "Label");
                writer.WriteElementString("string", "com.user.teststart");
                writer.WriteElementString("key", "ProgramArguments");
                writer.WriteStartElement("array");
                writer.WriteElementString("string", "/Applications/TestApp.app/Contents/MacOS/test_app");
                writer.WriteEndElement();
                writer.WriteElementString("key", "RunAtLoad");
                writer.WriteRaw("<true/>");
                writer.WriteEndElement();
                writer.WriteEndElement();
                writer.Close();
                Console.WriteLine("Plist created");
            }
            else
            {
                Console.WriteLine("Plist already exists");
            }
        }
        catch (Exception e)
        {
            Console.WriteLine(e.Message);
        }
    }

当我通过控制台运行以下命令时,.plist 文件有效:

launchctl load -w /Users/用户名/Library/LaunchAgents/teststart.plist

但不是通过代码。我尝试了许多不同的更改,例如将命令和参数设置如下。

var arguments = $"load -w /Users/username/Library/LaunchAgents/teststart.plist";
var command = "launchctl";

任何想法我做错了什么,或者我可以尝试什么?

更新:

我可以通过 Apple Script 使用以下代码将我的程序添加到用户的登录项:

var command = "/bin/bash";
var arguments = " -c \"osascript -e ' tell application \\\"System Events\\\" to make login item at end with properties {{path:\\\"/Applications/Shipmondo.app\\\", hidden:false}}'\"";

标签: c#.netmacoscross-platform

解决方案


I do not understand why you are trying to launch your agent from another program.

When a user logs in, macOS will start a new launchd process for that user. This launchd process will scan the agent directories /System/Library/LaunchAgents, /Library/LaunchAgents and the user's ~/Library/LaunchAgents for property list job files and will load them depending on the value of the Disabled key (if it exists) and the contents of the override database.

Loading a job definition will not necessarily start the job. When a job is started is determined by the job's property list file. If the RunAtLoad or KeepAlive keys have been specified, then launchd will start the job when as soon as it is loaded.

Apple's documentation on this topic is somewhat outdated to say the least, but for an Overview you can look at the archived https://developer.apple.com/library/archive/documentation/MacOSX/Conceptual/BPSystemStartup/Chapters/CreatingLaunchdJobs.html and https://developer.apple.com/library/archive/technotes/tn2083/_index.html, just be aware that some that information is outdated.

Perhaps the best source of information now is the man pages for launchd, launchctl and launchctl.plist.


推荐阅读