1

我正在尝试使用我的托盘应用程序完成以下操作:

  1. MyApp.app 应该在崩溃时重新启动
  2. MyApp.app 不应在用户登录时启动(即用户必须手动启动应用程序)

我有一个问题,如果用户手动启动应用程序,那么列表中 launchctl list com.myapp不会显示正在运行的应用程序。

但是,如果我让 LaunchAgent 在用户登录时启动应用程序,然后launchctl list com.myapp正确显示该应用程序,并将在崩溃(或任何非零退出代码)时重新启动它。

奇怪的是,如果用户手动启动应用程序,launchd 会在几分钟后尝试启动它自己的实例。我什至无法解释为什么会发生这种情况。

我的 LaunchAgent 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>KeepAlive</key>
      <dict>
         <key>SuccessfulExit</key>
         <false/>
         <key>AfterInitialDemand</key>
         <true/>
      </dict>
      <key>RunAtLoad</key>
      <false/>
      <key>Label</key>
      <string>com.myapp</string>
      <key>ProgramArguments</key>
      <array>
         <string>/Applications/MyApp.app/Contents/MacOS/MyApp</string>
      </array>
   </dict>
</plist>
4

1 回答 1

1

launchd只负责启动您的应用程序。如果您想在崩溃时重新启动您的应用程序,我建议您创建一个单独的应用程序,该应用程序仅在后台运行并负责启动您当前的应用程序。这样,它就能够跟踪它启动的应用程序,并在它崩溃时重新启动。如果您想尝试,这里有一些示例 C 代码:

    pid_t waitResult;
    pid_t processId = <Get process id here>
    int status = 0;

    do {
            waitResult = waitpid(processId, &status, WNOHANG | WUNTRACED);
            sleep(1);
        } while (waitResult == 0);

        if (waitResult == processId) {  //Process ends here
            if (WIFEXITED(status)) {
                //Child app ended normally
            } else if (WIFSIGNALED(status) || WIFSTOPPED(status)) { 
                //Child app crashed. Restart here again.
            }
        }
于 2018-02-06T09:11:59.330 回答